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