How to Use OpenBao: The Beginner's Guide (Init, Unseal, First Secret, First Policy, Dynamic Secrets)

CodexFuse Team · 2026-11-01T00:10:00.000Z · 18 min read

What is OpenBao, exactly?

OpenBao is an open-source secrets manager: one audited place to keep API keys, database passwords, TLS certificates, and encryption keys, and to hand them to applications over an HTTP API instead of through .env files and shared password managers. This guide shows you exactly how to use OpenBao, from a blank machine to a working secrets server — it is the OpenBao tutorial for beginners who want the real production flow, not just the toy dev server. It is the community fork of HashiCorp Vault — taken from Vault 1.14.0, the last release under the Mozilla Public License 2.0 before HashiCorp moved Vault to the Business Source License in August 2023 — and it has been developed under the Linux Foundation ever since, making it the open source Vault alternative with a future. The command-line tool is called bao, its environment variables start with BAO_, and the command surface is close enough to Vault's that most Vault muscle memory transfers directly.

If you can run containers, start with our Docker beginner guide — you will use it in the install section below. If you need somewhere to host the server, our guide on what is VPS hosting covers the basics.

Your 10-minute path through this OpenBao tutorial

Here is the complete arc this OpenBao for beginners guide walks you through, first install to working:

  1. Start a throwaway dev server and log in with a root token.
  2. Store and read your first secret with the KV engine (bao kv).
  3. Install the real binary and write a production config with Raft storage.
  4. Run bao operator init and understand why the output shows once.
  5. Perform the unseal ceremony and learn why a restarted server is a sealed server.
  6. Write your first least-privilege policy with bao policy write.
  7. Issue a token and pick the right auth method for machines.
  8. Learn the dynamic-secrets lesson: credentials that expire on their own.
  9. Set up backups and auto-unseal so a reboot stops being an emergency.
  10. Walk away knowing which lane OpenBao sits in — and which ones it does not.

OpenBao vs HashiCorp Vault: the fork story in 60 seconds

The fork story is the reason OpenBao exists, and it takes one paragraph to tell. HashiCorp relicensed Vault under the Business Source License in August 2023. The community forked the last MPL-2.0 release — Vault 1.14.0 — under the Linux Foundation, and that fork became OpenBao. This OpenBao vs Vault comparison stays honest: it shipped its first GA release, 2.0.0, in July 2024, moved from LF Edge to the OpenSSF as a sandbox project in June 2025, and released v2.7.2 on 26 October 2026, with roughly 8,800 GitHub stars and an MPL-2.0 license — all verified against the GitHub API at write time. The practical differences are smaller than the license talk suggests.

For beginners the practical differences are smaller than the license talk suggests. This table states the honest version:

QuestionOpenBaoHashiCorp Vault (current)
LicenseMPL-2.0, open sourceBusiness Source License (BSL)
GovernanceLinux Foundation, OpenSSF sandboxHashiCorp
CLIbao (a vault symlink ships in the Docker image)vault
Env varsBAO_ADDR, BAO_TOKENVAULT_ADDR, VAULT_TOKEN
Command surfaceNear-identical to Vault's — init, unseal, kv, policy, authThe original it mirrors
Enterprise featuresNot present — the fork starts from the 1.14 OSS treeBundled in the commercial builds
Standby-node local readsIn the OSS tree since 2.5.0Previously Enterprise-only

The one warning that matters: the commands mirror each other, but do not assume a Vault Enterprise feature you read about is present in OpenBao. It starts from the open-source tree and stays there.

How to install OpenBao

OpenBao publishes .deb, .rpm, and static archives on its GitHub releases page for every version, and official container images on Docker Hub, quay.io, and ghcr.io. The images are Alpine-based, run as a non-root openbao user, and the binaries are signed with GPG and Cosign — verify the signature before you trust the download. Every OpenBao install in this guide targets v2.7.2, the current release at write time.

On Debian or Ubuntu, the package route at write time (v2.7.2) looks like this:

