Zero-Downtime Deployments
Infrastructure

Zero-Downtime Deployments

Choose a deployment strategy that fits your uptime requirements. Compare standard, rolling, and blue/green approaches with config examples.

Every deployment has a moment where old code stops and new code starts. How you handle that moment determines whether your users notice. JuhJuh supports three deployment strategies, each with a different trade-off between simplicity, cost, and downtime.

Strategy comparison

Standard Rolling Blue/Green
Downtime Brief (5-30 seconds) Minimal (1-2 seconds) None
Rollback speed Minutes (redeploy previous version) Minutes Seconds (traffic switch)
VMs required 1 1 3 (1 load balancer + 2 application)
Extra cost None None 2 additional VMs
Complexity Low Low Medium
Best for Internal tools, staging, dev Production with tolerance for brief blips Production with strict uptime requirements
WebSocket handling Connections drop on restart Connections drain before restart Connections drain before switch
Health check Post-deploy only Per-container during rollout Pre-switch verification

Standard deployment

The default strategy. JuhJuh pulls the new container image, stops the running service, and starts the new version. One command, one restart, done.

How it works:

  1. JuhJuh connects to the VM
  2. Pulls the new image
  3. Stops the current containers
  4. Starts the new containers
  5. Runs the health check
  6. Reports success or failure

Downtime window: Between step 3 and step 5. Typically 5 to 30 seconds depending on startup time.

When to use: Staging environments, internal tools, development VMs, and any workload where a few seconds of downtime per deploy is acceptable.

This is the default behavior described in Deployments. No additional configuration needed.

Rolling deployment

A single-VM strategy that reduces downtime by starting the new version before stopping the old one. JuhJuh brings up new containers alongside existing ones, verifies they pass health checks, then drains and removes the old containers.

How it works:

  1. JuhJuh connects to the VM
  2. Pulls the new image
  3. Starts new containers alongside the current ones
  4. Waits for new containers to pass health checks
  5. Drains connections from old containers (respects in-flight requests)
  6. Stops and removes old containers
  7. Reports success

Downtime window: Near zero. A brief moment during the drain phase where new connections route to the new version while old connections finish on the previous version. WebSocket connections on old containers are closed gracefully after the drain timeout.

When to use: Production workloads on a single VM that need minimal disruption without the cost of additional infrastructure.

Configure rolling deployment

Dashboard:

  1. Open your deployment
  2. Under Strategy, select Rolling
  3. Set the health check path (e.g., /health/)
  4. Set the drain timeout in seconds (default: 30). In-flight requests get this long to finish before the old containers are stopped
  5. Deploy as normal

JuhJuh File:

deployments:
  production-app:
    vm: production-app
    image: registry.example.com/my-app
    tag: latest
    strategy: rolling
    healthCheck:
      path: /health/
      interval: 5
      timeout: 10
      retries: 3
    drainTimeout: 30

Blue/green deployment

Two identical application VMs sit behind a dedicated load balancer. One VM is live (serving traffic), the other is idle (a hot spare running the previous version). Deploying means updating the idle VM, verifying it works, and switching traffic in one atomic operation. Zero downtime, instant rollback.

How it works:

sequenceDiagram
    participant You
    participant JuhJuh
    participant LB as Load Balancer VM
    participant Idle as Idle App VM
    participant Live as Live App VM

    You->>JuhJuh: Deploy new version
    JuhJuh->>Idle: Pull image, start services
    JuhJuh->>Idle: Run health checks
    Idle-->>JuhJuh: Healthy
    JuhJuh->>LB: Switch traffic to Idle
    LB->>LB: Drain connections from Live
    Note over LB: Reload completes in <1s
    Idle-->>You: Now serving traffic
    Note over Live: Becomes idle hot spare

Downtime window: None. The load balancer only switches traffic after the newly deployed VM passes health checks. In-flight requests on the previously live VM finish before it goes idle.

Rollback: Seconds. JuhJuh switches traffic back to the other VM, which still runs the previous version. No image pull, no container restart. Just a traffic switch.

What you need

VM Role Always running
Load balancer VM Routes traffic to the active application VM. Handles SSL termination and health monitoring Yes
Application VM (blue) Runs your application. Alternates between live and idle Yes
Application VM (green) Runs your application. Alternates between live and idle Yes

