Production Deployment
1. DNS Setup
Point your A record to the VM public IP.
app.yourdomain.comfor the main UI and APIoauth.yourdomain.com(optional) for Hydra public OAuth2
2. Update .env for Production
# Public URLs
BASE_URL=https://app.yourdomain.com
HYDRA_PUBLIC_URL=https://oauth.yourdomain.com # or https://app.yourdomain.com/oauth2
REACT_APP_URL=https://app.yourdomain.com
# Domains for WebAuthn RP (no protocol/port)
DOMAIN=yourdomain.com
APP_DOMAIN=app.yourdomain.com
WEBAUTHN_ORIGIN=https://app.yourdomain.com
# Security hardening
ENVIRONMENT=production
GIN_MODE=release
REQUIRE_SERVER_AUTH=true
CORS_ALLOW_ORIGIN=https://app.yourdomain.com
TENANT_DOMAIN_SUFFIX=yourdomain.com
# SMTP provider
SMTP_HOST=smtp.yourmailprovider.com
SMTP_PORT=587
SMTP_USER=noreply@yourdomain.com
SMTP_PASSWORD=your-smtp-password
3. Configure TLS (Let's Encrypt)
sudo apt install -y certbot
sudo certbot certonly --standalone -d app.yourdomain.com
sudo chmod -R 755 /etc/letsencrypt/live/ /etc/letsencrypt/archive/
Enable TLS server blocks and cert paths in nginx/nginx.conf, then restart:
docker compose restart nginx
Auto-renew:
echo "0 3 * * * certbot renew --quiet && docker compose -f /path/to/onprem/docker-compose.yaml restart nginx" \
| sudo tee -a /etc/cron.d/certbot-renew
4. Firewall Rules
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw --force enable
Keep Postgres, Redis, and Hydra admin ports private (localhost only).
Final hardening step: Security Checklist.