banatie-service/docs/deployment.md

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`