BAO_VERSION=2.7.2
curl -sSLO "https://github.com/openbao/openbao/releases/download/v${BAO_VERSION}/openbao_${BAO_VERSION}_linux_amd64.deb"
sudo dpkg -i openbao_${BAO_VERSION}_linux_amd64.deb
bao version

The .deb creates an openbao system user and puts the config at /etc/openbao/openbao.hcl. If you install from the static archive instead, create the user and the data directory yourself.

The container route is one line, and it is the fastest way to get a known-good copy:

docker pull docker.io/openbao/openbao:2.7.2
docker run --rm -p 8200:8200 openbao/openbao:2.7.2 status

Pin a version tag rather than latest — pinning is the first grown-up habit this guide teaches, and it costs nothing.

How to run your first OpenBao server in 30 seconds

The dev server is the fastest way to learn the shape of OpenBao, and the official docs draw a hard line around it: it is insecure, it keeps everything in memory, and it must never protect real secrets or run in production. Practice only.

bao server -dev -dev-root-token-id="example-tutorial-token"

That single command boots an initialized, unsealed server listening on HTTP port 8200 with a root token you chose yourself. Point the CLI at it and log in:

export BAO_ADDR=http://127.0.0.1:8200/
bao login

Type the root token when prompted. The web UI — yes, there is one — is already live at http://127.0.0.1:8200. In a container the equivalent is docker run --rm -p 8200:8200 openbao/openbao:2.7.2, which the Docker image docs describe as the same thing: a bootstrapped, initialized, unsealed dev instance. Kill the process and it is gone; that is the point of practice.

How to write and read your first secret with bao kv

Secrets in OpenBao are documents — maps of keys and values — stored in secrets engines. The OpenBao KV engine is the simplest one, and the dev server ships a KV mount at secret/. The official developer quick start asks you to make sure that mount runs version 2, which adds versioning so you can roll back a secret:

bao kv enable-versioning secret/

Now store your first secret and read it back. The CLI form is the one you will use every day:

bao kv put secret/apps/billing db_password="changeme-001" api_key="demo-key-9"
bao kv get -mount=secret -field=db_password secret/apps/billing

The second command prints just the field value. That pair — write a document, fetch one field — is the whole KV mental model. One path rule worth tattooing on your hand: KV v2's API inserts a data/ segment under the hood, so the policy you write later will address secret/data/apps/billing, not secret/apps/billing. Forgetting the data/ segment is the most common reason a first policy silently matches nothing.

How to set up a production server: TLS, Raft, and the config file

A production OpenBao server needs three things in its config: a TLS listener, a storage backend, and its own addresses. The storage backend most beginners should choose is integrated Raft — it is the default in the 2.x line, it needs no external database, and it enables high availability when you later add nodes. A minimal config reads:

ui        = true
api_addr  = "https://bao.example.com:8200"

storage "raft" {
  path    = "/opt/openbao/data"
  node_id = "bao1"
}

listener "tcp" {
  address       = "0.0.0.0:8200"
  tls_cert_file = "/etc/openbao/tls/bao.crt"
  tls_key_file  = "/etc/openbao/tls/bao.key"
}

The UI flag turns on the web console at port 8200, and api_addr is the address the cluster advertises to clients. Run it as a systemd service under the unprivileged openbao user, lock the data directory to that user, and let a firewall or reverse proxy decide who reaches 8200. Two vCPUs and 2 GB of RAM comfortably serve a handful of applications on a single node — OpenBao's memory tracks active leases and tokens rather than stored secrets, so it stays small.

Plan for HA before you need it: Raft wants an odd node count — 3, 5, or 7 — for a stable quorum, and the cluster address (:8201) is how the nodes gossip.

How to initialize OpenBao: the unseal ceremony

Initialization prepares the storage backend to receive data and splits the root key into unseal key shares using Shamir's Secret Sharing. The OpenBao init step has one default you should memorize: five shares with a threshold of three, tunable with flags:

bao operator init -key-shares=5 -key-threshold=3

