Railbase
GPTClaude

Security hardening

Vault secrets, admin 2FA, the pinned vendor key, and limiting exposure.

Updated

Video guide —watch on YouTube ↗

A production Railbase has a handful of things worth getting right. None are exotic; they're the difference between a demo and a deployment you can trust.

Protect the vault secrets

Your data is only as safe as two things:

  • The vault password — supply it via RAILBASE_VAULT_PASSWORD_FILE (a file mode 0600, or a secrets-manager mount) rather than a plain env var or a shell history. In production, an empty password is refused.

    Caution

    A dev or scaffolded install ships a <data-dir>/.vault_password file containing the well-known development key — Railbase auto-discovers it (password source #4) and will unlock with it even under RAILBASE_PROD. Delete or replace it before going live, or the dev key still opens your vault. (Also remove runtime.dev: true from railbase.yaml if present.)

  • The master key (pb_data/.secret) — a 32-byte key created on a non-production first run (or by railbase init). Guard it and back it up separately from the vault file. In production a missing .secret is a hard error, not a silent regeneration — losing it means field-encrypted data becomes undecryptable, and leaking it undermines encryption at rest.
export RAILBASE_PROD=true
export RAILBASE_VAULT_PASSWORD_FILE=/run/secrets/railbase-vault
export RAILBASE_ENCRYPT_STORAGE=true

The Vault file is encrypted; uploaded file blobs use the filesystem storage driver and are encrypted at rest only when RAILBASE_ENCRYPT_STORAGE=true is enabled. Turn it on before production writes so new uploads are encrypted from the start.

Admin accounts

  • The first administrator is seeded explicitly with railbase admin bootstrap <email> (a first-run-only command that refuses once any admin exists) — there's no default account and no default password. Add admins routinely through the invite flow (admin UI → Users & access → Admins & roles → Invite, or POST /api/_admin/admins/invite), not the CLI.
  • Enroll two-factor authentication from the admin's account settings (it's self-service, not forced). Keep the recovery codes you're shown somewhere safe — once enrolled, sign-in requires the 6-digit code.
  • Reset a password from the CLI if needed: railbase admin reset-password <email>.

Limit what's exposed

Admin and lifecycle surfaces are powerful and should not be open to the world:

  • /_/ — the admin console, including Marketplace at /_/marketplace.
  • /api/_admin/* — admin-console APIs.
  • /_pm/* — plugin-manager and marketplace proxy endpoints (on by default; set RAILBASE_PLUGIN_MANAGER=0 to disable). Destructive lifecycle actions require an admin session, but the surface is still worth restricting.

Options, in rough order of preference:

  • Put the admin, admin API, and plugin-manager endpoints behind your network boundary (VPN / private network), or restrict them at the reverse proxy (IP allow-list, mTLS, or proxy auth).
  • Use RAILBASE_ALLOW_IPS / RAILBASE_DENY_IPS (CIDR lists) to filter at the app, and set RAILBASE_TRUSTED_PROXIES so those filters see real client IPs. Note the IP filter is a global middleware — it applies to every request (the public site and /api/* included), not just the admin surfaces, so an allow-list locks down the whole instance. The same knobs exist as persisted settings (security.allow_ips, …), which take precedence over the env vars.
  • Rate-limit with RAILBASE_RATE_LIMIT_PER_IP / _PER_USER / _PER_TENANT, and constrain browser origins with RAILBASE_CORS_ALLOWED_ORIGINS.

Caution

Don't toggle RAILBASE_PLUGIN_MANAGER=0 "during normal operation." Disabling the plugin manager also stops the in-core license-enforcement heartbeat for already-installed plugins — leave it on wherever licensed plugins run, and gate the /_pm/* surface at the network/proxy instead.

Tip

The admin ships a Security-audit panel (backed by GET /api/_admin/security-audit) that checks your boot/config posture — vault password source, prod mode, storage encryption, exposed surfaces — and flags what's risky. Review it after any config change.

The plugin trust anchor

Plugins only run if their signature verifies against the pinned vendor public key (see How plugins work). That pin is what makes marketplace-only acquisition safe — plugins ship as signed, encrypted JS+schema bundles, and there's no path to run an unsigned or unverified bundle. Don't disable verification or repoint the pin at an untrusted key.

Transport and operations

  • Always terminate TLS at your reverse proxy; never serve the admin over plain HTTP. See Deployment.
  • Ship logs as JSON (RAILBASE_LOG_FORMAT=json) to your log pipeline, and keep an eye on the audit log — Railbase maintains a tamper-evident, hash-chained audit trail.
  • Snapshot before risky changes and keep a copy off-box — Backups & restore.
Was this page helpful?Thanks for your feedback!