Secrets

Encrypted secrets that are injected into your deployments at runtime.

Secrets let you store sensitive values (API keys, database URLs, tokens) on the server. They’re encrypted at rest, never logged, and injected as environment variables when your container starts.

Managing secrets

# Create or update a secret
berth secret set STRIPE_KEY sk_live_abc123 --description "Stripe API key"

# List secrets (shows names and descriptions, never values)
berth secret list

# Delete a secret
berth secret delete STRIPE_KEY

The --description flag is optional but recommended — it helps you (and AI tools) understand what each secret is for without exposing the value.

Using secrets in deployments

Reference secrets by name when deploying:

# Single secret
berth deploy --secret STRIPE_KEY

# Multiple secrets
berth deploy --secret STRIPE_KEY --secret DATABASE_URL

# Combine with inline env vars
berth deploy --secret STRIPE_KEY --env NODE_ENV=production

Secrets are resolved at container creation time. Your app reads them like any other environment variable:

const stripe = require('stripe')(process.env.STRIPE_KEY)

If the same name appears in both --secret and --env, the explicit --env value takes precedence.

Secret rotation

When you update a secret that’s in use by running deployments, OpenBerth automatically restarts those deployments with the new value:

$ berth secret set STRIPE_KEY sk_live_new_value
  ✓ Secret updated
  ↻ Restarted: my-app, checkout-api

This is a runtime-only restart (~5 seconds) — no rebuild required. The container is recreated with the updated secret value.

Global secrets

Admins can create global secrets that are available to all users on the server:

# Create a global secret (admin only)
berth secret set SHARED_API_KEY abc123 --global

# Delete a global secret
berth secret delete SHARED_API_KEY --global

When a user has both a personal and global secret with the same name, the personal secret takes precedence.

How encryption works

Secrets use AES-256-GCM envelope encryption:

  1. A master key is auto-generated when the server first starts and saved in config.json
  2. Each secret gets its own random data encryption key (DEK)
  3. The DEK encrypts the secret value, then the master key encrypts the DEK
  4. Both encrypted values are stored in SQLite — the plaintext value is never persisted

Secret values are decrypted only at the moment a container is created, and injected as environment variables. They never appear in berth secret list, logs, or API responses.

MCP tools

AI tools can manage secrets through MCP:

Tool Description
berth_secret_set Create or update a secret
berth_secret_list List secret names and descriptions (never values)
berth_secret_delete Delete a secret

The berth_secret_list tool returns descriptions so AI tools can discover which secrets are available without seeing the values.