PORT=9000 JWT_SECRET="" POSTGRES_URL="postgres://postgres:password@localhost:5432/officer" MAIL_TRANSPORT="smtp://localhost:1025" PUBLIC_URL=http://localhost:9000 # Guards (CORS origin checks, rate limits, password-strength rules) are ON unless this is set to # "dev" or "development". Leave it unset or set it to "production" for a real deployment; only set # it to "dev" on a local machine you trust, since that disables all three. PUBLIC_BUILD_ENV=production DATA_PATH=/path/to/data OFFICER_ITEMS_DIR=/path/to/officer-items HOME_DIR=/home/user BROWSER_RELAY_PORT=18792 # ── Sidecars ──────────────────────────────────────────────────────────────────────────────────── # Each sidecar owns its upstream's credentials; the platform API is only a thin auth+forward proxy # and never sees them. An unset upstream URL is not fatal — the sidecar logs a warning at boot and # answers 503 until it is set, so you can run Officer with any subset of these configured. # Transmission (officer-transmission). TRANSMISSION_USER/PASS are only needed if the daemon has RPC # auth turned on; leave them empty otherwise, since Transmission rejects an empty Basic header. # TRANSMISSION_RPC_PATH defaults to /transmission/rpc and only needs setting behind a reverse proxy # that mounts the RPC endpoint somewhere else. TRANSMISSION_URL=http://127.0.0.1:9091 TRANSMISSION_USER= TRANSMISSION_PASS= # TRANSMISSION_RPC_PATH=/transmission/rpc # InvoiceShelf (officer-invoiceshelf). The token is a Sanctum personal access token — mint one with # POST /api/v1/auth/login {username: , password, device_name} and copy the `token` field. It has # full abilities and never expires, so treat it as a password. # INVOICESHELF_COMPANY_ID pins which company every request is scoped to. Leave it unset on a # single-company install and the sidecar resolves it once at boot and LOGS the choice — worth setting # explicitly if you have more than one, because InvoiceShelf does not error on a wrong company header, # it silently returns the other company's data. INVOICESHELF_URL=https://invoice.example.com INVOICESHELF_TOKEN="" # INVOICESHELF_COMPANY_ID=1 # slskd (officer-slskd). The key is injected as X-API-Key on every forwarded request. SLSKD_URL=http://127.0.0.1:5030 SLSKD_API_KEY="" # Vaultwarden (officer-vault). VAULT_STORE_KEY encrypts stored secrets at rest — any strong secret # of 16+ chars works, and CHANGING IT MAKES EXISTING STORED SECRETS UNREADABLE. VAULTWARDEN_URL=http://127.0.0.1:8222 VAULT_STORE_KEY="" # Anthropic proxy (officer-anthropic-proxy). Defaults to 5051; it holds the API credential, which # lives in the host env rather than here. # ANTHROPIC_PROXY_PORT=5051 # ReClip — the self-hosted yt-dlp service the download-media capability talks to. Defaults to # http://localhost:8899. # RECLIP_URL=http://localhost:8899 # ── Headscale (/api/vpn) ──────────────────────────────────────────────────────────────────────── # These drive the /api/vpn router, NOT the officer-headscale sidecar. The sidecar deliberately reads # neither, keeping its registered servers and their keys in Postgres so host env can never shadow # one. Set these only if you use /api/vpn. # HEADSCALE_URL=https://headscale.example.com # HEADSCALE_API_KEY="" # HEADSCALE_USER=officer # ── Bitcoin wallet (officer-wallet) ───────────────────────────────────────────────────────────── # Chain data source for the self-custodial on-chain wallet. Any Esplora-compatible API works — # mempool.space by default, or point it at your own node's esplora/electrs when you run one. # WALLET_ESPLORA_URL=https://mempool.space/api # WALLET_NETWORK=bitcoin # bitcoin | testnet | signet | regtest # # How long an unlocked wallet stays unlocked, in seconds. Default 900 (15 min). The root key is held # in the sidecar's memory for exactly this long after an unlock, then wiped. Shorter is safer. # WALLET_UNLOCK_TTL_SEC=900 # # NOTE: seed material is encrypted with VAULT_STORE_KEY (above) on top of the owner passphrase that # seals it. Both are required to spend. If you lose VAULT_STORE_KEY, every stored seed is # unrecoverable — back up the mnemonics separately, offline.