The output prints the five unseal keys and the initial root token — once, and only once. Record both at that moment. If you lose the shares, nothing can decrypt the storage, and no support ticket fixes that. Store them offline, split across custodians, and never commit them anywhere. The init output is the #1 beginner disaster in the OpenBao world, and now you know why: it is the only copy.

Initialization leaves the server sealed. Sealing is the core concept of this whole system, and it works in layers: your data is encrypted by keys in a keyring, the keyring by a root key, and the root key by an unseal key — and OpenBao holds the root key in memory only. So every restart is a sealing event. After a reboot the server can read its storage but cannot decrypt it until somebody supplies the threshold of shares:

bao operator unseal   # enter key 1 when prompted
bao operator unseal   # enter key 2 when prompted
bao operator unseal   # enter key 3 when prompted — sealed flips to false

Check the result with bao status, which prints Seal Type: shamir, Initialized: true, Sealed: false, and the share counts. A kernel update or an out-of-memory kill therefore ends with a sealed server and applications that cannot log in — a sealed secrets manager is an outage, not a warning. Budget for the unseal step in every runbook, or read the auto-unseal section below and automate it properly.

How to write your first OpenBao policy

Policies are path-based access control lists: rulesets that define which API paths a token can touch. Nothing in OpenBao should use the root token past setup — the root token is for the ceremony, policies are for the work. Write a policy file that grants read on exactly one path prefix and nothing else:

# billing-read.hcl
path "secret/data/apps/billing/*" {
  capabilities = ["read"]
}

Load it and prove the nothing-else half by minting a token bound to it:

bao policy write billing-read billing-read.hcl
bao token create -policy=billing-read -ttl=8h

That token can read your billing secrets for eight hours and cannot list the billing root, cannot read the payments secrets, and cannot write anything. The discipline is the feature: every application gets exactly the paths it needs, with a short TTL, and you can revoke the token — or the policy — the moment a machine is decommissioned. In production, rotate the root token right after this step so the ceremony credentials stop existing.

How to issue tokens and log machines in: auth methods

Humans log in; machines should authenticate. OpenBao supports many auth methods, and for beginners the two that matter are token (what you just did) and AppRole (what your services should do). AppRole hands an application a role_id — a semi-public identifier — plus a secret_id that is delivered wrapped, so the application unwraps it itself and renews its own token before expiry. The application fetches its secrets at boot rather than reading them from a file baked into the image.

The rule that never bends: never bake a static token into a container image, a CI config, or a repo. Tokens belong in the secret store, not in the thing that reads the store. If your team already runs single sign-on, pair OpenBao's OIDC/JWT auth with your identity provider rather than inventing a second credential system — our Authentik beginner guide covers the self-hosted IdP half of that setup. The Kubernetes auth method exists for clusters, and the agent pattern lets applications pick up secrets without changing application code.

The dynamic-secrets lesson: stop storing passwords at all

Static secrets have a shelf-life problem: a password written into OpenBao is still the same password next month, and rotating it means finding every copy. OpenBao dynamic secrets invert the model — the credential does not exist until someone asks for it. When an authorized client reads database/creds/my-role, OpenBao connects to PostgreSQL with its own privileged account, creates a brand-new login with a random password and an expiry, and returns the username, password, and a lease. Revoke the lease or the token that requested it, and the login disappears from the database.

The official PostgreSQL plugin flow is four commands:

bao secrets enable database

bao write database/config/my-postgresql-database \
  plugin_name="postgresql-database-plugin" \
  allowed_roles="my-role" \
  connection_url="postgresql://{{username}}:{{password}}@localhost:5432/mydb"

bao write database/roles/my-role \
  db_name="my-postgresql-database" \
  creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
  default_ttl="1h" \
  max_ttl="24h"

bao read database/creds/my-role

The response carries a lease_id like database/creds/my-role/2f6a614c-…, a lease_duration of one hour, lease_renewable: true, and a username OpenBao invents — something like v-openbaouse-my-role-x — with a random password. After one hour OpenBao automatically revokes them from the database. Your application held a credential only for the time it needed it, and rotation became automatic.

