Introduction & What is OpenBao
OpenBao is an open-source, community-driven fork of HashiCorp Vault, governed by the Linux Foundation and the Open Source Security Foundation (OpenSSF). Following HashiCorp's switch to a Business Source License (BSL), OpenBao emerged as the truly open-source alternative under the MPL 2.0 license — offering the same battle-tested architecture with no vendor lock-in.
Why OpenBao on RamNode?
- Full control over your secrets infrastructure on dedicated VPS resources
- No per-secret or per-request pricing — flat VPS cost regardless of usage
- Low-latency access from RamNode's high-performance network
- Ideal for self-hosters, small teams, and budget-conscious developers
- Perfect complement to existing self-hosted infrastructure
Key Features
| Feature | Description |
|---|---|
| Secret Storage | Encrypted at rest with AES-256-GCM; KV, database credentials, SSH keys, and more |
| Dynamic Secrets | Generate short-lived credentials on demand for databases and services |
| Encryption as a Service | Centralized transit encryption without exposing keys to applications |
| Access Control | Fine-grained ACL policies with LDAP, OIDC, AppRole authentication |
| Audit Logging | Comprehensive audit trail of every secret access and operation |
| Web UI | Built-in web interface for visual secret management |
| Namespaces | Multi-tenant isolation for teams and environments |
| PKI/Certificates | Built-in Certificate Authority with ACME support |
Prerequisites
- A RamNode VPS running Ubuntu 22.04 or 24.04 LTS
- Root or sudo access to your server
- A domain name pointed to your server's IP address (recommended for TLS)
- Basic familiarity with the Linux command line
- SSH access configured with key-based authentication
Note: This guide assumes intermediate Linux administration experience. If you're new to secrets management, the Docker deployment method (Method A) provides the quickest path to a working setup.
RamNode VPS Sizing Recommendations
| Use Case | vCPUs | RAM | Storage | Notes |
|---|---|---|---|---|
| Dev/Testing | 1 | 1 GB | 20 GB SSD | Dev mode, single user |
| Small Team | 2 | 2 GB | 40 GB SSD | Up to 10 users, KV + basic auth |
| Production | 2–4 | 4 GB+ | 80 GB SSD | Dynamic secrets, PKI, audit logs |
| High Availability | 4+ | 8 GB+ | 100 GB SSD | Raft cluster, multiple nodes |
RamNode Tip: For most self-hosting use cases, a 2 GB RAM VPS provides excellent performance. OpenBao's integrated Raft storage eliminates the need for an external database, keeping your deployment simple and cost-effective.
Method A: Docker Deployment (Recommended)
Docker provides the fastest path to a production-ready OpenBao deployment with easy upgrades and rollbacks.
Step 1: Install Docker
sudo apt update && sudo apt upgrade -y
sudo apt install -y ca-certificates curl gnupg
# Add Docker's official GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Add the Docker repository
echo "deb [arch=$(dpkg --print-architecture) \
signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo $VERSION_CODENAME) stable" \
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-pluginStep 2: Create Directory Structure
sudo mkdir -p /opt/openbao/{config,data,logs}
sudo chown -R 100:1000 /opt/openbaoStep 3: Create Configuration File
cluster_name = "ramnode-openbao"
ui = true
storage "raft" {
path = "/openbao/file"
node_id = "node1"
}
listener "tcp" {
address = "0.0.0.0:8200"
tls_disable = true # We will add TLS in Section 11
}
api_addr = "http://YOUR_SERVER_IP:8200"
cluster_addr = "http://YOUR_SERVER_IP:8201"
default_lease_ttl = "168h"
max_lease_ttl = "720h"
disable_mlock = trueImportant: Replace YOUR_SERVER_IP with your RamNode VPS public IP address. TLS will be configured later — do not expose port 8200 to the public internet without TLS in production.
Step 4: Create Docker Compose File
services:
openbao:
image: openbao/openbao:latest
container_name: openbao
restart: unless-stopped
cap_add:
- IPC_LOCK
ports:
- "8200:8200"
- "8201:8201"
volumes:
- /opt/openbao/config:/openbao/config:ro
- /opt/openbao/data:/openbao/file
- /opt/openbao/logs:/openbao/logs
environment:
BAO_ADDR: "http://127.0.0.1:8200"
BAO_API_ADDR: "http://YOUR_SERVER_IP:8200"
command: server
mem_swappiness: 0Step 5: Start OpenBao
cd /opt/openbao
sudo docker compose up -d
# Verify the container is running
sudo docker compose logs -f openbaoYou should see output indicating the server has started and is listening on port 8200. The server will report that it is sealed and not yet initialized — this is expected.
Method B: Native Package Installation
For those who prefer running OpenBao directly on the host without Docker.
Step 1: Install OpenBao from Official Repository
# Install dependencies
sudo apt update && sudo apt install -y gpg wget
# Add the OpenBao GPG key and repository
wget -O- https://pkg.openbao.org/gpg.key \
| sudo gpg --dearmor -o /usr/share/keyrings/openbao-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/openbao-keyring.gpg] \
https://pkg.openbao.org/deb stable main" \
| sudo tee /etc/apt/sources.list.d/openbao.list
sudo apt update
sudo apt install -y openbaoStep 2: Verify Installation
bao version
# Expected output: OpenBao v2.5.0 (...)Step 3: Configure OpenBao
cluster_name = "ramnode-openbao"
ui = true
storage "raft" {
path = "/var/lib/openbao/data"
node_id = "node1"
}
listener "tcp" {
address = "0.0.0.0:8200"
tls_disable = true
}
api_addr = "http://YOUR_SERVER_IP:8200"
cluster_addr = "http://YOUR_SERVER_IP:8201"
default_lease_ttl = "168h"
max_lease_ttl = "720h"Step 4: Prepare Data Directory and Start
sudo mkdir -p /var/lib/openbao/data
sudo chown -R openbao:openbao /var/lib/openbao
sudo systemctl enable openbao
sudo systemctl start openbao
sudo systemctl status openbaoStep 5: Set Environment Variable
# Add to ~/.bashrc or ~/.profile
export BAO_ADDR="http://127.0.0.1:8200"
# Reload your shell
source ~/.bashrcInitializing & Unsealing OpenBao
After starting OpenBao for the first time, you must initialize it to generate encryption keys and a root token. This is a one-time operation.
Initialize the Server
# Docker method:
sudo docker exec openbao bao operator init
# Native method:
bao operator initThis outputs 5 unseal keys and an Initial Root Token. By default, OpenBao uses Shamir's Secret Sharing with 5 key shares and a threshold of 3.
Critical Security Step: Store each unseal key and the root token in separate, secure locations. Consider a password manager, HSM, or splitting keys among trusted team members. If you lose enough unseal keys, your secrets are permanently inaccessible.
Unseal the Server
Provide 3 of the 5 unseal keys. Repeat this command three times with different keys:
# Docker method:
sudo docker exec -it openbao bao operator unseal
# Native method:
bao operator unsealVerify Status
# Docker method:
sudo docker exec openbao bao status
# Native method:
bao statusAuthenticate with Root Token
# Docker method:
sudo docker exec -e BAO_TOKEN="YOUR_ROOT_TOKEN" \
openbao bao token lookup
# Native method:
bao login YOUR_ROOT_TOKENEnabling the Web UI
The web UI is enabled by the ui = true directive in your configuration file (already included in both methods above). Once OpenBao is initialized and unsealed, access the UI at:
http://YOUR_SERVER_IP:8200Log in using your root token or any valid authentication token. The UI provides visual management for secrets engines, access policies, authentication methods, and audit devices.
Pro Tip: For secure remote access without exposing the UI to the internet, use an SSH tunnel: ssh -L 8200:127.0.0.1:8200 user@your-ramnode-ip. Then access the UI at http://localhost:8200.
Configuring the KV Secrets Engine
The Key/Value (KV) secrets engine is the most commonly used engine for storing arbitrary secrets.
Enable KV v2 Secrets Engine
# Enable the KV v2 secrets engine at the 'secret' path
bao secrets enable -path=secret kv-v2Store a Secret
bao kv put secret/myapp/config \
db_host="db.example.com" \
db_user="appuser" \
db_password="s3cur3P@ssw0rd"Retrieve a Secret
# Read the secret
bao kv get secret/myapp/config
# Get a specific field
bao kv get -field=db_password secret/myapp/config
# Output as JSON (useful for scripts)
bao kv get -format=json secret/myapp/configVersion History
KV v2 automatically versions secrets, allowing you to view previous values and roll back:
# View metadata and version history
bao kv metadata get secret/myapp/config
# Read a specific version
bao kv get -version=1 secret/myapp/configSetting Up Access Policies
Policies define what paths a token can access and what operations are allowed. Never use the root token for regular operations — create scoped policies instead.
Create an Application Policy
# Allow read access to application secrets
path "secret/data/myapp/*" {
capabilities = ["read", "list"]
}
# Allow the app to renew its own token
path "auth/token/renew-self" {
capabilities = ["update"]
}Apply the Policy
bao policy write myapp myapp-policy.hcl
# Verify
bao policy read myappCreate a Token with the Policy
bao token create -policy=myapp -ttl=24hEnable AppRole Authentication (Recommended for Apps)
# Enable AppRole auth
bao auth enable approle
# Create a role for your application
bao write auth/approle/role/myapp \
token_policies=myapp \
token_ttl=1h \
token_max_ttl=4h \
secret_id_ttl=10m
# Get the Role ID
bao read auth/approle/role/myapp/role-id
# Generate a Secret ID
bao write -f auth/approle/role/myapp/secret-id
# Authenticate (from your application)
bao write auth/approle/login \
role_id=YOUR_ROLE_ID \
secret_id=YOUR_SECRET_IDEnabling Audit Logging
Audit logging records every request and response to OpenBao, providing a comprehensive trail for compliance and security investigation.
Enable File-Based Audit Log
# For Docker deployments:
bao audit enable file file_path=/openbao/logs/audit.log
# For native deployments:
bao audit enable file file_path=/var/log/openbao/audit.logVerify Audit Device
bao audit list -detailedLog Rotation
/var/log/openbao/audit.log {
daily
rotate 30
compress
missingok
notifempty
postrotate
/bin/kill -HUP $(cat /var/run/openbao.pid 2>/dev/null) 2>/dev/null || true
endscript
}TLS Configuration with Let's Encrypt
Production deployments must use TLS to encrypt all communication with the OpenBao server.
Option A: Reverse Proxy with Nginx (Recommended)
sudo apt install -y nginx certbot python3-certbot-nginxserver {
listen 443 ssl http2;
server_name bao.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/bao.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/bao.yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8200;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}sudo ln -s /etc/nginx/sites-available/openbao /etc/nginx/sites-enabled/
sudo certbot --nginx -d bao.yourdomain.com
sudo systemctl reload nginxOption B: Native TLS in OpenBao
listener "tcp" {
address = "0.0.0.0:8200"
tls_cert_file = "/path/to/fullchain.pem"
tls_key_file = "/path/to/privkey.pem"
}Update your api_addr to use https:// and restart OpenBao.
Production Hardening Checklist
| # | Item | Details |
|---|---|---|
| 1 | Enable TLS | Never run without TLS in production |
| 2 | Revoke Root Token | After initial setup: bao token revoke YOUR_ROOT_TOKEN |
| 3 | Disable Swap | Use swapoff -a or ensure swap is encrypted |
| 4 | Enable Audit Logging | At least one audit device must be active |
| 5 | Firewall Rules | Restrict port 8200 to known IPs; block 8201 externally unless clustering |
| 6 | Least-Privilege Policies | Create scoped policies per application; never share root token |
| 7 | Token TTLs | Set short TTLs and require renewal; avoid long-lived tokens |
| 8 | Unseal Key Distribution | Split unseal keys among multiple trusted operators |
| 9 | Regular Updates | Subscribe to OpenBao's security advisories and update promptly |
| 10 | Monitor & Alert | Monitor /v1/sys/health endpoint; alert on seal events |
Backup & Recovery
The integrated Raft storage backend supports native snapshots for backup and recovery.
Raft Snapshot Backup
# Create a snapshot
bao operator raft snapshot save backup.snap
# Automate with cron (daily at 2 AM)
0 2 * * * /usr/bin/bao operator raft snapshot save \
/opt/openbao/backups/bao-$(date +\%Y\%m\%d).snapRestore from Snapshot
# Restore (requires initialized and unsealed server)
bao operator raft snapshot restore backup.snapBackup Security: Snapshots contain all your secrets in encrypted form. Store backups in an encrypted, off-site location. The unseal keys are still required to access the data after restore.
Troubleshooting
| Issue | Solution |
|---|---|
| Server won't start | Check logs: docker compose logs openbao or journalctl -u openbao. Verify config syntax. |
| Connection refused on 8200 | Ensure listener address is 0.0.0.0:8200 (not 127.0.0.1) if accessing remotely. Check firewall. |
| Server is sealed after restart | OpenBao seals on restart by design. Unseal with 3 of 5 keys each time. Consider auto-unseal with a KMS. |
| Permission denied errors | Verify your token has the correct policy attached. Use bao token lookup to inspect capabilities. |
| Audit log blocking requests | If the audit log is full or inaccessible, OpenBao blocks all requests. Ensure log rotation and disk space. |
| Docker IPC_LOCK capability | Ensure cap_add: IPC_LOCK is set in docker-compose.yml. |
| High memory usage | Review lease counts: bao lease list. Revoke unused leases. Tune max_lease_ttl. |
Next Steps & Further Reading
- Dynamic Database Credentials: Generate short-lived database users with automatic revocation
- PKI Secrets Engine: Run your own Certificate Authority for internal TLS with ACME support
- Transit Encryption: Encrypt and decrypt application data without exposing keys
- OIDC/LDAP Authentication: Integrate with your existing identity provider
- Namespaces: Create isolated tenant environments for different teams or projects
- High Availability with Raft: Deploy a multi-node cluster across multiple RamNode VPS instances
- Auto-Unseal: Configure automatic unsealing with cloud KMS or PKCS#11 HSM
Official Resources
| Resource | URL |
|---|---|
| OpenBao Documentation | openbao.org/docs |
| OpenBao GitHub | github.com/openbao/openbao |
| Docker Hub Image | hub.docker.com/r/openbao/openbao |
| OpenBao API Reference | openbao.org/api-docs |
OpenBao Deployed Successfully!
Your open-source secrets management infrastructure is now running on RamNode. Store, manage, and audit access to your sensitive data with enterprise-grade security.
