Set up a professional CI/CD pipeline: automated testing, Docker multi-stage builds, container registry, and rolling deployments on a VPS.
The Goal
Every git push to main should automatically: run tests โ build a Docker image โ push to registry โ deploy to VPS with zero downtime. Total pipeline time: under 3 minutes.
1. Multi-Stage Dockerfile
Multi-stage builds keep the final image small (<200 MB):
Enable output: 'standalone' in next.config.ts to generate the minimal server bundle.
2. GitHub Actions Workflow
Three jobs: test โ build โ deploy, each gated on the previous:
npm test + ESLint + TypeScript checkdocker build, tag with github.sha, push to GHCR3. Zero Downtime with Docker Compose + Health Checks
Add a health check so Docker waits for the app to be ready before taking the old container down:
Use --detach --wait with docker compose up so the deploy step blocks until the new container passes health checks before removing the old one.
4. Secret Management
Store secrets in GitHub Actions Secrets (SSH key, registry token, env vars). Inject at deploy time โ never bake secrets into the Docker image.
5. Nginx Reverse Proxy
Sit Nginx in front of the Next.js container for TLS termination, HTTP/2, static asset caching, and as a load balancer if you scale to multiple replicas.
Key Takeaways
1. Multi-stage Docker builds dramatically reduce image size
2. Always tag images with a unique identifier (commit SHA)
3. Health checks are non-negotiable for zero-downtime deploys
4. Keep secrets out of images โ inject at runtime
5. Nginx + Certbot = free, automatic HTTPS