HashiCorp Vault — Production Server

3 minute read

A production Vault server uses persistent storage, TLS encryption, and proper initialization. This page covers everything you need to run Vault in a production-like environment.


Production Configuration File

Create /etc/vault.d/vault.hcl:

# /etc/vault.d/vault.hcl

# Raft integrated storage
storage "raft" {
  path    = "/opt/vault/data"
  node_id = "vault-1"
}

# HTTPS listener
listener "tcp" {
  address       = "0.0.0.0:8200"
  tls_cert_file = "/opt/vault/tls/vault-cert.pem"
  tls_key_file  = "/opt/vault/tls/vault-key.pem"
}

# Cluster address (for HA communication)
cluster_addr = "https://127.0.0.1:8201"

# API address (what clients use to reach Vault)
api_addr = "https://127.0.0.1:8200"

# Enable the web UI
ui = true

# Prevent memory from being swapped to disk
disable_mlock = false

# Telemetry for monitoring
telemetry {
  prometheus_retention_time = "24h"
  disable_hostname         = true
}

Directory Setup

# Create directories
sudo mkdir -p /opt/vault/data
sudo mkdir -p /opt/vault/tls
sudo mkdir -p /etc/vault.d
sudo mkdir -p /var/log/vault

# Create vault user (non-root)
sudo useradd --system --home /opt/vault --shell /bin/false vault

# Set ownership
sudo chown -R vault:vault /opt/vault
sudo chown -R vault:vault /etc/vault.d
sudo chown -R vault:vault /var/log/vault

# Set permissions
sudo chmod 750 /opt/vault/data
sudo chmod 700 /opt/vault/tls

Generate Self-Signed TLS Certificates (Lab Only)

For production, use certificates from your PKI or a public CA. For labs:

# Generate self-signed certificate
openssl req -x509 -nodes -days 365 \
    -newkey rsa:2048 \
    -keyout /opt/vault/tls/vault-key.pem \
    -out /opt/vault/tls/vault-cert.pem \
    -subj "/CN=vault.local" \
    -addext "subjectAltName=DNS:vault.local,DNS:localhost,IP:127.0.0.1"

# Set permissions
sudo chown vault:vault /opt/vault/tls/*
sudo chmod 600 /opt/vault/tls/vault-key.pem
sudo chmod 644 /opt/vault/tls/vault-cert.pem

Start Vault

Manual Start

vault server -config=/etc/vault.d/vault.hcl

Systemd Service

Create /etc/systemd/system/vault.service:

[Unit]
Description=HashiCorp Vault
Documentation=https://www.vaultproject.io/docs
Requires=network-online.target
After=network-online.target
ConditionFileNotEmpty=/etc/vault.d/vault.hcl

[Service]
User=vault
Group=vault
ProtectSystem=full
ProtectHome=read-only
PrivateTmp=yes
PrivateDevices=yes
SecureBits=keep-caps
AmbientCapabilities=CAP_IPC_LOCK
NoNewPrivileges=yes
ExecStart=/usr/local/bin/vault server -config=/etc/vault.d/vault.hcl
ExecReload=/bin/kill --signal HUP $MAINPID
KillMode=process
KillSignal=SIGINT
Restart=on-failure
RestartSec=5
TimeoutStopSec=30
LimitNOFILE=65536
LimitMEMLOCK=infinity

[Install]
WantedBy=multi-user.target
# Enable and start
sudo systemctl daemon-reload
sudo systemctl enable vault
sudo systemctl start vault

# Check status
sudo systemctl status vault

Initialize Vault

The first time Vault starts, it must be initialized:

# Set the address (use HTTPS with -tls-skip-verify for self-signed certs)
export VAULT_ADDR='https://127.0.0.1:8200'
export VAULT_SKIP_VERIFY=true    # Only for self-signed certs in labs

# Initialize with default Shamir parameters (5 shares, threshold 3)
vault operator init

Expected output:

Unseal Key 1: MIGHAoGBAL...
Unseal Key 2: MIGHAoGBAM...
Unseal Key 3: MIGHAoGBAK...
Unseal Key 4: MIGHAoGBAJ...
Unseal Key 5: MIGHAoGBAI...

Initial Root Token: hvs.KLhFgN...

Vault initialized with 5 key shares and a key threshold of 3.
Please securely distribute the key shares printed above.

⚠️ Critical: Save the unseal keys and root token securely. This is the only time they are displayed.

Custom Initialization

# Fewer key shares (3 shares, threshold 2)
vault operator init -key-shares=3 -key-threshold=2

# PGP-encrypted keys (recommended for distribution)
vault operator init \
    -key-shares=5 \
    -key-threshold=3 \
    -pgp-keys="alice.asc,bob.asc,carol.asc,dave.asc,eve.asc"

Unseal Vault

# Check status (sealed)
vault status
# Sealed: true

# Provide unseal keys (repeat until threshold is met)
vault operator unseal MIGHAoGBAL...
# Unseal Progress: 1/3

vault operator unseal MIGHAoGBAM...
# Unseal Progress: 2/3

vault operator unseal MIGHAoGBAK...
# Sealed: false  ← Vault is now unsealed!

Login with Root Token

# Login
vault login hvs.KLhFgN...

# Verify
vault token lookup

Expected output:

Key                  Value
---                  -----
accessor             abc123
creation_time        1706198400
creation_ttl         0
display_name         root
entity_id            n/a
expire_time          <nil>
explicit_max_ttl     0
id                   hvs.KLhFgN...
meta                 <nil>
num_uses             0
orphan               true
path                 auth/token/root
policies             [root]
renewable            false
ttl                  0
type                 service

Production Docker Setup

For a more production-like Docker deployment:

# docker-compose-vault-prod.yml
services:
  vault:
    image: hashicorp/vault:1.15
    container_name: vault-prod
    ports:
      - "8200:8200"
    volumes:
      - ./vault/data:/vault/data
      - ./vault/config:/vault/config
      - ./vault/tls:/vault/tls
    environment:
      VAULT_ADDR: "https://0.0.0.0:8200"
    cap_add:
      - IPC_LOCK
    command: vault server -config=/vault/config/vault.hcl
    restart: unless-stopped

vault/config/vault.hcl:

storage "raft" {
  path    = "/vault/data"
  node_id = "vault-1"
}

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

api_addr     = "https://127.0.0.1:8200"
cluster_addr = "https://127.0.0.1:8201"
ui           = true

Post-Init Checklist

After initializing a production Vault:

✅ Save unseal keys in separate secure locations
✅ Revoke the root token after initial setup
✅ Enable audit devices
✅ Create admin policies and auth methods
✅ Enable required secrets engines
✅ Set up monitoring and alerting
✅ Configure auto-unseal (AWS KMS, Azure KV, etc.)
✅ Schedule backup procedures

Revoke the root token:

# Create admin user/policy first, then:
vault token revoke hvs.KLhFgN...

Quick Reference

Command Description
vault server -config=vault.hcl Start production server
vault operator init Initialize Vault
vault operator init -key-shares=N -key-threshold=M Custom Shamir params
vault operator unseal <key> Provide unseal key
vault login <token> Authenticate
vault token revoke <token> Revoke a token
systemctl start vault Start via systemd
systemctl status vault Check service status

Next: Storage Backends