Using Wireguard on a VPS to access your NATted home network

At home I'm using the open source media center Jellyfin hosted on a homeserver to stream series to different clients and keep track of watched episodes. It works rather nicely except for some minor hickups on the Fire TV app.
One problem of hosting your media at home, though, is that you can't access it remotely by default. Thankfully, you have a few options to fix that issue.

Option 1 - The direct approach

The easiest approach would be to open up the port of Jellyfin (8096) on your router so that you would be able to directly access your media center from remote.
Additionally, assuming you don't have a static IP, you could set up a dynamic DNS service which would automatically update it's records to point to your current IP (I used this successfully with my own domain, Gandi's DynDns API + a script I found on Github).
As tempting as this seems, it is not really a good idea as your security would rely on the security of Jellyfin, which might be a good media center, but I wouldn't trust it enough to keep my network safe.

Option 2 - Using a local VPN

Your second option would be to setup a VPN on your homeserver, only open up the port of the VPN on your router and then dial in via that. From there you would be able to access Jellyfin without problems.
For convenience you could also setup a dynamic DNS for this solution.

Option 3 - Using a middleman VPN

Although the second option is totally valid and a nice solution, it is not viable for my usecase as I am currently using an internet connection which is NATting, meaning that I can not simply open up ports on my router as these are dynamically remapped and I'm sharing my public IPs with others.
If you find yourself in the same situation you're actually quite limited in the amount of options you have. In all cases you will need some kind of middleman to be able to connect to your home network.
The solution I came up with is hosting a VPN on my VPS, that i was already using for my website anyway.
The homeserver and the client trying to access the homeserver would then both connect to that VPN and could henceforth establish a connection to each other.

The solution

After some research I decided to go for Wireguard instead of OpenVPN as it seems to be a more modern and secure solution. Also i really liked the way you can configure Wireguard on the client side.
An easy way to host your own Wireguard VPN is to use Debian as your distribution, activate the testing repositories and install freedombox (Wireguard support is unfortunately not included in the stable freedombox yet).
Once installed you should be able to login into the web interface of freedombox and install Wireguard from there.

To connect a client you need to generate a private and a public key for them. The Windows implementation does it automatically for you, you just need to add a tunnel and you will get the public + private key. On Linux you can use the wg command to generate them as follows:

cd /etc/wireguard
umask 077
wg genkey > privatekey
wg pubkey < privatekey > publickey

For later configuration you will need to copy the corresponding contents of those files (see below).
Back in the web interface of freedombox you would need to add a new client and paste the public key of your client there.
Once you've done that, Wireguard will give you an IP address that you can use in your client configuration. We now got everything we need to setup the Wireguard client.
On Windows you just need to paste the configuration into your client, on Linux you will need to create a file like /etc/wireguard/wg0.conf.
My configuration looks as follows:

[Interface]
PrivateKey = #the clients private key
Address = #the ip address you got from the server + its mask, e.g. 192.168.178.1/32
DNS = 1.1.1.1 #any dns you like, seems to be required on windows

[Peer]
PublicKey = #the public key of the wireguard server, can be found in the freedombox interface
AllowedIPs = #the traffic you want to route through the server. could be 0.0.0.0/0. if you want to route all traffic including internet. if you just want it to connect your homeserver use the ips wireguard is handing out + approriate mask, e.g. 192.168.178.1/24
Endpoint = #domain/ip + port of your server
PersistentKeepalive = 25 #should be added for clients behind a natted connection

On Windows just use the UI to enable the connection, on Linux use the wg-quick command like: wg-quick up wg0

I did this for both my client and the homeserver and they were able to ping each other using the Wireguard IP after that. I was not able to access Jellyfin, though.

After quite a bit of search I found out that the firewall on freedombox is causing the issue. To allow clients to access Jellyfin via the VPN network, I sshed into the VPS hosting freedombox and added a new firewall service configuration at /usr/lib/firewalld/services/jellyfin.xml.

<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>Jellyfin</short>
  <description>The open source media center</description>
  <port protocol="tcp" port="8096"/>
  <port protocol="tcp" port="8920"/>
  <port protocol="udp" port="1900"/>
</service>

Then you can activate the service for the internal zone, which is the one used by Wireguard, with the following command:

sudo firewall-cmd --permanent --zone=internal --add-service=jellyfin

Finally, I also had to enable port masquerading in order to maintain the original ports when forwarded via Wireguard:

sudo firewall-cmd --zone=internal --add-masquerade --permanent

After reloading the firewall configuration, I was finally able to access Jellyfin from remote, yay!

sudo firewall-cmd --reload

I love this solution as I'm completely independent from the ISP I'm using now. Additionally, Wireguard is easily configured in a way so that only traffic targetted for my homeserver is routed via Wireguard and the rest stays untouched.
If you're using Gandi to buy your domains you can even setup URL forwarding to point a subdomain of yours to the Jellyfin server including the port, which makes it even more convenient.


You'll only receive email when Florian Schrofner publishes a new post

More from Florian Schrofner