Skip to content

Environment

The server is configured through .env. Only one variable is strictly required.

Required

Variable Purpose
JWT_SECRET Signs session tokens. Generate with openssl rand -hex 32.

The bundled compose.yml provides a Postgres database and sensible defaults for everything else. You can override any of them in .env — see below.

Self-hosted mode is automatic

The server runs in self-hosted mode whenever LEMONSQUEEZY_API_KEY is unset (which is the default). In that mode:

  • Every paid feature is unlocked for every user — teams, team vaults, terminal sharing, audit logs.
  • No 14-day trial countdown on new accounts.
  • All /v1/billing/* endpoints return 503 BILLING_DISABLED.
  • The Lemon Squeezy webhook is disabled.
  • GET /v1/meta reports {"self_hosted": true, "billing_enabled": false} so the admin dashboard (if you run it) can hide its billing widgets.

There is no SELF_HOSTED flag to set. The absence of Lemon Squeezy configuration is the signal.

Optional

Variable Default Purpose
DATABASE_URL bundled Postgres Postgres connection string.
POSTGRES_IMAGE_TAG 16-alpine Tag of the bundled postgres image. Changing the major version does not upgrade an existing data volume — Postgres refuses to start on it.
HOST_PORT 14372 Host port to expose.
CORS_ORIGINS allow all Comma-separated allow-list. Set to your domain in public deployments.
TRUSTED_PROXIES unset Comma-separated IPs or CIDRs of your reverse proxy. Required for rate limiting to see real client IPs behind a proxy — a container proxy needs its network's subnet, e.g. 172.22.0.0/16, not a single address. The older single-address name TRUSTED_PROXY_IP still works.
SYNC_BLOB_RETENTION_DAYS 90 Days to keep a sync blob once a newer one from the same account supersedes it. The latest blob is never deleted.
TEAM_OBJECTS_MIN_CLIENT_VERSION unset Minimum desktop version allowed to write team vault objects, e.g. 0.33.0. Older clients get 426 Upgrade Required on writes; reads are never gated. Set it only once your users have updated.
ADMIN_SECRET unset Required only if you run the optional admin dashboard. Must match the same value in the dashboard's .env.

Email

Variable Default Purpose
RESEND_API_KEY unset Enables email verification + team invitation emails via Resend. Without it, those emails silently no-op; accounts still work.
RESEND_FROM Voltius <noreply@voltius.app> Sender address. Set this if you set RESEND_API_KEY: Resend only sends from a domain you have verified, so the default fails for every self-host and no email arrives.
VOLTIUS_APP_URL https://app.voltius.app Base URL of the links in verification and invitation emails. Point it at your deployment, or those links lead to the hosted service.
VOLTIUS_MARKETING_URL https://voltius.app Website link in the email footer.
RESEND_LOGO_URL https://voltius.app/logo.png Logo shown in email headers.

Access

Both default to true. Turn them off to run a closed instance that is still reachable from the Internet.

Variable Default Purpose
REGISTRATION_ENABLED true false refuses new accounts with 403 {"error": "REGISTRATION_DISABLED"}. Existing accounts keep logging in and syncing. To add someone later, turn it on, let them register, and turn it off again.
TEAM_INVITES_ENABLED true false refuses new team invitations, direct adds and join links with 403 {"error": "TEAM_INVITES_DISABLED"}. Invitations and links already issued stay usable until they expire or are revoked; listing, accepting, declining and revoking keep working.

Any other value than true/false (or 1/0, yes/no, on/off) stops the server at startup rather than guessing. GET /v1/meta reports both as registration_enabled and team_invites_enabled.

Rate limits

The defaults are fine for most deployments. Limits keyed per IP depend on TRUSTED_PROXIES being right behind a proxy.

Variable Default Purpose
AUTH_RATE_LIMIT 10 Login, refresh and challenge requests per minute per IP.
REGISTER_RATE_LIMIT 20 New registrations per day per IP.
WAITLIST_RATE_LIMIT 10 Waitlist submissions per hour per IP.
SYNC_RATE_LIMIT 10000 Authenticated API requests per hour per user (sync, teams, presence, sessions).
INVITE_RATE_LIMIT 20 Team invitations per hour per user.
USER_SEARCH_RATE_LIMIT 60 User directory searches per minute per user.
STRANGER_KNOCK_RATE_LIMIT 20 Terminal-sharing invites to people outside your teams, per hour per sender.

Production database & backups

The bundled Postgres is convenient but has no backup story — if its volume is lost, so is your data. For a durable setup, point DATABASE_URL at a Postgres you run yourself. server/compose.db.yml is the stack Voltius' own production database runs on: pinned Postgres, WAL-G continuous archiving and base backups to S3-compatible storage, pg_dump rotation mirrored off-box, a freshness watchdog, and an optional Supabase Studio profile for browsing tables. Configure it from .env.db.example; the restore runbook covers point-in-time recovery.

Migrations

Run automatically on every server start. No manual step.

Full reference

The complete annotated file lives at server/.env.example.