Goal: reach Jellyfin (and other containers) on your home LAN from anywhere, without exposing anything to the internet. Zero to working in about 15 minutes.
[Phone / Laptop]
|
Tailscale client
|
[Dedicated Server] ← public IP, runs Headscale (control plane only)
|
Tailscale network (WireGuard mesh)
|
[LAN Node] ← Docker host at 192.168.x.x, runs Jellyfin
The dedicated server only coordinates the mesh. Your media streams directly between your device and the LAN node over encrypted WireGuard.
http://jellyfin:8096 or the Tailscale IPFrom this repo's headscale_dev/ directory:
mkdir -p /data/headscale/config
cp config.yaml /data/headscale/config/config.yaml
nano /data/headscale/config/config.yaml # set server_url: https://headscale.example.com (YOUR domain)
cp sample.env .env
docker compose up -d
Point your reverse proxy (Nginx Proxy Manager) at container headscale,
port 8080, with SSL and websockets enabled. Then verify:
curl https://headscale.example.com/health
docker compose exec headscale headscale users create homelab
docker compose exec headscale headscale preauthkeys create --user homelab --expiration 1h
Copy the key it prints.
On the LAN node (your Docker host running Jellyfin):
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up --login-server=https://headscale.example.com --authkey <YOUR-PREAUTH-KEY>
On your phone: install the Tailscale app, choose custom / alternate coordination server,
and enter https://headscale.example.com. On a laptop, run the same
tailscale up command with a fresh key.
Verify from your laptop:
tailscale status
tailscale ping <lan-node-name>
With Tailscale connected on your device, open:
http://<lan-node-tailscale-ip>:8096 (the 100.64.x.x address from tailscale status), orhttp://<lan-node-name>.tailnet.local:8096 via MagicDNSsudo tailscale up --login-server=https://headscale.example.com --advertise-routes=192.168.1.0/24,
enable IP forwarding, then approve the route with
headscale nodes approve-routes on the server. See the README for details.docker compose exec headscale headscale nodes delete -i <NODE-ID>Full walkthrough, subnet routing, and gotchas: see README.md in this directory.