Skip Navigation

How do I securely host Jellyfin? (Part 2)

I am making this post in good faith

In my last post I asked about securely hosting Jellyfin given my specific setup. A lot of people misunderstood my situation, which caused the whole thread to turn into a mess, and I didn't get the help I needed.

I am very new to selfhosting, which means I don't know everything. Instead of telling me that I don't know something, please help me learn and understand. I am here asking for help, even if I am not very good at it, which I apologize for.

With that said, let me reoutline my situation:

I use my ISP's default router, and the router is owned by Amazon. I am not the one managing the router, so I have no control over it. That alone means I have significant reason not to trust my own home network, and it means I employ the use of ProtonVPN to hide my traffic from my ISP and I require the use of encryption even over the LAN for privacy reasons. That is my threat model, so please respect that, even if you don't agree with it. If you don't agree with it, and don't have any help to give, please bring your knowledge elsewhere, as your assistance is not required here. Thank you for being respectful!

Due to financial reasons, I can only use the free tier of ProtonVPN, and I want to avoid costs where I can. That means I can only host on the hardware I have, which is a Raspberry Pi 5, and I want to avoid the cost of buying a domain or using a third party provider.

I want to access Jellyfin from multiple devices, such as my phone, laptop, and computer, which means I'm not going to host Jellyfin on-device. I have to host it on a server, which is, in this case, the Raspberry Pi.

With that, I already have a plan for protecting the server itself, which I outlined in the other post, by installing securecore on it. Securing the server is a different project, and not what I am asking for help for here.

I want help encrypting the Jellyfin traffic in transit. Since I always have ProtonVPN enabled, and Android devices only have one VPN slot enabled, I cannot use something such as Tailscale for encryption. There is some hope in doing some manual ProtonVPN configurations, but I don't know how that would work, so someone may be able to help with that.

All Jellyfin clients I have used (on Linux and Android) do not accept self-signed certificates. You can test this yourself by configuring Jellyfin to only accept HTTPS requests, using a self-signed certificate (without a domain), and trying to access Jellyfin from a client. This is a known limitation. I wouldn't want to use self-signed certificates anyways, since an unknown intruder on the network could perform a MITM attack to decrypt traffic (or the router itself, however unlikely).

Even if I don't trust my network, I can still verify the security and authenticity of the software I use in many, many ways. This is not the topic of this post, but I am mentioning it just in case.

Finally, I want to mention that ProtonVPN in its free tier does not allow LAN connections. The only other VPN providers I would consider are Mullvad VPN or IVPN, both of which are paid. I don't intend to get rid of ProtonVPN, and again that is not the topic of this post.

Please keep things on-topic, and be respectful. Again, I am here to learn, which is why I am asking for help. I don't know everything, so please keep that in mind. What are my options for encrypting Jellyfin traffic in transit, while prioritizing privacy and security?

