Guide
7 min read

A Safer Reverse-Proxy Decision Tree for Self-Hosted Media Apps

Should Jellyfin and Immich be public behind a reverse proxy, private over a VPN, or both? A decision tree that weighs privacy, family access, and streaming bandwidth instead of guessing.

A Safer Reverse-Proxy Decision Tree for Self-Hosted Media Apps

"Should I put Jellyfin behind a reverse proxy and make it public, or keep it private over a VPN?" is the most-asked self-hosted media question, and the answer is genuinely "it depends" — but on a small number of things you can decide in five minutes. The mistake is answering it by copying someone else's setup whose priorities weren't yours. Here's a decision tree that weighs the factors that actually matter: who needs access, how private the content is, and how much bandwidth the streams need.

First, the three factors

  1. Who needs in? Just you and devices you control? Or family/friends who won't install a VPN client?
  2. How sensitive is the content? A movie library is different from a private photo collection where every frame is personal.
  3. How heavy is the traffic? High-bitrate video streaming is bandwidth-hungry; a photo timeline is light by comparison.

The decision tree

Only you, on devices you control → VPN-only. No public exposure at all. Run WireGuard/Tailscale, require the VPN to reach the app, and you've got the smallest possible attack surface. Perfect for a private Immich.

Family/friends who won't run a VPN → public, behind a reverse proxy, with auth. They need a clean https:// URL that just works. Put the app behind a reverse proxy with TLS and an authentication layer — never rely on the app's login alone for something internet-facing. Mind the app-specific settings (upload size, WebSockets, timeouts) in Immich behind a reverse proxy; they apply to any media app.

Private content + a few trusted people → mesh share, not public. Tailscale (or Headscale) lets you share access to specific people without opening the app to the internet — the middle ground that keeps a private photo library off the public web while still sharing it. The fleet-access patterns cover this.

Behind CGNAT (no inbound port) → VPS relay or tunnel. Your ISP removed the public port, so accept connections elsewhere. The full menu — VPS reverse-proxy relay, Cloudflare Tunnel (watch plaintext for media), Tailscale Funnel — is in reaching apps behind CGNAT.

The privacy rule that overrides convenience

For private media, don't let an external edge that terminates TLS see your content in plaintext. A movie catalog through a third-party proxy is one risk calculus; your family photos are another. Keep TLS terminating on hardware you control (your VPS or your box) for anything sensitive — even if a hosted tunnel would be one click easier.

The bandwidth reality

Public Jellyfin streaming runs real video through whatever's in the path. A VPS relay pays for that egress; a direct (CGNAT-free) connection doesn't. Size for direct play over transcoding to cut bandwidth, and don't route heavy streams through a tunnel that throttles or bills them.

ServerCompass self-hosted media server migration illustration Planning media access in ServerCompass — matching the exposure model to who needs in and how private the library is, rather than copying a stranger's reverse-proxy config.

Quick chooser

  • Just me → VPN-only.
  • Non-technical family → public reverse proxy + auth + TLS.
  • Private content, few people → mesh share, not public.
  • Behind CGNAT → VPS relay / tunnel (TLS you control for private media).
  • Heavy streaming → prefer direct play; mind egress.

Takeaway

There's no universal right answer for exposing media apps — but there's a right answer for your three factors. Decide who needs access, how private the content is, and how heavy the streams are, then follow the tree. VPN-only for you, authenticated reverse proxy for family, mesh shares for private content, a relay for CGNAT — chosen on purpose, not copied.

reverse-proxy
jellyfin
immich
remote-access
media-server

From across the StoicSoft network

Hand-curated reads on the same topic from sister sites in the StoicSoft family.

Keep reading

Guide
8 min

Plex-to-Jellyfin migrations need library integrity and client-connection checks before the cutover

Fresh Jellyfin and Immich threads show that media-server migration risk is not only about copying files. One user is moving from Plex to Jellyfin and sees music albums missing even though folders, permissions, and rescans look right. Another has Roku clients…

Guide
7 min

Lost HTTPS After a Network Change? A SWAG and Let's Encrypt Recovery Checklist

Immich or Jellyfin loses HTTPS after an ISP change or a simple network move, and the SWAG logs are a wall of ACME errors. A recovery checklist that starts at DNS and ends at a renewed cert.

Guide
7 min

Media Servers Keep Hitting the Same Three Walls: Proxmox Passthrough, GPU Sizing, Storage

Jellyfin and Immich on Proxmox run into the same trio every time — GPU passthrough that won't stick, transcoding sized wrong, and storage that fights the hypervisor. Clear each wall.

Guide
8 min

Reaching Your Self-Hosted Apps Behind CGNAT — Without Exposing Port 443

CGNAT removes inbound ports, not your options. A decision tree for clean domains and private access to Jellyfin and Immich using VPS relays, Cloudflare Tunnel, Tailscale, and WireGuard.

Guide
8 min

Beginner homelabs need an app-first checklist before buying storage, servers, or noisy rack gear

Very fresh homelab and self-hosted threads keep showing beginners choosing hardware before they have a stable application plan. One user already runs Immich and Jellyfin on an old laptop but is unsure what storage size, drive class, and server path fit a…

Guide
8 min

Media servers moved into VMs and containers need mount and client-resume proof before family users rely on them

Fresh Jellyfin, Plex, and media-server threads show that a media stack can look installed while still failing at the boundary users actually hit. One Jellyfin user runs the server in a NAS container and can start playback, but the desktop app on Bazzite…