This table is the decision you will make for every secret you own:

Static secret (KV)Dynamic secret (database engine)
What is storedThe password itself, versionedNothing — minted per request
Credential lifetimeUntil you rotate it by handTTL-bounded, e.g. 1h, auto-revoked
Blast radius of a leakEvery copy, until rotation finishesOne lease, already expiring
Best forAPI keys, certificates, tokens with no issuer APIDatabase logins, cloud credentials
Beginner costLow — bao kv put and doneMedium — needs the engine config and a privileged DB role

Start with KV for everything; graduate each database to dynamic credentials once the static flow is boring. Static roles — a 1-to-1 mapping of an OpenBao role to a fixed database username — exist for databases that cannot mint logins, but never use them for root database credentials.

Backups and auto-unseal: the two habits that save you

A backup of encrypted storage that you cannot decrypt is a backup of nothing. Snapshot the Raft data on a schedule and treat the output like ciphertext it is:

bao operator raft snapshot save /var/backups/openbao/bao-$(date +%F).snap
sha256sum /var/backups/openbao/bao-*.snap

Then prove the restore works — a restore you have never tested is a hope, not a plan. Note the pairing the docs community keeps repeating: snapshots travel with the unseal shares. Copy the snapshot to object storage while the shares sit nowhere recoverable, and you have archived an unreadable blob.

The second habit is auto-unseal, and it has one ordering rule that bites beginners: configure the seal stanza in the server config before the first bao operator init. With a seal like pkcs11, a static key, or a cloud KMS, a restarted node unseals itself and rejoins the cluster without a human pasting shares at 3 a.m. Note what changes: init then produces recovery keys instead of unseal keys — the recovery keys are for emergency operations only, and the cluster's unsealing happens automatically through the configured seal. Auto-unseal moves the trust to wherever the seal key lives, so guard that key with the same paranoia you once reserved for the shares.

OpenBao vs Infisical vs the file-based crowd: which lane are you in?

OpenBao is one lane in a crowded field, and picking the lane consciously beats collecting tools. Infisical is the secrets-platform sibling: a SaaS-flavored platform with its own server option, and the right choice when your team wants dashboards, integrations, and less ceremony — read our Infisical beginner guide if that sounds like you. Below both sit the file-based approaches — SOPS with age, systemd credentials, Docker secrets — which are files, not services: encrypted at rest, decrypted by something already running, with no API, no leases, and no audit log.

The honest accounting: OpenBao and Infisical are services you now have to keep alive — an API, a store, TLS, a login step, and a process. If your secrets fit in a handful of files and one machine, a file-based approach is cheaper and an OpenBao nobody unseals properly is worse than a mode-600 env file, because it adds a moving part and a backup you will get wrong. Choose OpenBao when you need the service properties: dynamic credentials, fine-grained policies per machine, and an audit trail of every access for compliance.

7 beginner mistakes that break OpenBao deployments

MistakeWhat happensThe fix
Running the dev server with real secretsIn-memory, unencrypted-on-disk by design, insecure defaultsDev mode is for practice only — build a Raft config for anything real
Losing the init outputUnseal keys and root token are shown once; storage becomes undecryptableRecord offline, split across custodians, before closing the terminal
Writing policies without the KV v2 data/ segmentPolicy matches nothing; reads fail with permission deniedAddress secret/data/apps/x, never secret/apps/x
Letting apps use the root tokenFull access to all data and functionality for every serviceLeast-privilege policies + short-TTL tokens or AppRole
Baking tokens into images or reposEvery image layer and git clone carries a live credentialAppRole/JWT auth — machines authenticate, never hardcode
Backing up snapshots without the unseal sharesA restore needs shares you never stored — the backup is unreadableStore shares and snapshots in separate, equally guarded places
No unseal runbook for restartsKernel update → sealed server → every app fails to startAuto-unseal seal stanza, or a documented on-call unseal ceremony

What to build next

