... I swear I'll stop writing about Tailscale soon
Yet another Tailscale post huh? Can’t blame me, can you?
There I was, back home in Seattle, my parents gone for the weekend, and I was bored. What if I watch the fourth season of the Sopranos?
Great, I’ll just watch it on my phone through my Jellyfin app… oh wait! My parents have a great LG TV that I can watch on. What if I cast the Jellyfin content from my phone to the TV? Spinny circle spinny circle, no output.
My parents’ TV has no access to my Jellyfin container all the way back in LA.
How do I solve this in an afternoon with nothing but a Raspberry Pi and some network magic?
The problem
If you’ve been following my previous Tailscale posts, you’ll know that I really enjoy hosting things on my server. One of the first things I hosted was a Jellyfin instance pointed at my NAS, which has my favorite shows and movies on it.
This Jellyfin container on my Proxmox host, like all my other containers, is connected via Tailscale to the rest of my devices/services.
Great. I can access this anywhere (including on an airplane, surprisingly!) as long as there’s internet connection.
However, Tailscale is really frustrating when I’m working with devices that aren’t truly mine or trying to share things with others (See my post on image sharing for details and my solution).
This was especially apparent when I tried casting my show that I could watch on the Jellyfin client on my phone to the LG TV.
Casting
Casting generally takes two forms:
The client sends the streaming url + auth to the device being cast to
OR
The client streams the video to the device being cast to.
Chromecast generally does the former and LG TV has some form of Chromecast that seems compatible with the Jellyfin Chromecast ability.
However, since the TV itself is not on my Tailnet, receiving an ip like jellyfin.tailxxx.net doesn’t let the TV actually fetch the stream at all.
Well, what if I just install Tailscale on the TV? LG webOS sucks, and there isn’t an application for it.
What’s in a Raspberry Pi?
A few months ago, my friend Yasir gave me his Raspberry Pi. At the time, I just wanted a way to access my parents’ network for VPN purposes, so I left it plugged into the router directly and went back to LA.
The Raspberry Pi is on my Tailnet and set up as an exit node, so I can route all my traffic through there if I want to pretend like I’m back in Seattle with a real domestic IP for whatever reason.
The main point, though, is that the Pi sits in between two networks.
On one side, the Pi is connected to my Tailnet and can talk to all those services. On the other side, the Pi is connected to my parents’ LAN and can talk to all the local devices.
Essentially, I have a portal to my Tailnet in the Raspberry Pi that’s directly accessible to all devices on the network.
Reverse proxying feels like magic
Hm, well, if I have a device on the network that can access my Tailnet, and my Jellyfin instance as a result, and that same device can also be reached by local devices that aren’t on Tailscale…
What if I setup a simple reverse proxy on that device?
:8096 {
reverse_proxy https://jellyfin.sumoftheir.parts
}
We’re done. That’s it. Seriously!
My Raspberry Pi has a local IP (DHCP for now, but I’ll fix it to be static later), runs a Caddy server that listens on 8096, and then simply proxies those requests to my Jellyfin instance.
The Pi is connected to my Technitium DNS node through Tailscale, so all of my domain name requests are automatically resolved.
When I cast from my phone to the TV, the TV receives a local stream url and can resolve that since it has access to the Pi locally. The only difference is, when I’m home, I need to configure my client to use the local ip Jellyfin forwarder as opposed to the usual domain name, but that’s not a big deal.
On the LG TV side, I can either watch the cast content, or I can install the Jellyfin application (easy), and then point it directly at the Raspberry Pi.
Brief ACL aside
Just to make sure everything was airtight, I setup ACL tags in Tailscale to only allow connections between my Jellyfin instance and the ‘relay’ (my Pi) on 443.
Perfect, we’re all done!
Bonus
Now that I have my Raspberry Pi handling some traffic for the TV, why not have it utilize our technitium DNS node for ad blocking on the TV web browser?
I installed dnsmasq on the Pi to handle DNS requests from the TV:
interface=eth0
server=100.xxx.xxx.xxx # technitium IP
no-resolv
I then set the DNS server on the TV itself to point to the Pi IP. With the Technitium blocklists, browsing websites on the TV results in zero ads or popups. Perfect for watching streams without ads!
Closing thoughts
Once again, I find myself getting great satisfaction from networking.
It feels like magic to be able to not only cast from my phone to the TV but to also just directly connect to Jellyfin as if the Jellyfin node is on the local network without even using Tailscale on the TV.
The Raspberry Pi fits so seamlessly, and there are no latency issues.
It feels as easy as Pi… cake..?
See you in my next Nithish Nerds out about Networking post ;)