TLS and reverse proxies
Every phone, browser and webhook sender talks to InfraInbox over HTTPS. There are three ways to get a certificate in front of it, in the order most self-hosters want them.
1. The built-in TLS front door: Caddy and Let’s Encrypt
Section titled “1. The built-in TLS front door: Caddy and Let’s Encrypt”For a server with a public DNS name. The compose file’s Caddy override obtains and renews a browser-trusted Let’s Encrypt certificate automatically and proxies to the app. Turn it on in .env:
COMPOSE_FILE=docker-compose.yml:docker-compose.caddy.ymlCADDY_ACME_EMAIL=you@example.comthen docker compose up -d as usual. What it needs from the outside world:
| Requirement | Why |
|---|---|
A DNS A record for your host, pointing straight at this machine |
Let’s Encrypt resolves the name and connects back to it |
| TCP 80 open to the internet | The ACME HTTP-01 challenge, and the plain-HTTP→HTTPS redirect |
| TCP 443 open to the internet | The site itself |
Point the DNS record directly at the machine — no CDN or proxy in front. With this override on, the app itself publishes no port at all; Caddy is the only way in.
2. TLS in the app container (the default)
Section titled “2. TLS in the app container (the default)”With no override, the app terminates TLS itself. Without a certificate configured it generates a self-signed one on first start, which browsers will warn about — fine for a private LAN instance, less fine for anything else. To use a real certificate you already have, mount it into the container and point these two settings at it:
INFRAINBOX_TLS_CERT_FILE=/certs/fullchain.pemINFRAINBOX_TLS_KEY_FILE=/certs/privkey.pemThere is no proxy in front in this mode, so no X-Forwarded-* header is trusted — nothing more to configure.
3. Your own reverse proxy
Section titled “3. Your own reverse proxy”Set INFRAINBOX_TLS=off to serve plain HTTP for a proxy you run yourself (Nginx Proxy Manager, HAProxy, an existing Traefik, and so on), and tell InfraInbox to trust it:
INFRAINBOX_TLS=offINFRAINBOX_HTTP_TRUSTED_PROXIES=192.0.2.10Two things your proxy must do:
- Pass the original
Hostheader through, not its own. InfraInbox compares it againstINFRAINBOX_PUBLIC_URL’s host; a proxy that rewrites it gets every request refused with a 421. - Never redirect a plain-HTTP hook or API call to HTTPS. A source’s key or a session cookie has already crossed the wire in clear by the time a redirect could save it. Refuse anything but
GET/HEADon port 80 instead of redirecting it (the Caddy examples below show the pattern).
Without INFRAINBOX_HTTP_TRUSTED_PROXIES set, every request looks like it came from the proxy, so every per-client rate limit collapses into one shared bucket.
Ready-made examples
Section titled “Ready-made examples”The repository ships three worked Compose overrides under deploy/examples/, each an override on the base compose file (so the read-only container, pinned image tags and required passwords still apply):
| Example | What it gives you |
|---|---|
caddy/ |
Caddy terminating TLS with its own internal CA — no public DNS name or open port 80 needed. Good for a LAN-only instance you still want real HTTPS on; phones pin the CA through the pairing QR code. |
traefik/ |
Traefik terminating TLS from a certificate you already have, configured entirely from files (no Docker socket mounted into the proxy). |
tailscale/ |
A Tailscale sidecar that serves the node’s own *.ts.net name over HTTPS, reachable only from your tailnet. |
Each has its own short README next to the Compose file. Set INFRAINBOX_TLS=off and INFRAINBOX_HTTP_TRUSTED_PROXIES to the proxy’s fixed address, the same as any other reverse proxy — the examples just do it for you.