Reverse proxy and HTTPS¶
Longbox speaks plain HTTP. To reach it from outside the house, or just to get
HTTPS on the LAN, put a proxy such as Caddy in front
and let it terminate TLS. deploy/proxy/ in the repository is a
working setup for one host running several apps: a Caddyfile, the matching
dnsmasq lines for the LAN, and a walkthrough from DNS records to a first check.
What Longbox itself needs, in /etc/longbox.env:
LONGBOX_HOST=127.0.0.1 # only the proxy can reach it
LONGBOX_PUBLIC_URL=https://comics.example.com # what links are built from
LONGBOX_SECURE_COOKIES=1 # session cookie over HTTPS only
LONGBOX_HOSTkeeps the port from answering to the network, so the proxy cannot be walked around.LONGBOX_PUBLIC_URLis required, not cosmetic: password setup and reset links are built from it, and without it they take whateverHostheader the caller sent.LONGBOX_SECURE_COOKIESstops the session cookie travelling over plain HTTP. It also means signing in overhttp://stops working, deliberately.
LONGBOX_TRUSTED_PROXIES is the setting that is easy to get wrong. The
login throttle keys on the caller's address, and behind a proxy that address
arrives in X-Forwarded-For, a header anyone can write. Longbox believes it
only from the proxies listed here, and then only the rightmost entry that is
not itself a proxy; reached any other way, the header is ignored and the
connection's own address is used. The default is loopback, a proxy on the same
host. A proxy in another container or on another machine has to be named
(172.18.0.0/16, say), or every visitor looks like the proxy and shares one
throttle. Never *, which believes the header from everybody.
OPDS readers send your password with every request, so point them only at the
https:// address.
The working example¶
deploy/proxy/ in the repository holds a complete, commented setup for one
host serving several applications behind a single Caddy:
| File | What it is |
|---|---|
Caddyfile |
One site block per name, all on one :443 listener. Belongs at /etc/caddy/Caddyfile. |
dnsmasq-lan-names.conf |
LAN answers for the same names, so devices at home reach the server directly. Belongs at /etc/dnsmasq.d/apps.conf. |
README.md |
The walkthrough, from DNS records through router forwarding to a first check. |
It configures the host rather than Longbox, which is why it sits beside the
deployment files and is not installed by deploy/install.sh.
Three things it deliberately leaves out, each for a reason worth knowing:
- No
trusted_proxiesin Caddy. Caddy is the outermost proxy, so it should believe nothing a client sends inX-Forwarded-*. By default it discards those headers and writes its own, and Longbox depends on that. Add it only if another proxy or a CDN sits in front. - No
encode. Almost everything served is already compressed — comic pages, archives, audio — so it would spend CPU for nothing. - No
Strict-Transport-Securityyet. Browsers remember it for the period you set, so add it once everything has worked for a while, not while you are still testing.
Getting the certificate without burning the rate limit¶
Let's Encrypt allows only a handful of failed attempts an hour, and a typo in a DNS record or a missed router forward will exhaust them quickly.
Start on the staging service, which has generous limits and issues certificates browsers do not trust — fine for proving the plumbing:
{
acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
}
Comment it out and reload once staging succeeds.
Editing the file is not enough on its own:
caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile
sudo systemctl reload caddy
Reaching it from inside the house¶
Devices on the LAN should not have to go out to the public address and back in.
Many routers cannot do that hairpin (NAT loopback) at all, and where they can
it is slower and fails confusingly.
Resolving the same public names to the server's private address on the LAN is what makes one set of names, and one certificate each, work identically inside and outside the house.
One line per name — never address=/example.com/... for the whole domain, which
would answer for every other name under it, mail and www included.
A note on ACME account email¶
Caddy's email option buys less than it looks like. Let's Encrypt ended
expiration notification emails on 4 June 2025, so it no longer gets you a
warning about a certificate that failed to renew. An address given now is not
stored against the account at all.
Renewal monitoring, if you want it, has to come from outside — an external
certificate monitor, or a cron job comparing
openssl s_client ... | openssl x509 -enddate against today.