Jellyfin HTTPS: a free SSL certificate with a reverse proxy

Updated ยท 5 min read

Out of the box, Jellyfin speaks plain HTTP on port 8096. That's fine inside your home and not fine on the internet. Here's how to give Jellyfin HTTPS with a free SSL certificate that renews itself, and why a reverse proxy is usually easier than Jellyfin's built-in option.

What you need first

A certificate proves to browsers and apps that they're talking to your server and nobody in between. Let's Encrypt issues them free, but only for a name it can check, so you need:

  • A name. A domain or subdomain you control, such as watch.example.com. Certificates for a bare IP address aren't the practical route here.
  • A DNS A record pointing that name at your home's public IPv4 address (and an AAAA record for IPv6, if you use it). If your home address changes, keep the record current with dynamic DNS.
  • Ports 80 and 443 reaching the server. On your router, forward TCP 443 (and usually 80) to the computer that will run the proxy. Let's Encrypt connects to one of them to confirm you control the name.
  • A public address of your own. If your provider shares one address among many homes, incoming connections never arrive. See Jellyfin behind CGNAT.

If you only need Jellyfin on your own devices, you may not need any of this: a private network such as Tailscale is covered in Jellyfin remote access, step by step.

Set up Caddy by hand

Jellyfin's documentation covers Caddy, nginx, Traefik, HAProxy and Apache, and recommends Caddy. Caddy gets the certificate, renews it, redirects HTTP to HTTPS and passes WebSocket connections through, all with a two-line config.

  1. Install Caddy on the computer that runs Jellyfin. Get it from caddyserver.com: there are packages for common Linux systems, and a single program for Windows and Mac.
  2. Write the Caddyfile. Create a file named Caddyfile with your name and Jellyfin's local address:
    watch.example.com {
        reverse_proxy 127.0.0.1:8096
    }
  3. Forward ports 80 and 443. On your router, send TCP 80 and TCP 443 to this computer's reserved address, and allow both through the computer's firewall.
  4. Start Caddy. On Linux with the package, run sudo systemctl reload caddy after editing /etc/caddy/Caddyfile. Elsewhere, run caddy run in the folder with the Caddyfile. Watch the output: it reports when the certificate is obtained.
  5. Add the proxy to Known proxies. In Jellyfin, open Dashboard > Networking and add 127.0.0.1 to Known proxies. Save and restart Jellyfin. Without it, Jellyfin sees every visitor as coming from the proxy, which breaks remote-versus-home rules and logs.
  6. Test from outside your home. On a phone with Wi-Fi off, open https://watch.example.com. You should see the padlock and Jellyfin's sign-in page.

Tip: keep Jellyfin's port 8096 closed on the router. Only the proxy's ports are forwarded; the proxy reaches Jellyfin on the same computer.

Prefer nginx or Traefik? Both work. nginx needs a certificate tool such as Certbot and explicit WebSocket and forwarded-header lines; Jellyfin's reverse proxy docs list the ones it expects. Traefik suits people who already use it with Docker labels. Whichever you use, the Known proxies step is the same.

If Jellyfin runs in Docker

Add Caddy to the same compose file, so it reaches Jellyfin by service name. This assumes your Jellyfin service is called jellyfin:

services:
  caddy:
    image: caddy:2
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data

volumes:
  caddy_data:

In the Caddyfile, use reverse_proxy jellyfin:8096. The caddy_data volume keeps the certificate between restarts; without it, Caddy asks for a new one each time and can hit Let's Encrypt's rate limits. For Known proxies, use the Caddy container's address on the compose network, which docker inspect shows.

On a NAS, ports 80 and 443 are often taken by the NAS's own web interface. Free them in the NAS settings or run the proxy on another machine. Docker reports this as a port that's already allocated.

Jellyfin's own HTTPS option

Jellyfin can serve HTTPS itself, on port 8920 by default. You enable it on the Networking page and point Jellyfin at a certificate file, usually a PKCS #12 (.pfx) file with its password. It works, but:

  • Jellyfin doesn't fetch or renew certificates. Let's Encrypt certificates last 90 days or less, so you need a separate tool to renew them and convert each one to .pfx.
  • Jellyfin's documentation strongly recommends doing HTTPS on a reverse proxy instead, and discourages self-signed certificates.
  • A proxy can serve other things on the same port 443 later.

The built-in option makes sense mainly if you already manage certificates for other services and want no extra program.

When the certificate won't come

  • Timeout or connection refused in Caddy's log. Let's Encrypt couldn't reach you. Check the router forwards, the computer's firewall, and whether an antivirus with its own firewall blocks the ports.
  • Wrong address in the log. The A record points somewhere old. Fix it, then wait for DNS to update.
  • A NAS or another device answers. Port 443 is forwarded to the wrong device.
  • Padlock fine, but "502 Bad Gateway". The proxy can't reach Jellyfin. Check the address and port in the Caddyfile, and that Jellyfin is running.

Questions

Does Jellyfin support Let's Encrypt?

Not directly. Jellyfin can use a certificate you give it, but it doesn't request or renew one. A reverse proxy such as Caddy handles Let's Encrypt for you.

Do I need port 80 open for a Jellyfin certificate?

Usually yes. Let's Encrypt checks your name over port 80 or port 443. Caddy can use either, but forwarding both is the most reliable, and port 80 also lets Caddy redirect plain visits to HTTPS.

What should I put in Known proxies?

The address the proxy connects to Jellyfin from. That's 127.0.0.1 when the proxy runs on the same computer, or the proxy container's address in Docker.

Can I use HTTPS without a domain?

Not with a trusted public certificate in a practical way. Use a free dynamic DNS name, or a private network such as Tailscale, which can give your server an HTTPS name inside your tailnet.

The one-click way: Reelhost

When you claim yourname.watchhome.app, Reelhost installs Caddy, gets a free Let's Encrypt certificate, opens port 443 on your router with UPnP, and keeps the name pointed at your home with an hourly check. Prefer your own name? Use my own domain instead sets up Jellyfin and HTTPS on your computer and lists your two steps: forward ports 80 and 443, and add the DNS A record. It needs Complete or Yearly.

The check-up is free and changes nothing. Every fix is previewed, backed up and reversible.