You now own the full beginner arc: the fork's story, a practice server, the init and unseal ceremony, a first policy and token, and the dynamic-secrets mindset that makes static passwords optional. The natural next projects, in order, are: enable the file audit device so every request is logged; move one real database to the database engine with a one-hour TTL; replace one baked-in token with AppRole; and set up the snapshot schedule plus a restore drill. Do those four and you are no longer a beginner — you are the person the team pages when the seal needs attention.

Sources

  • openbao.org — Developer quick start (dev server flags, BAO_ADDR/BAO_TOKEN, KV v2 enable-versioning, bao kv get -mount=secret -field=password)
  • openbao.org — PostgreSQL database secrets engine docs (bao secrets enable database, database/config, database/roles, database/creds response format)
  • openbao.org — Database secrets engine docs (dynamic roles and leases, static roles)
  • GitHub openbao/openbao releases API — v2.7.2 released 2026-10-26, ~8,800 stars, MPL-2.0, created 2023-11-09
  • GitHub openbao/openbao Dockerfile — official images on Docker Hub/quay.io/ghcr.io, Alpine, dumb-init entrypoint, non-root openbao user, GPG + Cosign signed binaries
  • ssdnodes.com — Self-hosted secrets managers compared (v2.7.2 latest as checked 27 Oct 2026; MPL-2.0; Vault BSL 2023 fork; init 5/3 defaults; restarted server = sealed server; Raft config)
  • safeguard.sh — Homelab Secrets Server (GA 2.0.0 July 2024; LF Edge to OpenSSF sandbox June 2025; 2.7.1 Oct 2026; seal layers; snapshot save/restore; official images)
  • stackharbor.com — Deploy OpenBao as a single-node secrets server with AppRole authentication (2.6.1; KV v2 policy path; AppRole role_id/secret_id, self-renewing tokens)
  • CNCF blog — Running OpenBao on Kubernetes with a CloudNativePG PostgreSQL backend (init once on the first pod; unseal each pod; Seal Type shamir; readiness = unseal status)
  • docs.osc.live — OpenBao Deployment Guideline (auto-unseal seal stanza before first init; pkcs11; odd replica counts for Raft quorum)
  • admin-it.io — OpenBao Secrets Management (auth → token → policy workflow; path-based ACL policies; dynamic secrets; audit logging)
  • lalatenduswain.medium.com — OpenBao vs HashiCorp Vault (fork of Vault 1.14.0 last MPL-2.0; standby-node local reads since 2.5.0)

Frequently Asked Questions

Is OpenBao a drop-in replacement for HashiCorp Vault?

Mostly, for the open-source command surface: the CLI is bao instead of vault, environment variables are BAO_*, and init, unseal, KV, policies, and auth methods work the same way. It is not a drop-in for Vault Enterprise features — those were never in the fork's ancestry, so verify each one instead of assuming it.

What happens if I lose my OpenBao unseal keys?

You lose your data. The keys are printed once by bao operator init, and the root key they reconstruct lives only in the server's memory. Without the threshold of shares, the storage cannot be decrypted by anyone — including you. Store the shares offline and split across custodians from the first minute.

Do I need a separate database to run OpenBao?

No. Integrated Raft storage is the default in the 2.x line and needs no external database, which is the right choice for beginners and single-node setups. External backends like PostgreSQL exist for specific architectures, but add them only when you have a reason, not by default.

Can applications fetch secrets without storing a token?

Yes — that is what auth methods are for. AppRole lets a machine authenticate with a role_id and a wrapped secret_id, and OpenBao supports JWT/OIDC and Kubernetes auth too. The rule is that machines authenticate; only humans and automation bootstraps ever handle raw tokens, and those are short-lived.

Should beginners start with KV or dynamic secrets?

KV. Store static secrets with bao kv put until the flow is boring, then graduate each database to the database engine's dynamic credentials with a short TTL. Dynamic secrets are the more powerful pattern, but they need a privileged database role and engine config — earn the complexity after the basics are solid.

Featured on Twelve Tools Launch Llama Tools Launch your MCP