self-hosting
Install with Docker Compose
Connected install: configure .env, build and start the stack, verify health, and put a TLS reverse proxy in front.
Updated Jun 23, 2026
This is the connected install — a host with Docker and outbound network access. For an install with no network, see Air-gapped install.
Prerequisites
- Docker Engine with the Compose plugin (
docker compose). - The VaultTerm repository on the host (the
appimage is built locally on a connected install).
Configure .env
All files live in deploy/onprem/. Copy the template and edit it; docker compose reads .env
automatically.
cd deploy/onprem
cp .env.example .env
At minimum, set these before first boot. Generate each secret with openssl rand -hex 32.
| Variable | What it is |
|---|---|
POSTGRES_PASSWORD | password for the bundled Postgres |
JWT_SECRET | session signing key, at least 32 bytes; boot fails under production with a weak or default value |
DEV_MASTER_KEY | 32-byte hex master key for the local key provider; wraps every stored credential |
APP_BASE_URL | the public HTTPS URL where users reach the portal, including any base path |
RP_ID / RP_ORIGIN | WebAuthn registrable domain (host only) and full origin; needs HTTPS or localhost |
POSTGRES_PASSWORD=<strong-db-password>
JWT_SECRET=<openssl rand -hex 32>
DEV_MASTER_KEY=<openssl rand -hex 32>
APP_BASE_URL=https://vault.example.com
RP_ID=vault.example.com
RP_ORIGIN=https://vault.example.com
DEV_MASTER_KEY is the one value you cannot regenerate: losing it makes vault contents unrecoverable.
Back it up out-of-band. See Core and database config for the database and
URL variables, and Backups and recovery for the master key.
Start the stack
docker compose up -d --build
docker compose logs -f app # watch migrations apply, then "starting VaultTerm"
curl -fsS http://localhost:4000/health
The app container applies database migrations on boot, then serves the API and web portal on :4000.
A successful /health response means the stack is up.
Put a reverse proxy in front
The stack serves plain HTTP on :4000. Terminate TLS in a reverse proxy — WebAuthn and secure
cookies require HTTPS, and localhost is the only exempt origin. A ready nginx sample ships in the
bundle at deploy/onprem/reverse-proxy.example.conf, configured for post-quantum hybrid TLS key
exchange (X25519MLKEM768), which protects the captured session against later quantum decryption and
falls back to classical key exchange for clients that don’t offer the hybrid group.
server {
listen 443 ssl;
http2 on;
server_name vault.example.com;
ssl_certificate /etc/ssl/vaultterm/fullchain.pem;
ssl_certificate_key /etc/ssl/vaultterm/privkey.pem;
ssl_protocols TLSv1.3 TLSv1.2;
ssl_ecdh_curve X25519MLKEM768:X25519:prime256v1;
location / {
proxy_pass http://127.0.0.1:4000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 1h;
}
}
The hybrid group requires nginx built against OpenSSL 3.5+; older OpenSSL silently serves classical-only key exchange. The WebSocket headers above are required for the interactive terminal, port-forwarding, and multiplayer sessions.
Keep the admin plane private
Proxy :4000 only. The admin/platform plane on :4100 binds to loopback by default and must stay off
the public internet — reach it over an SSH tunnel or a trusted private interface. Do not add a public
proxy location for it.
Next
- Licensing and activation — install the offline
.vtliclicense. - Backups and recovery — protect the master key and database.
- Upgrading — pull, rebuild, and let migrations run.