TLS and hosted deployment¶
Trimus's defaults target local, single-operator use: plain http://localhost,
optional encryption, insecure cookies. Running Trimus as a shared,
centrally-hosted service needs a stricter posture. This page covers the
TRIMUS_MODE=hosted switch, TLS termination, and the TRIMUS_PUBLIC_URL
contract.
Hosted mode (TRIMUS_MODE)¶
| Mode | Behavior |
|---|---|
local (default) |
Current permissive behavior. Encryption optional, HTTP OK, insecure cookies. Nothing changes for existing installs. |
hosted |
Enforces production-grade invariants at startup. The server refuses to boot (with an aggregated, actionable error) until they're met. |
In hosted mode, config.Load() fails fast unless:
TRIMUS_ENCRYPTION_KEYis set — refusing to run with plaintext secrets at rest. Generate withopenssl rand -base64 32. (Provider keys, OAuth tokens, and signed-trigger secrets are encrypted at rest via the KEK/DEK vault; see Secrets and encryption. Existing plaintext rows are migrated withtrimus-cli encrypt-providers.)TRIMUS_PUBLIC_URLishttps://…— browsers dropSecurecookies over plain HTTP and workers/webhooks must reach a stable HTTPS endpoint. Thehttp://localhostfallback is rejected.
When those pass, hosted mode also forces TRIMUS_SECURE_COOKIES=true.
Example failure:
TRIMUS_MODE=hosted: 2 invariant(s) not met:
- TRIMUS_ENCRYPTION_KEY is required (generate: `openssl rand -base64 32`) — refusing to run with plaintext secrets
- TRIMUS_PUBLIC_URL must be https:// (got "http://localhost:3100") — set a real HTTPS public URL or terminate TLS upstream
Test locally with TRIMUS_MODE=local, then flip to hosted when you deploy.
TLS¶
You have two options.
Option 1 — Terminate TLS at a reverse proxy (recommended)¶
Run Trimus on plain HTTP behind nginx, Caddy, or a cloud load balancer. This is the most common and flexible topology (centralised certs, HTTP/2, OCSP stapling, etc.).
When you do this, set TRIMUS_TRUSTED_PROXIES to the proxy's CIDR so
X-Forwarded-For is honoured (SEC-014), and make sure the proxy forwards
X-Forwarded-Proto: https so Trimus knows the original scheme.
nginx
server {
listen 443 ssl;
server_name trimus.example.com;
ssl_certificate /etc/letsencrypt/live/trimus.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/trimus.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3100;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Caddy
Cloud ALB / LB: terminate TLS at the LB, forward to the Trimus target group
on :3100, and wire the health check to /readyz (readiness) and /healthz
(liveness) — see Monitoring.
Option 2 — Built-in TLS¶
For simple single-node deployments without a separate proxy, point Trimus at a cert/key pair:
Both must be set together (one without the other is a boot error). When set,
the server listens with ListenAndServeTLS. Graceful shutdown works the same.
TRIMUS_PUBLIC_URL contract¶
TRIMUS_PUBLIC_URL is the externally-reachable base URL agents, workers,
webhooks, Slack/Telegram links, and A2A federation use to reach this server. It
must be stable and reachable from those clients.
- It is validated for shape at startup (must be
http(s)://host[:port]). - In hosted mode it must be
https://. - Changing it requires re-registering workers and updating integration configs.
- Set
TRIMUS_SELFTEST_PUBLIC_URL=trueto have the server background-probe<TRIMUS_PUBLIC_URL>/healthzafter boot and WARN if it's unreachable (a quick way to catch DNS/TLS/proxy misconfiguration). The probe never blocks startup.
Health endpoints (for load balancers)¶
| Path | Use |
|---|---|
/healthz, /healthz/live |
Liveness — always 200 if the process is up. |
/readyz, /healthz/ready |
Readiness — checks DB and dependencies. |
See Monitoring for details.
Worker co-location and proxies¶
When workers run on the same network as the server, add the server host to
TRIMUS_NO_PROXY (or NO_PROXY) so worker→server traffic stays direct while
LLM/API egress still routes through any configured proxy. See the proxy section
of Environment.