76 comments
  • Hi again.

    How about the following idea:

    Set up ProtonVPN on the raspberry pi.

    On all other devices (or at least those you want to use Jellyfin on), switch from using Proton to using Wireguard. Unlike your phone, the raspberry pi has no trouble running multiple VPNs. I think the ProtonVPN limitations in regard to not allowing split tunneling don't apply here, since all outgoing traffic will still go via Proton.

    Essentially, the Pi would function as a proxy for all of your traffic, "and also" host Jellyfin. You would still connect to http://192.168.20.10:8096/ (or whatever) on your devices, but that address would only resolve to anything when you are connected to the pi via Wireguard. No HTTPs, but "HTTP over Wireguard", if you will.

    Nots that this requires you trusting the pi to the same degree that you trust your phone.

    For your static devices (PC, TV) this should solve the problem. Devices which you take with you, like your phone, unfortunately will loose internet connectivity when you leave your home until you switch off Wireguard, and switch on Proton, and not be able to connect to Jellyfin when you return home, until you switch them back.

    Essentially, you would have a "home" VPN and a "on the go" VPN, though you never need to connect to both. There might be ways to automate this based on WiFi SSID on Android, but I have not looked into it.

    The Pros:

    • this should meet all your requirements. No additional expenses, no domain, no dynDNS; no selfsigned certificate or custom CA; traffic is never unencrypted; works on all common devices.
    • Wireguard is sufficiently lightweight to not bog down the pi, normally
    • this is actually well within the intended use-cases for Wireguard, so no "black magic" required in configuring it
    • if you ever do decide to get a domain, you can configure everything to always be connected to your pi via Wireguard, even on the go! Not required though.

    The Cons:

    • when you are new to selfhosting, Wireguard is a bit daunting to set up. It is not the easiest to debug (don't worry, it's easy to tell IF it is working, but not always WHY it isn't working). Some manual route handling is probably also required on the pi. It should definitely be doable though, but might turn this Jellyfin thing from a weekend project to a 2 week project...
    • I have no experience with how well the pi runs Jellyfin. If the answer is "barely", then adding multiple concurrent Wireguard sessions might be a bad experience. Though in this case, you could only switch Proton to Wireguard whenever you want to watch Jellyfin.
    • the manual switching might be annoying, but that is the price to pay here, so to speak

    Edit: someone else already mentioned setting up your own trusted network with a second router. IMO that is the better, more hassle-free option IF you are willing to shell out the money. My suggestion is the "free" version of that, essentially 😄

    • Hi again.

      Hi there!

      Set up ProtonVPN on the raspberry pi.

      I'm actually surprised nobody suggested simply using the Pi with OpenWrt as my own router. Though, that would make it hard to host Jellyfin.

      Nots that this requires you trusting the pi to the same degree that you trust your phone.

      For the most part, I trust the security of my Pi. I can hold it in my hand and see every line of code, after all!

      Devices which you take with you, like your phone, unfortunately will loose internet connectivity when you leave your home until you switch off Wireguard, and switch on Proton, and not be able to connect to Jellyfin when you return home, until you switch them back.

      I plan to post a tutorial about how to securely host Jellyfin. Another user gave a solution to this problem that I absolutely love, and I'll showcase it there. I don't want to spoil it :)

      Could you explain Wireguard vs. Tailscale in this scenario?

      Thank you all so much for your help! This is likely the solution I will go with, combined with another one, so again thank you so much!

      P.S. I don't care if you wrap an ethernet cord around her finger, get going!

      • Tailscale is just a bunch of extra fancy stuff on top of Wireguard. If you don't need the fancy stuff, using raw Wireguard can be more lightweight, but might require more networking knowledge.

        The biggest thing Tailscale brings you the table is NAT traversal. On top of that it uses direct Wireguard tunnels as necessary instead of creating a mesh like you usually would if you were using raw Wireguard. It also offers convenient bits of sugar like internal DNS, and it handles key exchanges for you so it's just generally easier to configure. When you do raw Wireguard you're doing all the config yourself, which could be a pro or a con depending on your needs—and you'll be editing config files, unlike Tailscale which has a GUI for most things. It also supports some more detailed security options like ACLs and I think SSO, while Wireguard is reliant on your existing firewall for that.

        Here's what Tailscale has to say about it: https://tailscale.com/compare/wireguard

        I've messed around with Tailscale myself, but ultimately settled on running Wireguard. The reason I do that though is because I trust my LAN, and I only run Wireguard at the edge. Tailscale really wants to be run on every node, which in turn is something that raw Wireguard theoretically can do but would be onerous to maintain. If I didn't trust my LAN, I'd probably switch to Tailscale.

      • I’m actually surprised nobody suggested simply using the Pi with OpenWrt as my own router. Though, that would make it hard to host Jellyfin.

        A brief internet search shows that surprisingly, hosting Jellyfin on OpenWRT should work.... No idea how well though. Come to think of it, having OpenWRT on the pi might make it a lot easier to configure, with graphical settings available and so on.

        Could you explain Wireguard vs. Tailscale in this scenario?

        I've never used tailscale, I'm afraid. Normally I would say: just use whatever seems easier to set up on your device/network; however, note that tailscale needs a "coordinate server". No actual traffic ever goes through it, it just facilitates key exchanges and the like (from what I understand), but regardless, it's a server outside your control which is involved in some way. You can selfhost this server, but that is additional work, of course...

        Thank you all so much for your help! This is likely the solution I will go with, combined with another one, so again thank you so much!

        Glad I could help, after being so unhelpful yesterday :)

        P.S. I don’t care if you wrap an ethernet cord around her finger, get going!

        Eh... Marriage is not really common in either of our families. We agreed to go sign the papers if there ever is a tax reason, lol. Sorry if that's a bit unromantic :D Nice rings though ^^

  • To be totally honest I didn’t read your entire post, but just from your intro I think we are in similar situations. ISP router, low costs, using only the hardware you have around. I’ve solved a lot of stuff with Tailscale. None of my services are public facing and instead I connect to them over Tailscale (could be replaced with wireguard).

    The wall I’m hitting you or maybe others could help with, is accessing my services from sub domains of a single Tailscale address rather than having to type port numbers for everything. I know this involves a reverse proxy and DNS (I use PiHole for that), but I’m stuck trying to configure the two in a way that actually works. Once I finally ditch iOS for good I’ll probably just sync a hosts file between all my devices using Syncthing to help streamline the DNS situation.

  • Wow, there isn’t a single solution in here with the obvious answer?

    You’ll need a domain name. It doesn’t need to be paid - you can use DuckDNS. Note that whoever hosts your DNS needs to support dynamic DNS. I use Cloudflare for this for free (not their other services) even though I bought my domains from Namecheap.

    Then, you can either set up Let’s Encrypt on device and have it generate certs in a location Jellyfin knows about (not sure what this entails exactly, as I don’t use this approach) or you can do what I do:

    1. Set up a reverse proxy - I use Traefik but there are a few other solid options - and configure it to use Let’s Encrypt and your domain name.
    2. Your reverse proxy should have ports 443 and 80 exposed, but should upgrade http requests to https.
    3. Add Jellyfin as a service and route in your reverse proxy’s config.

    On your router, forward port 443 to the outbound secure port from your PI (which for simplicity’s sake should also be port 443). You likely also need to forward port 80 in order to verify Let’s Encrypt.

    If you want to use Jellyfin while on your network and your router doesn’t support NAT loopback requests, then you can use the server’s IP address and expose Jellyfin’s HTTP ports (e.g., 8080) - just make sure to not forward those ports from the router. You’ll have local unencrypted transfers if you do this, though.

    Make sure you have secure passwords in Jellyfin. Note that you are vulnerable to a Jellyfin or Traefik vulnerability if one is found, so make sure to keep your software updated.

    If you use Docker, I can share some config info with you on how to set this all up with Traefik, Jellyfin, and a dynamic dns services all up with docker-compose services.

  • OP, I have been facing the same situation as you in this community recently. This was not the case when I first joined Lemmy but the behaviour around these parts has started to resemble Reddit more and more. But we'll leave it at that.

    I think I have a solution for you if you're willing to spend $2-$3 a month - set up a VPS and run a Wireguard server on it. Run clients on your devices and the raspberry pi and connect to it.

    As for your LAN: from the discussion you linked, it seems that Jellyfin will use the CAs present in the OS trust store. That's not very hard to do on Linux but I guess if you have to do it on Android you'd have some more trouble. In either case, using a reverse-proxy (I like HAProxy but I use it at work and it might be more enterprise than you need, for beginners Caddy is usually easier) will fix the trouble you're having with your own CA and self-signed certs.

    I am interested in the attack vector you mentioned; could you elaborate on the MITM attack?

    Unfortunately, if you don't have control over your network, you cannot force a DNS server for your devices unless you can set it yourself for every individual client. If I assume that you can do that, then:

    1. Set up DNS server on Pi
    2. Set up CA on Pi
    3. Create root CRT, CSR and server certs from it (bare-minimim setup)
    4. Copy over this stuff to Jellyfin image/VM, and copy root cert to clients trust store.
    5. Run reverse proxy in front of Jellyfin and configure the correct IP address of the reverse proxy with an A record in your DNS server.
    6. Configure reverse-proxy with server/application cert.
    7. Use RethinkDNS on Android to pass everything through the wireguard server hosted on the VPS, and set private DNS to the DNS server hosted on the Pi.

    I think that should do it. This turned out more complicated than I imagined (it's more of a brain dump at this point), feel free to ask if it is overwhelming.

    • OP, I have been facing the same situation as you in this community recently. This was not the case when I first joined Lemmy but the behaviour around these parts has started to resemble Reddit more and more. But we’ll leave it at that.

      I've noticed that behavior is split between communities. Lemmy gets a bit weird because communities are usually hyper-specialized, and sometimes instances themselves cultivate different cultures (e.g. lemmy.ml is usually for privacy enthusiasts, since that's where c/privacy is hosted). That, with the addition of specific idols for each community (e.g. Louis Rossmann for the selfhosted community) affects how each community behaves. That's my theory, anyways.

      I am interested in the attack vector you mentioned; could you elaborate on the MITM attack?

      Basically the "this website is not secure" popup you see in your browser is sometimes due to the website using a self-signed cert. There's no way to verify that that cert is from the website itself or from an attacker trying to inject their own cert, since there's no CA attached to the cert. If an attacker injects their own self-signed cert, they can use that to decrypt your HTTPS traffic (since your browser will be encrypting using their cert) and then forward your traffic along to the real website so that from your perspective (minus the warning screen) nothing is wrong. I'm oversimplifying this, but that's basically how it works.

      Unfortunately, if you don’t have control over your network, you cannot force a DNS server for your devices unless you can set it yourself for every individual client.

      I forgot to mention in this post, but because of browser fingerprinting reasons I don't want to use a custom DNS. Thanks for the suggestion though!

  • I mentioned a firewall in your last post, but didn't get a chance to respond to what you said and saw this post.

    You can use something like opnsense or pfsense (or something similar) behind your current router/modem.

    If you have a router/modem combo, it would look like this.

    Wall cable (fiber, copper etc) > Router/Modem > Firewall/Router device with opnsense installed on it > wireless or wire connected devices.

    The hardware will cost money up front, the OS for it is free.

    You can use this to isolate your devices from the router/modem that is the cause of concern, and have a secure connection to your jellyfin server. Eliminating the need for signed certificates.

    Don't over think it. You can secure your network without making it excessively complicated.

    If you have a raspberry pi you can also experiment with running the firewall on that (just as a test since there aren't official builds for the RPI that I know of) and pentest from whatever device you use to do so connected to your router provided by your ISP or however you want to test it before you go out and buy hardware.

    Just to be clear I wasn't trying to be any sort of way with my question previously, but wanted a better understanding of what you meant by not trusting your device.

    Edit: So a little side note, there are options to increase security when using something like opnsense. You can use freeradius to harden the access requirements to your network.

    Since you mentioned pen testing but also seem to say that your knowledge of networking is a little bit limited, it may be a bit more involved than you're ready for. The thing is (and this is by no means a knock on you) if you are doing pen testing then you definitely need to increase your knowledge on networking. Those two things kinda go hand in hand. If you don't understand networking but you are trying to pen test a network, then how do you know what you are doing is actually effective? I suspect you may understand a bit more than you think you do, so try to broaden your knowledge more!

    https://wiki.freeradius.org/

    There's something to check out just to get some concepts. You can do plenty of things to harden your security that could give you the comfort you need without defaulting to encrypted connections over LAN.

    • Thank you for this!

      Is OPNsense like dd-wrt or OpenWrt?

      The thing is (and this is by no means a knock on you) if you are doing pen testing then you definitely need to increase your knowledge on networking.

      I have background in Wi-Fi hacking and LAN attacks, and I understand the structure of networking (LAN, WAN, layers of the internet, DNS, CAs, etc.). My head starts to hurt when RADIUS is involved, ad hoc networking (which I understand the concepts of, just not how it works. I want to learn this first), mDNS, and other complicated topics. I'm trying to push past those mental roadblocks and learn as best I can, but it's a tricky topic!

      https://wiki.freeradius.org/

      There’s something to check out just to get some concepts. You can do plenty of things to harden your security that could give you the comfort you need without defaulting to encrypted connections over LAN.

      Thank you! I'll definitely check this out. You've been a huge help!

  • I remember you were worried about your ISP messing things up for you, hence the VPN. I would recommend creating a "Virtual Machine" that does all of your downloading to whatever hard drive you're using. That VM can have proton installed. Then, on your regular computer (not within the VM), you can host Jellyfin with no VPN involved, making it accessible at 192.168.0.xx.

    I think this hits your goals without needing to expose Jellyfin to the Internet. Plus it has minimal technical complexity. Your downloading traffic will be VPN protected, but Jellyfin will still be accessible to your local network.
    edit: You can set up a password for Jellyfin, protecting it from your internal threats.

    edit2: You can use letsencrypt to create a certificate that picky clients will accept. Buy a domain, any domain, and configure the "A record" to point to 192.168.0.xx (your Jellyfin IP). Then tell your client to go to whatever domain you get, like "luigiliterallydidnothingwrongplzfree.com", then the client will have to use the internet to ask DNS what the IP address is, but after that, it will just use your local network.

    edit3: Since you just have the raspberry PI, instead of using a Virtual Machine, you could have 2 separate SD cards. One only has the downloader and VPN installed, the other only has Jellyfin installed (no VPN). Then swap as needed.

76 comments