CI/CD·6 min read·

Zero-Downtime Blue-Green Deployments with Docker Compose and Nginx Reloads

Achieve seamless atomic application updates on a single production VPS using dual container sockets, upstream switching, and curl health validation.

NB

Netbay Engineering

Netbay Engineering

On this page

Deploying application updates on a single Linux server often introduces a frustrating window of downtime. When 'docker compose down' executes, existing in-flight HTTP requests are dropped, new incoming TCP connections receive connection refused errors, and users see broken screens until the new containers finish booting.

You do not need an entire Kubernetes cluster to achieve zero-downtime deployments. By maintaining dual parallel container environments (Blue and Green) governed by Docker Compose and an Nginx reverse proxy, you can achieve atomic, request-safe deployments on a single VPS host.

Dual-Upstream Blue-Green Architecture

The blue-green model treats containers as disposable side-by-side color pairs:

  • Active Color (Blue): Runs the current stable release on internal port 3001, receiving 100% of live traffic via Nginx.
  • Idle Color (Green): Receives the new release on internal port 3002. It boots, connects to the database, executes schema checks, and undergoes local curl health verification.
  • Atomic Symlink Switch: Once Green is verified healthy, the deployment script updates an Nginx upstream symlink and executes 'nginx -s reload'. Nginx gracefully hands off active connections to Green without dropping a single packet.
  • Teardown: The previous Blue container is gracefully stopped after a 15-second drain window.
Single-VPS Blue-Green Deployment Architecture Public Traffic HTTPS Port 443 Let's Encrypt TLS Zero In-Flight Drops Nginx Reverse Proxy Upstream: /etc/nginx/live.conf Symlink points to active port Atomic reload: nginx -s reload Worker processes drain gracefully BLUE: Active (Port 3001) Serving live customer requests GREEN: Standby (Port 3002) Warming up & passing health check Atomic Hand-off Guarantee Nginx preserves master process listening socket while spawning new workers Old workers terminate cleanly only after finishing existing connection streams

Docker Compose Configuration with Dual Targets

In 'docker-compose.yml', define the two target color services:

yaml
# /srv/app/docker-compose.yml
version: '3.8'

services:
  app-blue:
    image: registry.example.in/myapp:current
    container_name: app-blue
    restart: always
    ports:
      - "127.0.0.1:3001:3000"
    environment:
      - NODE_ENV=production
      - COLOR=blue

  app-green:
    image: registry.example.in/myapp:current
    container_name: app-green
    restart: always
    ports:
      - "127.0.0.1:3002:3000"
    environment:
      - NODE_ENV=production
      - COLOR=green

Automated Zero-Downtime Deployment Script

Below is the complete deployment script executing container startup, health polling, and atomic symlink cutover:

bash
#!/usr/bin/env bash
set -euo pipefail

# 1. Determine active and idle colors
if [ -f /etc/nginx/current_color ] && [ "$(cat /etc/nginx/current_color)" = "blue" ]; then
    ACTIVE="blue"
    IDLE="green"
    IDLE_PORT="3002"
else
    ACTIVE="green"
    IDLE="blue"
    IDLE_PORT="3001"
fi

echo "Active target: $ACTIVE | Deploying new release to: $IDLE"

# 2. Pull and start idle container
docker compose pull app-$IDLE
docker compose up -d app-$IDLE

# 3. Health check verification loop
echo "Verifying $IDLE health on port $IDLE_PORT..."
for i in {1..30}; do
    if curl -fs "http://127.0.0.1:$IDLE_PORT/healthz" > /dev/null; then
        echo "Health check passed!"
        break
    fi
    sleep 1
    if [ "$i" -eq 30 ]; then
        echo "FATAL: Health check timed out! Aborting deployment."
        docker compose stop app-$IDLE
        exit 1
    fi
done

# 4. Atomic Nginx upstream cutover
echo "upstream backend { server 127.0.0.1:$IDLE_PORT; }" > /etc/nginx/conf.d/upstream.conf
nginx -t && nginx -s reload

echo "$IDLE" > /etc/nginx/current_color
echo "Traffic successfully shifted to $IDLE!"

# 5. Gracefully drain and stop old container
sleep 15
docker compose stop app-$ACTIVE
echo "Zero-downtime deployment finished cleanly."
Expand
Zero Downtime Deployment Pipeline
Zero downtime continuous deployment

Video Guide on Docker & Container Deployments

Watch this fundamental tutorial on Docker container management and deployment workflows:

Docker Tutorial for Beginners
YouTube

Blue-green deployments give small engineering teams enterprise-grade deployment reliability without complex orchestrators.

Run high-performance container stacks with enterprise NVMe storage on Netbay Cloud VPS servers at netbayhosts.in.

Keep reading

Follow along on a real VPS

Deploy Linux in under 60 seconds

These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.

Deploy an instance