DEV Community

Ramer Labs
Ramer Labs

Posted on

The Ultimate Checklist for Zero‑Downtime Deploys with Docker & Nginx

Why Zero‑Downtime Matters

In a world where users expect instant responses, even a few seconds of downtime can erode trust. A single failed deployment can cascade into lost revenue, support tickets, and a tarnished brand. For a DevOps lead, the goal is simple: push new code without interrupting live traffic.

Business Impact

  • Revenue protection – E‑commerce sites lose an average of $5,600 per minute of outage.
  • Customer confidence – Repeated glitches increase churn by up to 15 %.
  • Team morale – Frequent rollbacks create a firefighting culture.

Zero‑downtime deployments give you the confidence to ship faster while keeping the user experience seamless.

Pre‑deployment Checklist

Before you touch the production cluster, run through this concise checklist.

  • Version control hygiene
    • All changes are merged into main via PRs.
    • Commit messages follow a conventional format.
  • Infrastructure as code
    • Dockerfiles, compose files, and Nginx configs are stored in the repo.
    • Secrets are injected at runtime, never baked into images.
  • Health‑check endpoints
    • /health returns 200 only when the app is ready.
    • /ready distinguishes between “ready to receive traffic” and “just started”.
  • Database migration strategy
    • Use backward‑compatible migrations.
    • Verify that old and new code can read/write the same schema.
  • Load‑balancer readiness
    • Nginx is configured for graceful draining.
    • Sticky sessions are avoided unless absolutely required.

If any item fails, halt the pipeline and address the gap.

Docker‑Based Release Workflow

Docker gives you immutable artifacts that can be rolled back instantly. Below is a minimal docker‑compose.yml that supports health checks and zero‑downtime swaps.

version: "3.8" services: app: image: myapp:latest ports: - "8080:80" environment: - NODE_ENV=production healthcheck: test: ["CMD", "curl", "-f", "http://localhost/health"] interval: 30s timeout: 10s retries: 3 nginx: image: nginx:stable-alpine ports: - "80:80" volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro depends_on: app: condition: service_healthy 
Enter fullscreen mode Exit fullscreen mode

Key points:

  1. Immutable image tags – Tag each release with a Git SHA (myapp:1a2b3c4d).
  2. Health checks – Nginx will only start forwarding traffic once Docker reports the app as healthy.
  3. Separate containers – Keeps the reverse proxy stateless and easy to upgrade.

Deploy the new stack with:

docker compose pull docker compose up -d --no-deps --scale app=2 
Enter fullscreen mode Exit fullscreen mode

The --scale flag spins up a second instance while the first continues serving traffic. Once the new container passes its health check, you can safely retire the old one.

Nginx Blue‑Green Configuration

Nginx can act as a simple traffic router between two upstream groups: green (current) and blue (new). The snippet below demonstrates a zero‑downtime switch using the upstream and map directives.

# /etc/nginx/nginx.conf worker_processes auto; events { worker_connections 1024; } http { upstream green { server 127.0.0.1:8080; # current version } upstream blue { server 127.0.0.1:8081; # next version } # Variable that decides which upstream to use map $http_x_deploy_stage $upstream { default green; "blue" blue; } server { listen 80; location / { proxy_pass http://$upstream; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } # Health‑check endpoint for Nginx itself location /nginx_status { stub_status on; allow 127.0.0.1; deny all; } } } 
Enter fullscreen mode Exit fullscreen mode

To flip traffic:

# Mark the request header for the next rollout curl -X POST -H "X-Deploy-Stage: blue" http://localhost/some/trigger # Or simply reload Nginx after updating the map file nginx -s reload 
Enter fullscreen mode Exit fullscreen mode

Because Nginx resolves the upstream at request time, existing connections finish on the green servers while new requests flow to blue. After confirming stability, retire the green containers.

CI/CD Integration

Automating the checklist removes human error. Below is a GitHub Actions workflow that builds the Docker image, runs tests, pushes to a registry, and triggers a blue‑green rollout.

name: Deploy Zero‑Downtime on: push: branches: [ main ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - name: Login to Docker Hub uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_USER }} password: ${{ secrets.DOCKER_PASS }} - name: Build and push run: | IMAGE=repo/myapp:${{ github.sha }} docker build -t $IMAGE . docker push $IMAGE - name: Deploy blue version env: IMAGE: ${{ steps.build.outputs.image }} run: | ssh deploy@server "docker pull $IMAGE && docker compose up -d --scale app=2" - name: Verify health run: | curl -f http://server/health || exit 1 - name: Switch Nginx to blue run: | ssh deploy@server "curl -X POST -H 'X-Deploy-Stage: blue' http://localhost/trigger && nginx -s reload" 
Enter fullscreen mode Exit fullscreen mode

The workflow enforces the checklist:

  • Build & test before any image reaches the registry.
  • Push a version‑tagged image, making rollbacks trivial (docker compose up -d app=repo/myapp:previous_sha).
  • Health verification guarantees the new containers are ready.
  • Nginx switch completes the blue‑green transition with a single command.

Observability & Rollback

Zero‑downtime is only as good as your ability to detect problems quickly.

  • Logging – Forward container logs to a centralized system (e.g., Loki or Elastic). Use a label like app=myapp to filter.
  • Metrics – Export Prometheus metrics from both the app and Nginx (/metrics endpoint). Set alerts on latency spikes.
  • Tracing – Enable OpenTelemetry to trace requests across the green and blue instances.

If an alert fires, rollback is a one‑liner:

docker compose up -d --no-deps app=repo/myapp:previous_sha nginx -s reload # revert to green upstream 
Enter fullscreen mode Exit fullscreen mode

Because the previous image is still cached locally, the rollback completes in seconds, keeping user impact minimal.


Zero‑downtime deployments with Docker and Nginx become repeatable once you bake the checklist into your pipeline. If you need help shipping this, the team at https://ramerlabs.com can help.

Top comments (0)