Well this is very timely and relevant. I usually access jellyfin on my network devices like `http://homecloud:8096` but now that I have been exploring adding other services, remembering the ports is getting tedious. I also am trying to be forward thinking about external access in the future.
Looks like I could use some combination of Caddy, Nginx Proxy Manager, Tailscale? What's the simplest setup?
I just got mine working a few months ago on FreeBSD using cloudflared. I paid for a cloudflare DNS and run cloudflared (in a jail, which is optional). Here is a redacted example of my tunnel.yml file (should work similarly on other OS's)
# cat /root/.cloudflared/fbsd0_tunnel.yml
tunnel: <redacted UUID>
credentials-file: /root/.cloudflared/<different UUID>.json
ingress:
# Example of an HTTP request over a Unix socket:
- hostname: <redacted full cloudflare URL, no port appended>
service: http://localhost:8096 #this is where jellyfin would normally run
# Example of a rule responding to traffic with an HTTP status:
- service: http_status:404
There was a debate here in the comments a few months ago about whether it's actually forbidden by their ToS. Lots of people said they don't care if you use it for personal streaming and aren't pumping a hundred gigs per day.
I use traefik to proxy to containers, pihole to provide dns for "*.mydomain.com", and tailscale to avoid opening ports
The end result is a valid HTTPS experience inside the network and outside (as long as tailscale is active on whatever device I'm using). And if I decide to ditch tailscale it's just a matter of mapping ports 80 and 443.
I’ve been using caddy, very easy to set up reverse proxies, and it generates a local root CA you can install on your machines at home so you get SSL for free. Nothing you couldn’t also rig with nginx, I just enjoyed the simplicity
I’ve got pihole running so that’s my home dns server, I have custom domains with a home-only TLD (I think “.internal” is cleared for use now?). So something like https://plex.homecloud.internal can load up plex, I can only assume jellyfin could do the same.
I’ve actually been using ZeroTier instead of tailscale for external access and I’ve been very happy with it, but I know lots of people love tailscale and I’m sure it’s great too
Traefik has that same auto ssl with LE that caddy does. That's what originally drew me to caddy - which I still use for stuff - but I just recently started working on something configured for Traefik out of the box and discovered it was pretty much the same experience. Just FYI.
I think they are may be simpler solutions but there is SWAG
https://github.com/linuxserver/docker-swag
that have built in config for proxying Jellyfin. It have all the necessary settings for proxy and built-in Letsencrypt client so you do not have configure it yourself.
I have a script written that do `docker compose down && docker compose pull && docker compose up -d` that runs every now and then so it keeps itself up to date (SWAG, Jellyfin and others).
Again there are probably easier options to get it running but in my case most of it runs on docker so (in theory since I had no major outages just a few times I migrated hardware) moving/restoring from backup is relatively easy - copy all the files and run `docker compose` in each directory.
The simplest setup is to run jellyfin and tailscale in docker with docker compose utilizing tailscale serve. You will get automatic https and a simple reverse proxy with tailscale serve.
im running a pihole so i take advantage of lighttpd that it uses, with the mod_proxy configuration. i can then do something like the following to have a friendly url on my local network
I've been using nginx for more than a decade now, before that I used lighttpd. Both work well for the purpose of reverse proxying services like Jellyfin. I do not use Caddy because I prefer to keep certificate management centralised in its own (Proxmox-managed) container. I have about 50 services running in Proxmox-managed containers (some containers run more than a single service, others are service-specific) proxied through a single nginx instance, the setup is reliable and performs well. Since nginx is widely used there is usually a config file available which can be used to base your own installation on. Here's what it looks like in my case:
# kijkbuis.example.org
server {
listen 80;
listen [::]:80;
server_name kijkbuis.example.org;
include /etc/nginx/snippets/enforcehttps.conf;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name kijkbuis.example.org;
ssl_certificate /etc/letsencrypt/live/kijkbuis.example.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/kijkbuis.example.org/privkey.pem;
set $jellyfin 192.168.1.51;
resolver 192.168.1.1 valid=30;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
# the google-related domains are there to enable chromecast support
add_header Content-Security-Policy "default-src https: data: blob: http://image.tmdb.org; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' https://www.gstatic.com/cv/js/sender/v1/cast_sender.js https://www.gstatic.com/eureka/clank/108/cast_sender.js https://www.gstatic.com/eureka/clank/107/cast_sender.js https://www.gstatic.com/eureka/clank/cast_sender.js https://www.youtube.com blob:; worker-src 'self' blob:; connect-src 'self'; object-src 'none'; frame-ancestors 'self'";
location = / {
return 302 https://$host/web/;
}
location / {
# Proxy main Jellyfin traffic
proxy_pass http://$jellyfin:8096;
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;
proxy_set_header X-Forwarded-Protocol $scheme;
proxy_set_header X-Forwarded-Host $http_host;
# Disable buffering when the nginx proxy gets very resource heavy upon streaming
proxy_buffering off;
}
# location block for /web - This is purely for aesthetics so /web/#!/ works instead of having to go to /web/index.html/#!/
location = /web/ {
# Proxy main Jellyfin traffic
proxy_pass http://$jellyfin:8096/web/index.html;
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;
proxy_set_header X-Forwarded-Protocol $scheme;
proxy_set_header X-Forwarded-Host $http_host;
}
location /socket {
# Proxy Jellyfin Websockets traffic
proxy_pass http://$jellyfin:8096;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
proxy_set_header X-Forwarded-Protocol $scheme;
proxy_set_header X-Forwarded-Host $http_host;
}
}
Looks like I could use some combination of Caddy, Nginx Proxy Manager, Tailscale? What's the simplest setup?