HashiCorp Vault — HA Architecture

2 minute read

Vault’s HA architecture uses a single active node for writes, with standby nodes that forward requests or serve reads directly.


Leader Election

Startup:
  All nodes start → compete for leader lock
  One node wins → becomes Active
  Others → become Standby

Failover:
  Active node goes down
  → Standby nodes detect failure
  → New leader elected (seconds)
  → Clients redirect to new active node

Node Types

Type Reads Writes When
Active ✅ Yes ✅ Yes One per cluster
Standby Forward to active Forward to active OSS behavior
Performance Standby ✅ Yes (local) Forward to active Enterprise

Basic HA Configuration

# vault-config.hcl

# Node identity
cluster_name = "vault-prod"
cluster_addr = "https://node1.vault.internal:8201"
api_addr     = "https://node1.vault.internal:8200"

listener "tcp" {
  address         = "0.0.0.0:8200"
  cluster_address = "0.0.0.0:8201"
  tls_cert_file   = "/etc/vault/tls/cert.pem"
  tls_key_file    = "/etc/vault/tls/key.pem"
}

# Raft integrated storage (HA built-in)
storage "raft" {
  path    = "/vault/data"
  node_id = "node1"
}

# UI
ui = true

Request Forwarding

Client → Standby Node → Forwards to Active → Response

With performance standbys (Enterprise):
Client → Perf Standby → Serves read locally → Response (fast!)
Client → Perf Standby → Write → Forward to Active → Response

Standby Redirect vs Forward

Mode Behavior
Forward (default) Standby proxies request to active, returns response
Redirect Standby returns HTTP 307 redirect to active’s api_addr

Health Check Endpoints

# Active node (returns 200)
curl -s "$VAULT_ADDR/v1/sys/health" | jq
# {"initialized": true, "sealed": false, "standby": false}

# Standby node (returns 429 by default)
curl -s -o /dev/null -w "%{http_code}" "$STANDBY_ADDR/v1/sys/health"
# 429

# Check for any healthy node (active or standby)
curl -s -o /dev/null -w "%{http_code}" \
    "$VAULT_ADDR/v1/sys/health?standbyok=true"
# 200

Health Endpoint Parameters

Parameter Default Description
standbyok false Return 200 for standby nodes
perfstandbyok false Return 200 for performance standbys
activecode 200 Status code for active node
standbycode 429 Status code for standby node
sealedcode 503 Status code for sealed node

Load Balancer Configuration

                    ┌────────────────┐
                    │ Load Balancer  │
                    │                │
                    │ Health check:  │
                    │ /v1/sys/health │
                    │ ?standbyok=true│
                    └───────┬────────┘
                ┌───────────┼───────────┐
                ▼           ▼           ▼
           ┌────────┐ ┌────────┐ ┌────────┐
           │ Node 1 │ │ Node 2 │ │ Node 3 │
           │(Active)│ │(Stdby) │ │(Stdby) │
           └────────┘ └────────┘ └────────┘

Use ?standbyok=true so the LB routes to all healthy nodes. Standby nodes will forward writes to the active node transparently.


Monitoring HA Status

# Check if node is leader
vault status -format=json | jq '.ha_enabled, .is_self'

# List HA status
vault operator raft list-peers

# Check leader
curl -s "$VAULT_ADDR/v1/sys/leader" | jq

Quick Reference

Command Description
vault status Check node status (active/standby)
vault operator raft list-peers List all Raft cluster members
/v1/sys/health Health check endpoint
/v1/sys/leader Current leader info

Next: Raft Storage