All three VMs are persistent. JuhJuh doesn't create or destroy VMs during deployment. The load balancer VM runs a minimal traffic routing service with no application code.

Architecture

graph TD
    Internet[Internet] --> StaticIP[Static IP]
    StaticIP --> LB[Load Balancer VM]
    LB -->|active| Blue[App VM - Blue]
    LB -.->|idle| Green[App VM - Green]
    Blue --> DB[(Database)]
    Green --> DB
    Blue --> Cache[(Cache)]
    Green --> Cache

The static IP is attached to the load balancer VM, not the application VMs. DNS always points to the load balancer. Switching between blue and green never changes the IP your users connect to.

Configure blue/green deployment

Dashboard:

  1. Provision three VMs: one for the load balancer, two for the application
  2. Navigate to Deployments
  3. Click Create deployment
  4. Under Strategy, select Blue/Green
  5. Select the load balancer VM
  6. Select both application VMs (blue and green)
  7. Set the health check path
  8. Set the drain timeout
  9. Deploy. JuhJuh handles the rest

JuhJuh File:

vms:
  production-lb:
    name: my-app-lb
    env_type: production
    cpu: 1
    memory_gb: 1
    disk_gb: 10
    region: europe-west

  production-blue:
    name: my-app-blue
    env_type: production
    cpu: 4
    memory_gb: 16
    disk_gb: 200
    region: europe-west

  production-green:
    name: my-app-green
    env_type: production
    cpu: 4
    memory_gb: 16
    disk_gb: 200
    region: europe-west

deployments:
  production-app:
    strategy: blue-green
    loadBalancer: production-lb
    targets:
      blue: production-blue
      green: production-green
    image: registry.example.com/my-app
    tag: latest
    vault: app-vault
    services: [web, worker]
    healthCheck:
      path: /health/
      interval: 5
      timeout: 10
      retries: 3
    drainTimeout: 30

Deploy flow

  1. JuhJuh identifies the idle VM (the one not currently receiving traffic)
  2. Connects to the idle VM and pulls the new image
  3. Starts the application services
  4. Runs health checks against the idle VM directly (not through the load balancer)
  5. If healthy, tells the load balancer to switch traffic to the newly deployed VM
  6. The load balancer drains in-flight connections from the previously live VM
  7. The previously live VM becomes the idle hot spare, still running the previous version
  8. Deployment is marked as successful

If the health check fails in step 4, the deployment is marked as failed. Traffic stays on the live VM. Your users don't notice a thing.

Rollback

  1. Click Rollback on the deployment dashboard (or run juhjuh deploy rollback production-app)
  2. JuhJuh switches traffic back to the other VM, which still runs the previous version
  3. The rollback completes in seconds, no image pull required

For deeper rollbacks (to a version older than the one on the idle VM), JuhJuh deploys the selected version to the idle VM first, health checks it, then switches.

Database migration safety

No deployment strategy protects you from a breaking database migration. If your migration locks a table or removes a column the running application still reads, you'll have downtime regardless of how you switch traffic.

Safe migration practices:

  1. Expand first. Add new columns, tables, or indexes in one deploy. Make them nullable or give them defaults so the current application version ignores them
  2. Migrate code. Deploy the new application version that uses the new schema
  3. Contract later. Remove old columns or constraints in a follow-up deploy, after you've confirmed the new version is stable

This expand/migrate/contract pattern keeps old and new application versions compatible with the same database schema at all times.

Avoid in a single deploy:

  • Renaming columns (breaks the running version immediately)
  • Dropping columns the current code still reads
  • Adding NOT NULL constraints without a default value
  • Long-running data backfills that lock tables

Session and state considerations

Blue/green deployments route traffic to a different VM after the switch. If your application stores session data in process memory, users get logged out when traffic moves.

Before enabling blue/green, confirm your sessions are stored externally (in your database or cache). JuhJuh vault secrets are injected into both application VMs, so both connect to the same session store.

WebSocket connections on the previously live VM close during the drain phase. Clients should reconnect automatically. If your client-side code doesn't handle reconnection, users will need to refresh the page after a deploy.

Cost comparison

Assuming identical application VM specs:

