HTTPS and reverse proxy
Put Orchestrat behind Caddy on your own domain, with automatic HTTPS.
Orchestrat listens on plain HTTP on port 8801. That is fine on localhost. To reach it from other machines, or to connect a Git provider, which needs a public HTTPS URL for webhooks and sign-in callbacks, put it behind a reverse proxy that terminates TLS. Orchestrat doesn't bundle one; this page uses Caddy, which gets and renews certificates for you.
One port serves everything: the API under /api/v1, the realtime WebSocket the dashboard uses for live updates, and the dashboard itself. The proxy needs one site for Orchestrat, plus one for storage if you use the bundled SeaweedFS.
1. Point a domain at the server
Create DNS records pointing at the machine that runs Orchestrat, for example orchestrat.example.com, and s3.orchestrat.example.com for storage. Ports 80 and 443 must be reachable from the internet so Caddy can complete the certificate challenge.
2. Configure Caddy
With Caddy installed on the same host as Docker, proxy each site to its published port:
orchestrat.example.com {
reverse_proxy localhost:8801
}
s3.orchestrat.example.com {
reverse_proxy localhost:8333
}Leave out the second site if you don't use the bundled storage. Caddy forwards WebSocket connections and the original Host header without extra configuration.
If you run Caddy as another service in the same compose project instead, proxy to the service names, orchestrat:8801 and seaweedfs:8333.
3. Tell Orchestrat its public URLs
In .env, set the URL people and providers use, tell the server that one proxy sits in front of it, and set the address browsers upload attachments to:
ORCHESTRAT_PUBLIC_URL=https://orchestrat.example.com
ORCHESTRAT_TRUST_PROXY_HOPS=1
ORCHESTRAT_S3_PUBLIC_ENDPOINT=https://s3.orchestrat.example.comORCHESTRAT_TRUST_PROXY_HOPS=1 makes the server read each client's address from the X-Forwarded-For header Caddy adds. Without it, rate limits see every request as coming from the proxy.
Only Caddy should reach the plain HTTP ports. If Caddy runs on the same host, publish them on the loopback interface only:
ORCHESTRAT_PORT=127.0.0.1:8801
S3_PORT=127.0.0.1:8333Then apply the changes, with -f compose.yml -f compose.storage.yml if you use the bundled storage:
docker compose up -dWhat the public URL changes
ORCHESTRAT_PUBLIC_URL builds the setup link in the server log, Git provider callback, setup and webhook URLs, and avatar URLs. Avatars uploaded before you changed it keep the old address, so upload them again if that address is no longer reachable.
Invite links and CLI approval links don't depend on it: invite links use the address you opened the dashboard at, and the CLI uses the server URL you give it. After moving to HTTPS, reconnect agents against the new URL. Credentials are bound to the server URL, so setup asks you to approve the CLI again:
npx @orchestrat/cli setup --server https://orchestrat.example.comOn a new install, you can pass the URL to init instead of editing .env:
docker compose run --rm --no-deps -T orchestrat init https://orchestrat.example.com > .envStorage behind the proxy
Browsers upload attachments straight to ORCHESTRAT_S3_PUBLIC_ENDPOINT, so it needs HTTPS too: browsers block uploads from an HTTPS page to a plain HTTP address. The second Caddy site above gives the bundled SeaweedFS that address. Presigned upload URLs are signed for that hostname, so the proxy must pass the Host header and paths through unchanged, which reverse_proxy does. See Storage.
With Amazon S3 or Cloudflare R2, the storage endpoint already has HTTPS, and you don't need the second site.