2025-08-21 15:24:40 +09:00
|
|
|
# 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
|
2025-08-22 17:02:49 +09:00
|
|
|
|
2025-08-21 15:24:40 +09:00
|
|
|
- Domain name pointed to your server (A/AAAA records)
|
|
|
|
|
- Docker and Docker Compose installed
|
|
|
|
|
- Open ports 80 and 443
|
|
|
|
|
|
|
|
|
|
## Environment configuration
|
2025-08-22 17:02:49 +09:00
|
|
|
|
|
|
|
|
- Copy `.env.production.example` to `.env` at the repository root:
|
|
|
|
|
|
2025-08-21 15:24:40 +09:00
|
|
|
```bash
|
2025-08-22 17:02:49 +09:00
|
|
|
cp .env.production.example .env
|
2025-08-21 15:24:40 +09:00
|
|
|
```
|
2025-08-22 17:02:49 +09:00
|
|
|
|
2025-08-21 15:24:40 +09:00
|
|
|
- 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)
|
2025-08-22 17:02:49 +09:00
|
|
|
- BFF_PORT (e.g., 4000)
|
2025-08-21 15:24:40 +09:00
|
|
|
- NEXT_PUBLIC_API_BASE (e.g., https://yourdomain.com)
|
|
|
|
|
- Salesforce/WHMCS credentials and key path
|
|
|
|
|
|
|
|
|
|
## First-time TLS certificate
|
2025-08-22 17:02:49 +09:00
|
|
|
|
2025-08-21 15:24:40 +09:00
|
|
|
Run certbot once to issue a certificate (HTTP challenge):
|
2025-08-22 17:02:49 +09:00
|
|
|
|
2025-08-21 15:24:40 +09:00
|
|
|
```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
|
|
|
|
|
```
|
2025-08-22 17:02:49 +09:00
|
|
|
|
2025-08-21 15:24:40 +09:00
|
|
|
- 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
|
2025-08-22 17:02:49 +09:00
|
|
|
|
2025-08-21 15:24:40 +09:00
|
|
|
```bash
|
|
|
|
|
pnpm prod:deploy
|
|
|
|
|
```
|
2025-08-22 17:02:49 +09:00
|
|
|
|
2025-08-21 15:24:40 +09:00
|
|
|
This will:
|
2025-08-22 17:02:49 +09:00
|
|
|
|
2025-08-21 15:24:40 +09:00
|
|
|
- Build images
|
|
|
|
|
- Start database and cache, wait for health
|
|
|
|
|
- Run migrations
|
|
|
|
|
- Start proxy, frontend, backend
|
|
|
|
|
|
|
|
|
|
## Health checks
|
2025-08-22 17:02:49 +09:00
|
|
|
|
2025-08-21 15:24:40 +09:00
|
|
|
- Proxy/Frontend: https://yourdomain.com/healthz
|
|
|
|
|
- Backend: proxied at https://yourdomain.com/api/health (and container-local http://backend:4000/health)
|
|
|
|
|
|
|
|
|
|
## Renewals
|
2025-08-22 17:02:49 +09:00
|
|
|
|
2025-08-21 15:24:40 +09:00
|
|
|
- A certbot sidecar runs and renews every ~12 hours. On renew, it reloads Nginx.
|
|
|
|
|
|
|
|
|
|
## Notes on security
|
2025-08-22 17:02:49 +09:00
|
|
|
|
2025-08-21 15:24:40 +09:00
|
|
|
- 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
|
2025-08-22 17:02:49 +09:00
|
|
|
|
2025-08-21 15:24:40 +09:00
|
|
|
```bash
|
|
|
|
|
pnpm prod:update
|
|
|
|
|
```
|
2025-08-22 17:02:49 +09:00
|
|
|
|
2025-08-21 15:24:40 +09:00
|
|
|
This rebuilds and recreates `frontend` and `backend` without downtime.
|
|
|
|
|
|
|
|
|
|
## Troubleshooting
|
2025-08-22 17:02:49 +09:00
|
|
|
|
2025-08-21 15:24:40 +09:00
|
|
|
- Check logs:
|
2025-08-22 17:02:49 +09:00
|
|
|
|
2025-08-21 15:24:40 +09:00
|
|
|
```bash
|
|
|
|
|
pnpm prod:logs
|
|
|
|
|
```
|
2025-08-22 17:02:49 +09:00
|
|
|
|
2025-08-21 15:24:40 +09:00
|
|
|
- Validate Nginx config inside container:
|
2025-08-22 17:02:49 +09:00
|
|
|
|
2025-08-21 15:24:40 +09:00
|
|
|
```bash
|
|
|
|
|
docker exec -it portal-proxy nginx -t
|
|
|
|
|
```
|