Strategy VMs Relative cost
Standard 1 app 1x
Rolling 1 app 1x
Blue/Green 1 LB + 2 app ~2.1x (LB VM is minimal spec)

The load balancer VM only routes traffic. It needs minimal compute (1 CPU, 1 GB RAM, 10 GB disk). The additional cost comes primarily from the second application VM, which mirrors the first.

If you want zero-downtime but can't justify the cost of a third VM, rolling gets you close on a single machine.

CLI reference

# Deploy with strategy override
juhjuh deploy create production-app --strategy blue-green --wait

# Check which VM is currently live
juhjuh deploy status production-app

# Rollback (blue/green: instant traffic switch)
juhjuh deploy rollback production-app --wait

# Drain and switch manually (blue/green only)
juhjuh deploy switch production-app --target blue --wait

Load balancer options

When you select blue/green, JuhJuh provisions a traffic routing service on your load balancer VM. Two routing engines are available.

Standard proxy Advanced balancer
Approach Lightweight reverse proxy Purpose-built load balancer
Active health checks Script-driven (JuhJuh checks health before switching) Built-in (continuously monitors both VMs)
Connection draining Graceful reload, in-flight requests complete First-class drain state with per-connection tracking
SSL termination Excellent, widely documented Good, slightly more configuration
WebSocket support Full support, explicit configuration Full support, native handling
Stats and monitoring Basic; extend with observability tools Rich built-in stats dashboard
Memory footprint ~2-5 MB ~5-10 MB
Configuration Simpler, fewer directives More verbose, more granular control
Switchover mechanism Rewrite upstream config, reload (<1s) Update server state via socket, reload (<1s)

Standard proxy is the default. One upstream definition, one reload command, and JuhJuh handles health verification before the switch. This covers the blue/green use case with minimal moving parts.

Advanced balancer is for teams that need continuous health monitoring at the load balancer level, fine-grained connection draining, or a built-in stats dashboard without additional tooling. Select it during load balancer VM setup or set load_balancer_engine in your JuhJuh File:

deployments:
  production-app:
    strategy: blue-green
    loadBalancer: production-lb
    load_balancer_engine: advanced    # default: standard
    targets:
      blue: production-blue
      green: production-green

Both engines deliver the same outcome: zero-downtime switchover with instant rollback. The difference is in how health monitoring and connection draining work. JuhJuh configures either engine automatically when provisioning the load balancer VM.

Load balancer as a single point of failure

With blue/green, the load balancer VM is the single point through which all traffic flows. If it reboots, traffic stops until it comes back (typically 30 to 60 seconds).

For most teams, this is fine. VM reboots are rare and recovery is fast. If your uptime requirements demand more, two options exist:

  1. Managed cloud load balancer. Place a managed load balancing service in front of your JuhJuh load balancer VM. The managed service handles failover automatically with no VM to maintain. This adds a layer of indirection but removes the single point of failure entirely.

  2. Dual load balancers. Provision two load balancer VMs behind a forwarding rule. If one goes down, the other continues serving. More complex to configure and doubles the load balancer cost, but keeps everything on VMs you control.

Most teams don't need either. Start with a single load balancer VM and revisit if you have contractual uptime SLAs.

Choosing a strategy

Start with standard. It works, it's simple, and a few seconds of downtime per deploy is fine for most workloads.

Move to rolling when your users start noticing deploys, when you deploy frequently during business hours, or when you run WebSocket connections that shouldn't drop unnecessarily.

Move to blue/green when you have strict uptime SLAs, when rollbacks need to be instant, or when you can't afford to discover a bad deploy through user-facing errors. The extra cost is the price of confidence.

You can use different strategies for different deployments in the same organization. Run blue/green for your production API and standard for your staging environment.

  • Deployments: core deployment concepts, versioning, and execution logs
  • VMs: provision the infrastructure your deployments run on
  • Vault: secrets injected into all VMs at deploy time
  • Networking: private networking between load balancer and application VMs
  • Dependencies: coordinate deploy order across multiple services
  • JuhJuh File: define your full deployment strategy in code
  • CLI: trigger deployments, rollbacks, and traffic switches from your terminal
  • Infrastructure Overview: how deployment strategies fit into the broader stack