216 lines
5.5 KiB
Markdown
216 lines
5.5 KiB
Markdown
# Banatie Production Deployment Guide
|
|
|
|
> Last Updated: December 23, 2025
|
|
|
|
This guide covers deploying Banatie to a VPS with Docker. For local development, see [environment.md](./environment.md).
|
|
|
|
## Overview
|
|
|
|
Banatie is deployed as an isolated ecosystem with:
|
|
|
|
- **Landing** (Next.js 15.5.9) → banatie.app
|
|
- **API** (Express.js) → api.banatie.app
|
|
- **PostgreSQL** (15-alpine) → Database
|
|
- **MinIO** (SNMD mode) → Object storage
|
|
|
|
## Prerequisites
|
|
|
|
- VPS with Docker and Docker Compose
|
|
- Caddy reverse proxy (or similar) with SSL
|
|
- DNS records configured
|
|
- GEMINI_API_KEY from Google AI Studio
|
|
|
|
## Quick Start
|
|
|
|
```bash
|
|
# 1. Create directory structure
|
|
sudo mkdir -p /opt/banatie/{data,logs,scripts}
|
|
sudo mkdir -p /opt/banatie/data/{postgres,minio,waitlist-logs,api-results,api-uploads}
|
|
sudo mkdir -p /opt/banatie/data/minio/{drive1,drive2,drive3,drive4}
|
|
sudo chown -R $USER:$USER /opt/banatie
|
|
|
|
# 2. Clone repository
|
|
git clone <repo> ~/workspace/projects/banatie-service
|
|
|
|
# 3. Copy production configs
|
|
cp ~/workspace/projects/banatie-service/infrastructure/docker-compose.production.yml /opt/banatie/docker-compose.yml
|
|
cp ~/workspace/projects/banatie-service/infrastructure/.env.example /opt/banatie/.env
|
|
cp ~/workspace/projects/banatie-service/infrastructure/secrets.env.example /opt/banatie/secrets.env
|
|
cp ~/workspace/projects/banatie-service/infrastructure/init-db.sql /opt/banatie/scripts/
|
|
|
|
# 4. Configure environment
|
|
nano /opt/banatie/.env # Edit public variables
|
|
nano /opt/banatie/secrets.env # Generate and add secrets
|
|
chmod 600 /opt/banatie/secrets.env
|
|
|
|
# 5. Build and start
|
|
cd /opt/banatie
|
|
docker compose --env-file .env --env-file secrets.env build
|
|
docker compose --env-file .env --env-file secrets.env up -d
|
|
|
|
# 6. Initialize database schema
|
|
cd ~/workspace/projects/banatie-service
|
|
pnpm install
|
|
pnpm --filter @banatie/database db:push
|
|
|
|
# 7. Create master API key
|
|
curl -X POST https://api.banatie.app/api/bootstrap/initial-key
|
|
# Or use UI: https://banatie.app/admin/master/
|
|
```
|
|
|
|
## Deploy Scripts
|
|
|
|
Located in `scripts/` directory:
|
|
|
|
```bash
|
|
# Deploy landing page
|
|
./scripts/deploy-landing.sh # Normal deploy
|
|
./scripts/deploy-landing.sh --no-cache # Fresh build (when deps change)
|
|
|
|
# Deploy API
|
|
./scripts/deploy-api.sh # Normal deploy
|
|
./scripts/deploy-api.sh --no-cache # Fresh build
|
|
```
|
|
|
|
## Configuration Files
|
|
|
|
### Environment Variables (.env)
|
|
|
|
```bash
|
|
NODE_ENV=production
|
|
PORT=3000
|
|
POSTGRES_DB=banatie_db
|
|
POSTGRES_USER=banatie_user
|
|
DATABASE_URL=postgresql://banatie_user:<password>@banatie-postgres:5432/banatie_db
|
|
MINIO_ENDPOINT=banatie-minio:9000
|
|
MINIO_PUBLIC_URL=https://cdn.banatie.app
|
|
API_PUBLIC_URL=https://api.banatie.app
|
|
NEXT_PUBLIC_API_URL=https://api.banatie.app
|
|
CORS_ORIGIN=https://banatie.app,https://api.banatie.app
|
|
```
|
|
|
|
### Secrets (secrets.env)
|
|
|
|
```bash
|
|
POSTGRES_PASSWORD=<generated>
|
|
MINIO_ROOT_USER=banatie_admin
|
|
MINIO_ROOT_PASSWORD=<generated>
|
|
MINIO_ACCESS_KEY=banatie_service
|
|
MINIO_SECRET_KEY=<generated>
|
|
GEMINI_API_KEY=<your-key>
|
|
JWT_SECRET=<generated>
|
|
SESSION_SECRET=<generated>
|
|
```
|
|
|
|
Generate secrets with:
|
|
```bash
|
|
openssl rand -base64 32 | tr -d '\n\r '
|
|
```
|
|
|
|
## DNS Configuration
|
|
|
|
| Type | Name | Value |
|
|
|------|------|-------|
|
|
| A | @ | VPS_IP |
|
|
| CNAME | www | banatie.app |
|
|
| CNAME | api | banatie.app |
|
|
| CNAME | storage | banatie.app |
|
|
| CNAME | cdn | banatie.app |
|
|
|
|
## Caddy Configuration
|
|
|
|
Add to your Caddyfile:
|
|
|
|
```caddy
|
|
www.banatie.app {
|
|
redir https://banatie.app{uri} permanent
|
|
}
|
|
|
|
banatie.app {
|
|
reverse_proxy banatie-landing:3000
|
|
}
|
|
|
|
api.banatie.app {
|
|
reverse_proxy banatie-api:3000
|
|
}
|
|
|
|
storage.banatie.app {
|
|
reverse_proxy banatie-minio:9001
|
|
}
|
|
|
|
cdn.banatie.app {
|
|
reverse_proxy banatie-minio:9000
|
|
header Access-Control-Allow-Origin "*"
|
|
}
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Permission Denied on Volumes
|
|
|
|
Docker User Namespace Remapping offsets UIDs by 165536:
|
|
|
|
```bash
|
|
# Fix permissions for Next.js (uid 1001 → 166537)
|
|
sudo chown -R 166537:166537 /opt/banatie/data/waitlist-logs
|
|
|
|
# Fix permissions for API (uid 1001 → 166537)
|
|
sudo chown -R 166537:166537 /opt/banatie/data/api-results
|
|
sudo chown -R 166537:166537 /opt/banatie/data/api-uploads
|
|
```
|
|
|
|
### Environment Variables Not Applied
|
|
|
|
Use `docker compose up -d` instead of `docker restart`:
|
|
|
|
```bash
|
|
docker compose --env-file .env --env-file secrets.env up -d banatie-api
|
|
```
|
|
|
|
### NEXT_PUBLIC_* Variables
|
|
|
|
Must be set at both build time AND runtime. Ensure `NEXT_PUBLIC_API_URL` is in .env before building.
|
|
|
|
### pnpm Workspace Symlinks in Docker
|
|
|
|
The Dockerfiles use simplified single-stage install to avoid symlink issues:
|
|
|
|
```dockerfile
|
|
COPY pnpm-workspace.yaml package.json pnpm-lock.yaml ./
|
|
COPY apps/landing ./apps/landing
|
|
COPY packages/database ./packages/database
|
|
RUN pnpm install --frozen-lockfile
|
|
RUN pnpm --filter @banatie/landing build
|
|
```
|
|
|
|
### Database Connection Refused
|
|
|
|
URL-encode special characters in DATABASE_URL:
|
|
- `=` → `%3D`
|
|
- `@` → `%40`
|
|
- `#` → `%23`
|
|
|
|
## Known Issues
|
|
|
|
### Healthcheck Showing "Unhealthy"
|
|
|
|
Alpine images don't have `curl` by default. The healthcheck uses `wget` but may still show unhealthy in some cases. Services work correctly despite this status.
|
|
|
|
### Next.js Cache Permission Warning
|
|
|
|
```
|
|
EACCES: permission denied, mkdir '/app/apps/landing/.next/cache'
|
|
```
|
|
|
|
This is non-critical - images still work, just not cached. To fix:
|
|
```bash
|
|
sudo chown -R 166537:166537 /opt/banatie/data/landing-cache
|
|
# And add volume mount for .next/cache
|
|
```
|
|
|
|
## Full VPS Documentation
|
|
|
|
For complete VPS setup and infrastructure details, see:
|
|
- VPS Repository: `VPS/docs/banatie-deployment.md`
|
|
- Deployment Manual: `VPS/manuals/banatie-service-deployment.md`
|