feat: production infra — nginx configs, deploy script, security hardening
Some checks failed
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 58s
Deploy / Build Web Image (push) Failing after 14s
Deploy / Rollback Production (push) Has been skipped
CI / E2E Tests (push) Has been skipped
Deploy / Build API Image (push) Failing after 3m8s
Deploy / Build AI Services Image (push) Failing after 10s
E2E Tests / Playwright E2E (push) Failing after 1m21s
Deploy / Deploy to Staging (push) Has been skipped
Deploy / Smoke Test Staging (push) Has been skipped
Deploy / Deploy to Production (push) Has been skipped
Deploy / Smoke Test Production (push) Has been skipped
Deploy / Rollback Staging (push) Has been skipped

- Add Nginx reverse-proxy configs for api.goodgo.vn and platform.goodgo.vn
  with SSL, gzip, rate limiting, security headers, and WebSocket support
- Add Cloudflare DNS setup script for A/AAAA/CNAME records
- Add server-setup.sh for Ubuntu provisioning (Docker, fail2ban, UFW,
  swap, unattended-upgrades)
- Add deploy-production.sh for manual production deployments
- Add env.production.example with all required environment variables
- Bind container ports to 127.0.0.1 in docker-compose.prod.yml
  (security: prevent direct access bypassing Nginx)
- Fix deploy workflow: add -T flag to exec, sync Nginx configs,
  copy pgbouncer and backup configs to server

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ho Ngoc Hai
2026-04-13 14:11:25 +07:00
parent b93c28fa01
commit e5f7acf7da
9 changed files with 946 additions and 6 deletions

View File

@@ -197,9 +197,11 @@ jobs:
DEPLOY_KEY: ${{ secrets.STAGING_SSH_KEY }}
IMAGE_TAG: ${{ github.sha }}
run: |
# Copy production compose and deploy
# Copy production compose, monitoring, and infra configs
scp -i ~/.ssh/deploy_key docker-compose.prod.yml "$DEPLOY_USER@$DEPLOY_HOST:~/goodgo/"
scp -i ~/.ssh/deploy_key -r monitoring/ "$DEPLOY_USER@$DEPLOY_HOST:~/goodgo/monitoring/"
scp -i ~/.ssh/deploy_key -r infra/pgbouncer/ "$DEPLOY_USER@$DEPLOY_HOST:~/goodgo/infra/pgbouncer/"
scp -i ~/.ssh/deploy_key -r scripts/backup/ "$DEPLOY_USER@$DEPLOY_HOST:~/goodgo/scripts/backup/"
ssh -i ~/.ssh/deploy_key "$DEPLOY_USER@$DEPLOY_HOST" << DEPLOY_SCRIPT
cd ~/goodgo
@@ -218,12 +220,29 @@ jobs:
docker compose -f docker-compose.prod.yml up -d --no-deps --wait ai-services
# Run database migrations
docker compose -f docker-compose.prod.yml exec api npx prisma migrate deploy
docker compose -f docker-compose.prod.yml exec -T api npx prisma migrate deploy
# Cleanup old images
docker image prune -f
DEPLOY_SCRIPT
- name: Sync Nginx configs
env:
DEPLOY_HOST: ${{ secrets.STAGING_HOST }}
DEPLOY_USER: ${{ secrets.STAGING_USER }}
DEPLOY_KEY: ${{ secrets.STAGING_SSH_KEY }}
run: |
scp -i ~/.ssh/deploy_key infra/nginx/*.conf \
"$DEPLOY_USER@$DEPLOY_HOST:/tmp/goodgo-nginx/"
ssh -i ~/.ssh/deploy_key "$DEPLOY_USER@$DEPLOY_HOST" << 'NGINX_SCRIPT'
sudo mkdir -p /tmp/goodgo-nginx
sudo cp /tmp/goodgo-nginx/*.conf /etc/nginx/sites-available/ 2>/dev/null || true
for conf in /etc/nginx/sites-available/*goodgo*; do
[ -f "$conf" ] && sudo ln -sf "$conf" /etc/nginx/sites-enabled/
done
sudo nginx -t && sudo systemctl reload nginx
NGINX_SCRIPT
- name: Verify staging deployment
env:
STAGING_URL: ${{ secrets.STAGING_URL }}
@@ -372,8 +391,11 @@ jobs:
chmod 600 ~/.ssh/deploy_key
ssh-keyscan -H "$DEPLOY_HOST" >> ~/.ssh/known_hosts 2>/dev/null
# Copy configs
scp -i ~/.ssh/deploy_key docker-compose.prod.yml "$DEPLOY_USER@$DEPLOY_HOST:~/goodgo/"
scp -i ~/.ssh/deploy_key -r monitoring/ "$DEPLOY_USER@$DEPLOY_HOST:~/goodgo/monitoring/"
scp -i ~/.ssh/deploy_key -r infra/pgbouncer/ "$DEPLOY_USER@$DEPLOY_HOST:~/goodgo/infra/pgbouncer/"
scp -i ~/.ssh/deploy_key -r scripts/backup/ "$DEPLOY_USER@$DEPLOY_HOST:~/goodgo/scripts/backup/"
ssh -i ~/.ssh/deploy_key "$DEPLOY_USER@$DEPLOY_HOST" << DEPLOY_SCRIPT
cd ~/goodgo
@@ -389,11 +411,27 @@ jobs:
docker compose -f docker-compose.prod.yml up -d --no-deps --wait web
docker compose -f docker-compose.prod.yml up -d --no-deps --wait ai-services
docker compose -f docker-compose.prod.yml exec api npx prisma migrate deploy
docker compose -f docker-compose.prod.yml exec -T api npx prisma migrate deploy
docker image prune -f
DEPLOY_SCRIPT
- name: Sync Nginx configs (production)
env:
DEPLOY_HOST: ${{ secrets.PRODUCTION_HOST }}
DEPLOY_USER: ${{ secrets.PRODUCTION_USER }}
DEPLOY_KEY: ${{ secrets.PRODUCTION_SSH_KEY }}
run: |
scp -i ~/.ssh/deploy_key infra/nginx/*.conf \
"$DEPLOY_USER@$DEPLOY_HOST:/tmp/goodgo-nginx/"
ssh -i ~/.ssh/deploy_key "$DEPLOY_USER@$DEPLOY_HOST" << 'NGINX_SCRIPT'
sudo cp /tmp/goodgo-nginx/*.conf /etc/nginx/sites-available/ 2>/dev/null || true
for conf in /etc/nginx/sites-available/*goodgo*; do
[ -f "$conf" ] && sudo ln -sf "$conf" /etc/nginx/sites-enabled/
done
sudo nginx -t && sudo systemctl reload nginx
NGINX_SCRIPT
- name: Verify production deployment
env:
PRODUCTION_URL: ${{ secrets.PRODUCTION_URL }}