# Production Deployment Guide This guide describes how to deploy the Customer Portal in production with Docker Compose, Nginx reverse proxy, and automatic TLS renewal via Certbot. ## Prerequisites - Domain name pointed to your server (A/AAAA records) - Docker and Docker Compose installed - Open ports 80 and 443 ## Environment configuration - Copy `.env.production.example` to `.env` at the repository root: ```bash cp .env.production.example .env ``` - Fill in all required values, especially: - DATABASE_URL (matches docker-compose Postgres credentials) - REDIS_URL (usually redis://cache:6379) - JWT_SECRET (strong, random) - CORS_ORIGIN (e.g., https://yourdomain.com) - BFF_PORT (e.g., 4000) - NEXT_PUBLIC_API_BASE (e.g., https://yourdomain.com) - Salesforce/WHMCS credentials and key path ## First-time TLS certificate Run certbot once to issue a certificate (HTTP challenge): ```bash docker compose -f docker/prod/docker-compose.yml run --rm \ -p 80:80 \ -e "CERTBOT_DOMAIN=yourdomain.com" \ -e "CERTBOT_EMAIL=you@example.com" \ certbot certonly --webroot -w /var/www/certbot \ -d yourdomain.com --agree-tos --no-eff-email ``` - Certificates will be stored under the `letsencrypt` volume mounted at `/etc/letsencrypt`. - Nginx is configured to use `/etc/letsencrypt/live/portal` by default. You can update the path or create a symlink to match your issued cert name. ## Deploy ```bash pnpm prod:deploy ``` This will: - Build images - Start database and cache, wait for health - Run migrations - Start proxy, frontend, backend ## Health checks - Proxy/Frontend: https://yourdomain.com/healthz - Backend: proxied at https://yourdomain.com/api/health (and container-local http://backend:4000/health) ## Renewals - A certbot sidecar runs and renews every ~12 hours. On renew, it reloads Nginx. ## Notes on security - HSTS, modern TLS ciphers, and security headers are enabled in Nginx - Backend disables x-powered-by and supports trust proxy - Avoid exposing container ports directly; use the proxy service - Keep `.env` outside of version control ## Updates ```bash pnpm prod:update ``` This rebuilds and recreates `frontend` and `backend` without downtime. ## Troubleshooting - Check logs: ```bash pnpm prod:logs ``` - Validate Nginx config inside container: ```bash docker exec -it portal-proxy nginx -t ```