Expose Jellyfin Over Tailscale
This guide puts Jellyfin on your tailnet as its own Tailscale Service, at https://jellyfin.your-tailnet.ts.net. Every device signed in to your tailnet can stream from it, nothing is published on your router, and Jellyfin does not need a Docker port mapping.
Before You Start
- DockTail runs on the Docker host, as in the Quick Start.
- The host is tagged and allowed to advertise services; see ACL Configuration.
- DockTail has OAuth credentials, so it creates the
jellyfinservice definition itself. Without them, create the service in the Tailscale admin console first. - HTTPS is enabled for your tailnet (Tailscale admin console, DNS page), so Tailscale can issue the certificate.
The Compose File
services:
jellyfin:
image: jellyfin/jellyfin:latest
restart: unless-stopped
volumes:
- ./config:/config
- ./cache:/cache
- /path/to/media:/media:ro
labels:
- "docktail.service.enable=true"
- "docktail.service.name=jellyfin"
- "docktail.service.port=8096"
- "docktail.service.service-port=443"
What the labels do:
docktail.service.port=8096is Jellyfin's HTTP port inside the container. DockTail proxies straight to the container IP, so there is noports:section.docktail.service.service-port=443makes the tailnet side HTTPS with an automatic certificate. The backend stays plain HTTP, because the backend protocol only defaults to HTTPS when the container port is443.
Start it:
docker compose up -d
The first time, the service may need approval in the Services tab of the Tailscale admin console; see Approve Services. Then open https://jellyfin.your-tailnet.ts.net and run the Jellyfin setup wizard.
Jellyfin Apps
In the Jellyfin apps (Android, iOS, Android TV, Swiftfin, Jellyfin Media Player), add the server as https://jellyfin.your-tailnet.ts.net. The device needs Tailscale running. Tailscale Serve passes WebSocket upgrades through, which Jellyfin uses for remote control and live updates.
Client IPs In Jellyfin
Tailscale Serve sends the tailnet client's address in X-Forwarded-For. Jellyfin ignores that header unless the request comes from a known proxy, so by default its dashboard and logs show the address tailscaled connects from: with Tailscale on the host, the gateway of the Docker network Jellyfin is on.
To see real client addresses, look up that gateway and add it under Dashboard > Networking > Known proxies, then restart Jellyfin:
docker network inspect <project>_default --format '{{range .IPAM.Config}}{{.Gateway}}{{end}}'
This is optional. Streaming works either way.
Host Networking For DLNA
Jellyfin's documentation says host networking is required for DLNA. DockTail works with it: a container with network_mode: host is served on 127.0.0.1, so the same labels apply.
services:
jellyfin:
image: jellyfin/jellyfin:latest
restart: unless-stopped
network_mode: host
volumes:
- ./config:/config
- ./cache:/cache
- /path/to/media:/media:ro
labels:
- "docktail.service.enable=true"
- "docktail.service.name=jellyfin"
- "docktail.service.port=8096"
- "docktail.service.service-port=443"
With host networking, Jellyfin also listens on port 8096 of every host interface, so it stays reachable on your LAN as before. In that case the known proxy to add is 127.0.0.1.
Optional: Share Publicly With Funnel
To let someone without Tailscale reach Jellyfin, add a Funnel. The host needs the funnel node attribute first; see Funnel ACL.
labels:
- "docktail.service.enable=true"
- "docktail.service.name=jellyfin"
- "docktail.service.port=8096"
- "docktail.service.service-port=443"
- "docktail.funnel.enable=true"
- "docktail.funnel.port=8096"
The public URL is the machine's name, https://your-machine.your-tailnet.ts.net, not jellyfin.your-tailnet.ts.net. Anyone on the internet then reaches the Jellyfin login page, so use strong passwords and keep Jellyfin updated.
Troubleshooting
- The service never shows up.
docker compose logs docktailnames the cause, most often an untagged host or a missing auto-approver. - It shows up but does not connect. On rootless Docker the host often cannot reach container IPs; see Rootless Docker.
- Jellyfin is on a network DockTail does not pick. If the container is attached to several networks, name the one to use with
docktail.service.network; see Service Labels.