Skip to content

Reverse Proxy

JovinJovinsson edited this page Jul 24, 2026 · 1 revision

Running behind a reverse proxy

Putting Collapsarr behind nginx/Traefik/Caddy (custom domain, TLS termination, one shared port 443 for several services) works fine, but there is one setting you must change first, or every visitor — including strangers on the internet — will silently skip login.

Why: the local-bypass footgun

By default (Login requirement = "Disabled for local addresses", the local_bypass mode), Collapsarr looks at the direct TCP peer address of each request. If that address is loopback or private-range (127.0.0.1, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), it's treated as trusted and the request skips setup/login entirely — deliberately, so a LAN/localhost install is zero-friction.

Collapsarr never reads X-Forwarded-For for this decision, because that header is client-suppliable and trivially forged. That's the correct call in general, but it has a consequence: behind a reverse proxy, the proxy is the direct peer, and the proxy is almost always running on localhost or in the same private network as Collapsarr. So every client — including one out on the public internet — gets classified as local and sails through with no login. Trusted-proxy support (actually parsing forwarded-for headers from a proxy you've explicitly configured as trusted) is planned but not built yet.

The fix: set Login requirement to "Always required" (auth_required = "enabled") on any install that sits behind a reverse proxy. This is a one-time setting, not something the proxy config below can work around.

  • Existing install: Settings → General → Login requirement → "Always required".
  • Fresh headless install (Docker Compose / Ansible, no human to click through /setup): set COLLAPSARR_AUTH_REQUIRED=enabled alongside COLLAPSARR_AUTH_USERNAME/COLLAPSARR_AUTH_PASSWORD — this only seeds on first boot when no credential exists yet, so it won't retroactively change an already-set-up instance (see the README's Authentication section).

Collapsarr has no built-in TLS and no websocket/SSE traffic — it's plain HTTP/REST plus a static SPA bundle, so a standard proxy_pass/reverse-proxy config is all you need beyond that.

One header that matters: X-Forwarded-Proto

Unlike the local/public classification above, the session cookie's Secure flag does honor X-Forwarded-Proto — if it's missing or wrong, browsers will refuse to send the cookie back over your TLS-terminated domain and logins won't "stick". Make sure your proxy sets it to https on every request it forwards.

nginx

server {
    listen 443 ssl;
    server_name collapsarr.example.com;

    ssl_certificate     /etc/letsencrypt/live/collapsarr.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/collapsarr.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8282;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Traefik (Docker Compose labels)

services:
  collapsarr:
    image: odxnsson/collapsarr:latest
    container_name: collapsarr
    volumes:
      - ./config:/config
      - /path/to/media:/media
    environment:
      - PUID=1000
      - PGID=1000
    restart: unless-stopped
    labels:
      - traefik.enable=true
      - traefik.http.routers.collapsarr.rule=Host(`collapsarr.example.com`)
      - traefik.http.routers.collapsarr.entrypoints=websecure
      - traefik.http.routers.collapsarr.tls.certresolver=letsencrypt
      - traefik.http.services.collapsarr.loadbalancer.server.port=8282

Traefik sets X-Forwarded-Proto/X-Forwarded-For/X-Forwarded-Host automatically for every routed request — no extra headers middleware needed for this.

Verifying it worked

  1. Confirm Login requirement is "Always required" (Settings → General, or GET /api/settings and check auth_required).
  2. Visit the public URL (not http://localhost:8282 directly) in a private/incognito window. You should hit /login, not the app — if you land straight in the UI, the proxy's address is still being classified as local, meaning step 1 didn't take.
  3. Log in and reload — the session should persist. If you're bounced back to /login every reload, X-Forwarded-Proto likely isn't being forwarded (or isn't https), so the browser is dropping the Secure cookie.

See also: Beta builds, the main README.

Clone this wiki locally