Wireguard drains battery on video streaming

Hi folks!

I have an issue with VPN and Jellyfin.

First, let me detail my current setup. I have a Truenas server with Nextcloud, Jellyfin and Nginx. Nextcloud stores private documents and Jellyfin contains media that is not private (I don’t mind if it an attacker is able to read what’s inside Jellyfin). I also have a Fritzbox router, which contains a Wireguard server by default. When I’m not at home, I use Wireguard to have access to my Fritzbox, it assigns me a local IP and then I’m able to access to Nextcloud and Jellyfin. No port is directly forwarded from router to Truenas. Only a VPN port is open on router, and Wireguard is on the router itself.

All of this works well, BUT…

When I’m out and streaming video on Jellyfin my laptop gets really hot and battery drains fast. I know this is due to the intensive CPU work cyphering and decyphering video data over the VPN.

I want to explain now the solution I have thought for this and I’d like to have your opinion:

Wireguard assigns a local IP when I activate VPN on phone, laptop or whatever. So I could open and forward a port from router to Nginx. Then, on Nginx, I could set filters (access list): if you have a public IP, then you can only access Jellyfin. If you have a local IP, you can access both Jellyfin and Nextcloud. This way, I could access Jellyfin from outside without the need of turning on VPN, while protecting the private data.

I know it’s riskier than using a VPN for everything and Nginx will become a critical point in my setup, that’s why I’m here asking for help. Is the risk worth for that benefit? Is Nginx solid and safe enough to handle it? They are both on the same server, does it matter? Do you think there is a better solution for this?

Thanks for your help!

Security wise you’re in a great spot with WG being the single point of access into the network.

Personally I would not open Jellyfin to the Internet. With their entire leadership essentially stepping down the future is a bit uncertain. They may fall behind on security patches, they may be fine, but as it stands it’s a bit of a gamble. Plus, if Jellyfin gets compromised, it will be used as a jumpbox into your other systems in the private network.

With that being said, there are more secure options than simply opening up Jellyfin to the entire world and relying on their up to date patching. Best I can think of right now that doesn’t involve some sort of Wireguard (Tailscale uses WG behind the scenes, so you gain nothing by using it) would be mTLS client authentication.

Assuming you have Nginx acting as a reverse proxy for your Jellyfin, the way it works is it authenticates your web browser before allowing any sort of access. If you have a suitable certificate you get proxied and can authenticate into Jellyfin with your normal user and pass. For everyone else off the Internet, they don’t even know what’s behind Nginx since they will be denied connection.

A sample configuration would look something like this:

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name jellyfin.example.com;

    ssl_certificate     /etc/letsencrypt/live/jellyfin.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/jellyfin.example.com/privkey.pem;

    # Require a client certificate signed by your private CA.
    ssl_client_certificate /etc/nginx/mtls/jellyfin-client-ca.crt;
    ssl_verify_client on;
    ssl_verify_depth 2;

    location / {
        proxy_pass http://127.0.0.1:8096;
.
.
.

So it’s a pretty standard reverse proxy setup, the different bits being these 3 lines:

# Require a client certificate signed by your private CA.
ssl_client_certificate /etc/nginx/mtls/jellyfin-client-ca.crt;
ssl_verify_client on;
ssl_verify_depth 2;

You kind of need a self hosted Certificate Authority to do this. You have to create a SSL certificate that needs to be signed by the CA and you’ll need to install in your browser, and put the CA public (not the private part!) file in the mtls folder.

Essentially your own CA signs whatever client certificates you want, and Nginx is instructed by those lines to allow only clients that present a not expired, valid certificate signed by your CA.

I’ll definitively investigate how to do this, it looks like a pretty safe alternative. Thanks!

Interesting. I’m also using Jellyfin. Have there been any public news about this?

Do I understand correctly that such a solution would not work for any Jellyfin apps on Ios?

Oh yes, there’s lots of news on this, too many to link here. Just search on Google.

I am not familiar with the Jellyfin apps on Ios, It would be an interesting experiment to explore.

how about going with Emby instead of worrying about the security posture of Jellyfin?

I wouldn’t wide open any self hosted web app to the Internet, no matter who’s making it. The risk is simply too great if it’s part of your home lab. And everyone out there had security issues at one point or another.

VPN is the better solution from a security standpoint. mTLS is an acceptable compromise.

I would trust Emby more than Jellyfin given recent developments. And there is always the “wife” factor. If there is a need to stream from the outside by anyone like the wife or a family member putting it behind a VPN would make it unworkable for most people and that will lead to complains and how much of pos the system that you built is and why dont we go with xyz streaming service since its much simpler. I speak from experience on this.

I don’t think the encryption is your issue. I think because you have a home LAN address, Jellyfin sees you as on the home network and isn’t implementing a bit rate cap. That means your laptop is potentially decoding something like a full-fat 4K HEVC 10-bit stream (or whatever you run natively at home), likely partly or completely in software. The easy check is to open dashboard/sessions while streaming. It shows direct play or transcode and the actual bitrate. If that’s the cause, the fix is in settings/playback. Lower the “home network” quality, not the internet one. The internet cap never fires for you because of the VPN address.

Thanks, I will have a look to this configuration. Last time I checked it showed “direct play”. That means that the video is sent at maximum rate, causing more CPU work and it should instead be transcoded server side to a lower rate to have less data transferred, right?