Skip to content

Reverse Proxy

Brandon Johnson edited this page Sep 7, 2026 · 3 revisions

Reverse Proxy

If something else terminates TLS in front of Obelo — nginx, Caddy, Traefik, a container ingress — tell Obelo which address that proxy connects from:

OBELO_TRUSTED_PROXIES=127.0.0.1/32                 # a proxy on the same machine
OBELO_TRUSTED_PROXIES=10.4.0.9/32,10.4.0.10/32     # two proxies, by address

It is empty by default, and empty means nothing is believed

With no value set, no X-Forwarded-For or X-Forwarded-Proto header is believed from anybody. Obelo uses the connection's real peer address and the connection's real scheme, which is always true and sometimes less useful.

That default is not caution for its own sake. Obelo can terminate HTTPS itself, so clients reach it directly — and a forwarded header on a direct connection is written by whoever dialled the port. Obelo therefore reads one only when the machine on the other end of the socket is an address you listed.

What setting it turns back on

  • Per-client rate limits. The failed-login limiter and the TV sign-in code quota are counted per client address. Behind an undeclared proxy every request looks like it came from the proxy, so the whole household shares one budget — safe, but blunt. Declared, each device gets its own again.
  • The session cookie's Secure flag on the proxy's HTTPS. Undeclared, Obelo sees a plain-HTTP request and marks the cookie accordingly. Nothing breaks — the cookie still travels inside your proxy's TLS — but it is not flagged.

Only list a proxy you control

Every host inside a range you name is allowed to tell Obelo what address a request came from, which means it can also lie about it — and a host that can name its own address has no rate limit at all.

List the proxy itself — 10.4.0.9/32 — not the network it sits on. 10.0.0.0/8 because the proxy is somewhere in there also trusts every laptop, television, and compromised smart plug on your LAN.

  • A bare address means that one host (127.0.0.1 is read as 127.0.0.1/32).
  • An entry that is neither an address nor a CIDR stops the server at boot and says which one it was.
  • Never list a tailnet range (100.64.0.0/10). A tailnet peer is a client, not a proxy — see Remote Access with Tailscale.

How the header is read

Obelo reads the left-most entry in X-Forwarded-For that is not itself a trusted proxy, working from the right.

A client can put anything it likes at the front of that header; whatever your proxy appends comes after it, so the forged part is never reached.


Proxy configuration notes

Obelo streams media, uses Server-Sent Events for realtime updates, and serves HLS. Three things matter in whatever proxy you use:

  • Do not buffer responses. Response buffering breaks SSE (updates arrive in bursts or never) and adds latency to HLS segment delivery. In nginx that is proxy_buffering off; on the Obelo location.
  • Generous read timeouts. An SSE connection is idle by design between events. A 60-second proxy read timeout will tear it down repeatedly.
  • Pass X-Forwarded-For and X-Forwarded-Proto, and make sure the address the proxy connects from is what you listed in OBELO_TRUSTED_PROXIES.

A minimal nginx location:

location / {
    proxy_pass http://127.0.0.1:8080;
    proxy_http_version 1.1;
    proxy_set_header Host              $host;
    proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_buffering off;
    proxy_read_timeout 3600s;
}

Point the proxy at Obelo's plain-HTTP listener (OBELO_LISTEN_ADDR). If the proxy is terminating TLS, Obelo does not also need to — leave OBELO_TLS_MODE=off.

Do not proxy in front of acme mode

If you are using OBELO_TLS_MODE=acme, the TLS-ALPN-01 challenge has to reach Obelo's own TLS handshake. A proxy that terminates TLS first breaks validation. Pick one:

  • Let the proxy obtain the certificate, and leave Obelo on plain HTTP behind it (this page), or
  • forward TCP straight through to Obelo's TLS port and let Obelo obtain it (HTTPS).

Obelo

Home

Getting started

Reference

Going further

Plugins

Sharing with another household

Reaching it from away

When it breaks

Clone this wiki locally