Files

OpenBao

Automated installation and update script for an OpenBao secrets-manager server running inside an Alpine LXC on Proxmox.

Features

Single script, automatic mode selection:

Context Action
From Proxmox host, no existing OpenBao container Detects newest Alpine template, creates LXC, installs bao + OpenRC service
From Proxmox host, OpenBao container already present Reuses the existing LXC, refreshes packages, upgrades bao to the latest release
From inside an LXC, no bao binary Installs OpenBao from scratch
From inside an LXC, bao already present Updates the binary only (no config / data changes)

The container is identified by hostname and the openbao tag, so it is re-found across reruns even if the CTID was auto-allocated the first time.

Requirements

  • Proxmox VE host with pveam, pct, pvesh, jq available
  • Internet access from both the host (template download) and the LXC (binary download)
  • Script must be run as root on the Proxmox host (enforced; the Web UI shell qualifies)

Usage

Full install (from Proxmox shell)

bash -c "$(curl -fsSL https://gitea.arnodo.fr/Damien/infra-scripts/raw/branch/main/openbao/install.sh)"

Re-running the exact same command later upgrades packages inside the LXC and brings the bao binary to the latest release, without touching the config or the raft data directory.

Customisation

Every parameter is exposed as an environment variable:

Variable Default Description
CTID auto Container ID (auto-allocated via pvesh get /cluster/nextid)
OPENBAO_HOSTNAME openbao LXC hostname (also used as raft node_id)
TEMPLATE auto-detected Alpine template; auto-detected from pveam available
STORAGE local-lvm Proxmox storage for the LXC root disk
TEMPLATE_STORAGE local Storage where Alpine templates live
CORES 2 vCPU cores
RAM 1024 RAM in MiB
DISK 8 Root disk size in GB
BRIDGE vmbr0 Network bridge
LXC_TAG openbao Stable tag used to re-discover the container
OPENBAO_VERSION latest Pin a specific release (e.g. v2.0.3) or latest
OPENBAO_LISTEN_ADDR 127.0.0.1:8200 TCP listener address. Loopback by default — Tailscale fronts it.
OPENBAO_API_ADDR http://<listen> Public API URL (used for UI / OIDC redirects). Set to https://<host>.<tailnet>.ts.net once known.
TS_AUTHKEY (unset) Pre-auth key (generate at https://login.tailscale.com/admin/settings/keys). If unset, finish tailscale up manually inside the LXC.
CTID=210 OPENBAO_HOSTNAME=vault CORES=4 RAM=2048 \
  bash -c "$(curl -fsSL https://gitea.arnodo.fr/Damien/infra-scripts/raw/branch/main/openbao/install.sh)"

First-time initialisation

OpenBao starts sealed. Once the LXC is up:

pct enter <CTID>
export VAULT_ADDR=http://127.0.0.1:8200
bao operator init        # save the unseal keys + root token somewhere safe
bao operator unseal      # repeat with each key share until unsealed

Tailscale reverse proxy

The listener binds to 127.0.0.1:8200 only — Tailscale (running inside the same LXC) acts as the reverse proxy and terminates TLS via tailnet certificates.

If TS_AUTHKEY was supplied at install time, the script runs tailscale up and tailscale serve --bg --https=443 http://127.0.0.1:8200 automatically. OpenBao then becomes reachable at https://<hostname>.<tailnet>.ts.net.

Otherwise, finish setup manually inside the LXC:

pct enter <CTID>
tailscale up --ssh
tailscale serve --bg --https=443 http://127.0.0.1:8200
tailscale status        # prints the tailnet FQDN

Then point OPENBAO_API_ADDR at that FQDN and rerun the script so the UI / OIDC redirects use it:

OPENBAO_API_ADDR=https://openbao.<tailnet>.ts.net \
  bash -c "$(curl -fsSL https://gitea.arnodo.fr/Damien/infra-scripts/raw/branch/feat/lxc-OpenBao/openbao/install.sh)"

HTTPS in tailscale serve requires HTTPS to be enabled on your tailnet (Admin console → DNS → HTTPS Certificates).

Update (from inside the LXC)

curl -fsSL https://gitea.arnodo.fr/Damien/infra-scripts/raw/branch/feat/lxc-OpenBao/openbao/install.sh | bash

The script auto-detects the presence of /usr/local/bin/bao and switches to update mode. The OpenRC service is stopped, the binary is swapped (the old one is kept as bao.bak.<ts>), then the service is restarted.

Architecture

  • OS: latest Alpine LXC template (auto-detected), unprivileged, nesting=1, /dev/net/tun passthrough for Tailscale
  • Binary: official bao release from github.com/openbao/openbao, installed in /usr/local/bin
  • Service: OpenRC, runs as user openbao, logs to /var/log/openbao.log (rotated daily, 7 days retained)
  • Network: listener bound to 127.0.0.1:8200; Tailscale runs in the LXC and acts as the reverse proxy (tailscale serve --https=443)
  • Config: /etc/openbao/config.hcl — raft storage, TLS disabled on the listener (Tailscale terminates TLS), disable_mlock = true for unprivileged LXC
  • Data: /var/lib/openbao/data (raft)
  • Version tracking: /opt/openbao_version.txt records the currently installed tag for idempotent reruns