2.3 KiB

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:
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)

First-time TLS certificate

Run certbot once to issue a certificate (HTTP challenge):

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

pnpm prod:deploy

This will:

  • Build images
  • Start database and cache, wait for health
  • Run migrations
  • Start proxy, frontend, backend

Health checks

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

pnpm prod:update

This rebuilds and recreates frontend and backend without downtime.

Troubleshooting

  • Check logs:
pnpm prod:logs
  • Validate Nginx config inside container:
docker exec -it portal-proxy nginx -t