Run Blue-Green Docker Compose Deployments with Nginx Cutover Checks

Bring up the new stack before you move traffic, validate it while the old stack is still serving, then cut over through Nginx with an explicit rollback path if the new release fails checks.

Docker Compose Nginx Blue-green deploys
Illustrated guide cover for Run Blue-Green Docker Compose Deployments with Nginx Cutover Checks
Docker Compose • Nginx • Blue-green deploys

Before you begin

  • Use this for a stateless or mostly stateless web tier.
  • Keep the database shared and managed outside the blue-green web switch.
  • Have application health endpoints or at least a repeatable smoke test.
  • Know whether the release includes schema changes. If it does, your rollout needs stricter choreography.
Warning: This pattern reduces risk. It does not guarantee literal zero downtime, and it is not a safe shortcut for schema-breaking releases.

Step 1: Keep the scope honest

Blue-green works best when the web tier can run twice for a short window and either version can talk to the shared dependencies. If version B requires a database schema that version A cannot tolerate, treat that as a migration problem first, not just a proxy cutover problem.

  • Good fit: stateless web app with compatible database schema.
  • Risky fit: sticky sessions stored in app memory, destructive one-way migrations, or background workers tightly coupled to one release only.

Step 2: Lay out blue and green services

One practical Compose shape is separate profiles for the inactive stack:

services:
  app_blue:
    image: registry.example.com/myapp:2026-07-05-blue
    environment:
      APP_PORT: 8080
    ports:
      - "127.0.0.1:18080:8080"

  app_green:
    image: registry.example.com/myapp:2026-07-05-green
    environment:
      APP_PORT: 8080
    ports:
      - "127.0.0.1:28080:8080"
    profiles: ["green"]

Docker's Compose profiles let you keep optional services out of the default docker compose up flow. That makes it easier to start the inactive color only when you need it.

docker compose --profile green up -d app_green

Step 3: Run preflight checks before cutover

Do not touch Nginx until the new color passes direct checks.

curl -fsS http://127.0.0.1:28080/health
curl -I http://127.0.0.1:28080/
docker compose logs --tail=100 app_green

Expected outcome:

  • The container is healthy and serving.
  • The app can connect to shared dependencies.
  • Critical smoke-test flows pass before public traffic moves.

Step 4: Swap Nginx upstreams safely

Use an upstream file that points at the active color:

upstream myapp_active {
    server 127.0.0.1:18080;
}

When green is ready, change it to:

upstream myapp_active {
    server 127.0.0.1:28080;
}

Then validate and reload Nginx in the documented order:

sudo nginx -t
sudo systemctl reload nginx

Nginx supports reloading configuration without killing the master process abruptly. That is the right moment to move traffic after the new stack is already serving locally.

Step 5: Roll back if the new stack fails

If public checks fail after cutover, do not debug under load for long. Point the upstream back to blue, validate, and reload again.

sudo nginx -t
sudo systemctl reload nginx
docker compose stop app_green

Rollback should mean:

  • Traffic is back on the known-good color.
  • The failed color stays available for logs and postmortem if you need it.
  • You do not destroy the old stack until the new one proves itself.

Limits and warnings

Schema changes:
If the new release requires a one-way migration, the proxy swap is not the hardest part. Plan maintenance or compatibility windows separately.

Sticky sessions:
If users depend on in-memory sessions, a simple upstream swap may log them out or break active flows.

Shared background workers:
Avoid running incompatible worker versions against one queue during the overlap window.