Skip to content

Instantly share code, notes, and snippets.

@ShipkaChalk
Last active May 5, 2024 19:33
Show Gist options
  • Star 27 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save ShipkaChalk/629fdc42dad781776d2007fc502188f3 to your computer and use it in GitHub Desktop.
Save ShipkaChalk/629fdc42dad781776d2007fc502188f3 to your computer and use it in GitHub Desktop.
Plex Hetzner workaround using Docker.

Hey, here is how you can route all plex traffic via wireguard out of another VPS, this can be used for any container but was inspired by the recent Hetzner block Plex put in place.

And no not all of us are using it for nefarious means, sometimes people don't have room for a home server.

Why docker? I prefer it as it keeps items separated and cleaned. It also allows for quickly moving configurations around from server to server if need be.

  1. Get yourself a VPS
  2. Install docker
  3. Create this docker-compose.yml
version: '3'
services:
  wireguard:
    image: linuxserver/wireguard
    container_name: wireguard
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Etc/UTC
      - SERVERURL=111.111.111.111 # Replace with your server's public domain or IP
      - SERVERPORT=51820
      - PEERS=plexServer # Replace with peer names, this is chosen by you. Do not use any special characters like _
      - PEERDNS=9.9.9.9
      - INTERNAL_SUBNET=10.13.13.0
      - LOG_CONFS=true
    ports:
      - "51820:51820/udp"
      - "32400:32400"
    volumes:
      - /root/wireguard/config:/config
    sysctls:
      - net.ipv4.conf.all.src_valid_mark=1
    restart: unless-stopped
  1. Bring the docker container up once.
  2. Stop the container
  3. Update the main config wg0.conf so that under [Interface] but before [Peer] you include:
  4. Update the --to-destination X.X.X.X to point to the Ip of the peer below.
[Interface]
Address = ...
etc...

PostUp = iptables -A FORWARD -i %i -j ACCEPT
PostUp = iptables -A FORWARD -o %i -j ACCEPT
PostUp = iptables -t nat -A POSTROUTING -o eth+ -j MASQUERADE
PostUp = iptables -t nat -A PREROUTING -p tcp --dport 32400 -j DNAT --to-destination 10.13.13.2 # IP Of peer below

PostDown = iptables -D FORWARD -i %i -j ACCEPT
PostDown = iptables -D FORWARD -o %i -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -o eth+ -j MASQUERADE
PostDown = iptables -t nat -A PREROUTING -p tcp --dport 32400 -j DNAT --to-destination 10.13.13.2 # IP Of peer below

[Peer]

  1. Update the 10.13.13.2 in the above to be the IP of your peer_plexServer. This will forward port traffic from 32400 to that internal peer.
  2. Visit /root/wireguard/config and find the .conf file for the plexServer peer.
  3. Copy that information down.
  4. Bring the container back up with docker cmpose up
  5. You're done for the VPS!

On the hetzner server

  1. Install docker
  2. Create a directory to hold the goods, in the below I created /home/shipka/PlexWireguard
  3. Create /home/shipka/PlexWireguard/wireguard-client/wg_confs/wg0.conf

This file will be what is generated by the VPS you just need to add in the PostUp, PreDown , PostUp and PreDown

[Interface]
Address = 10.13.13.2
PrivateKey = 
ListenPort = 51820
DNS = 10.13.13.1

PostUp = iptables -t nat -A POSTROUTING -o wg+ -j MASQUERADE
PreDown = iptables -t nat -D POSTROUTING -o wg+ -j MASQUERADE
PostUp = FORWARDEDPORT=32400; iptables -A INPUT -i wg0 -p udp --dport $FORWARDEDPORT -j ACCEPT; iptables -A INPUT -i wg0 -p tcp --dport $FORWARDEDPORT -j ACCEPT;
PreDown = FORWARDEDPORT=32400; iptables -D INPUT -i wg0 -p udp --dport $FORWARDEDPORT -j ACCEPT; iptables -D INPUT -i wg0 -p tcp --dport $FORWARDEDPORT -j ACCEPT;

[Peer]
PublicKey = 
PresharedKey = 
Endpoint = END POINT OF VPS:51820
AllowedIPs = 0.0.0.0/0 # You might want to remove the  , ::/0 if you have issues using IPv6
  1. Create the docker-compose.yml
  2. Make sure your volumes in plex line up and the volumes for the wireguard line up.
services:
  wireguard:
    image: lscr.io/linuxserver/wireguard
    container_name: wireguard
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Etc/UTC
    volumes:
      - /home/shipka/PlexWireGuard/wireguard-client:/config
      - /lib/modules:/lib/modules
    sysctls:
      - net.ipv4.conf.all.src_valid_mark=1
    ports:
      - 32400:32400
    restart: unless-stopped

  plex:
    image: linuxserver/plex
    container_name: plex
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Etc/UTC
      - VERSION=docker
      - PLEX_CLAIM= #lasts 4 minutes get from plex.tv/claim
    volumes:
      - /home/shipka/PlexWireGuard/config:/config
      - /data/tv:/tv
      - /data/downloaded:/movies
    network_mode: service:wireguard
    restart: unless-stopped

And that should be it! Bring it up with docker compose up and visit VPS:32400 and you’ll see your plex container. Finally make sure to manually specify port 32400 (Or which ever port you used in docker for plex) in the plex remote access settings.

Trouble Shooting

Follow the steps below in order, post a comment saying where you get to if it fails. ( Like 2.a )

exec into the containers on Hetzner.

docker exec -it plex /bin/bash

a. Do curl localhost:32400 you should see some html coming back. If it's not plex isn't up. b. Do curl icanhazip.com to make sure it's returning the VPS ip. If it's not then your wireguard tunnel is not connected. c. Do curl 8.8.8.8 this should return active pings. If it does not there is not internet connection at all.

Repeat this for

docker exec -it wireguard /bin/bash

a. Do curl localhost:32400 you should see some html coming back. If it's not then the plex container is not connected to the wireguard container. b. Do curl icanhazip.com to make sure it's returning the VPS ip. If it's not then your wireguard tunnel is not connected. c. Do curl 8.8.8.8 this should return active pings. If it does not there is not internet connection at all.

Then on the VPS

docker exec -it wireguard /bin/bash

a. curl icanhazip.com to make sure that wireguard container is reaching the outside world you should see the VPS ip. b. Do curl 8.8.8.8 this should return active pings. If it does not there is not internet connection at all. c. curl localhost:32400 you should see the plex html. If you don't then you need to make sure you've done the forward ports part on the Hetzner.

On the VPS a. Outside of the docker instance, do wg show look to see if the peer has connected.

b. curl localhost:32400, you should see the plex html. If you don't then you need to forward the ports on the wg0.conf of the VPS.

On your home machine: a. Visit VPS:32400 you should get to plex, if you do not then on the VPS it's self you need to open the ports or make sure ufw etc is not blocking them.

@sovajri7
Copy link

Thank you for offering your help. I followed your instructions, but Im not yet able to connect to plex. Going through the troubleshooting, Im running into problems starting at 1.

1.a I am getting xml data instead of html

<?xml version="1.0" encoding="UTF-8"?>
<MediaContainer size="24" allowCameraUpload="0" allowChannelAccess="1" allowMediaDeletion="1" allowSharing="1" allowSync="0" allowTuners="0" backgroundProcessing="1" companionProxy="1" countryCode="" diagnostics="logs,databases,streaminglogs" eventStream="1" friendlyName="66633dcda674" hubSearch="1" itemClusters="1" livetv="7" machineIdentifier="a7d10623cf088b7eaebbc422c8e95afc8f9c59ed" mediaProviders="1" multiuser="1" musicAnalysis="2" myPlex="1" myPlexMappingState="unknown" myPlexSigninState="none" myPlexSubscription="0" platform="Linux" platformVersion="5.15.0-86-generic" pluginHost="1" pushNotifications="0" readOnlyLibraries="0" streamingBrainVersion="2" sync="1" transcoderActiveVideoSessions="0" transcoderAudio="1" transcoderLyrics="1" transcoderPhoto="1" transcoderSubtitles="1" transcoderVideo="1" transcoderVideoBitrates="64,96,208,320,720,1500,2000,3000,4000,8000,10000,12000,20000" transcoderVideoQualities="0,1,2,3,4,5,6,7,8,9,10,11,12" transcoderVideoResolutions="128,128,160,240,320,480,768,720,720,1080,1080,1080,1080" updatedAt="1700222866" updater="1" version="1.32.7.7621-871adbd44" voiceSearch="1">
<Directory count="1" key="actions" title="actions" />
<Directory count="1" key="activities" title="activities" />
<Directory count="1" key="butler" title="butler" />
<Directory count="1" key="channels" title="channels" />
<Directory count="1" key="clients" title="clients" />
<Directory count="1" key="devices" title="devices" />
<Directory count="1" key="diagnostics" title="diagnostics" />
<Directory count="1" key="hubs" title="hubs" />
<Directory count="3" key="library" title="library" />
<Directory count="3" key="livetv" title="livetv" />
<Directory count="3" key="media" title="media" />
<Directory count="3" key="metadata" title="metadata" />
<Directory count="1" key="neighborhood" title="neighborhood" />
<Directory count="1" key="playQueues" title="playQueues" />
<Directory count="1" key="playlists" title="playlists" />
<Directory count="1" key="resources" title="resources" />
<Directory count="1" key="search" title="search" />
<Directory count="1" key="server" title="server" />
<Directory count="1" key="servers" title="servers" />
<Directory count="1" key="statistics" title="statistics" />
<Directory count="1" key="system" title="system" />
<Directory count="1" key="transcode" title="transcode" />
<Directory count="1" key="updater" title="updater" />
<Directory count="1" key="user" title="user" />
</MediaContainer>

1.b curl: (6) Could not resolve host: icanhazip.com

1.c curl 8.8.8.8 returns nothing. Prompt does not return unless I ctrl-c

Hi, I've written a gist update of this because I was unable to get this working using wireguard container on server machine, you should take a look and lmk if still not working : https://gist.github.com/sovajri7/856f75833f3d8764c5dc36e19ff5d0aa

@Dokw0N
Copy link

Dokw0N commented Nov 18, 2023

Hey @sovajri7. I just followed your gist update. Its well written and very comprehensive. Unfortunately though Im still not able to get plex running. When I try to reach my VPS at port 32400 the connection times out. Through troubleshooting I can see that a from from within the plex container curl icanhazip.com throws: curl: (7) Couldn't connect to server
curling localhost:32400 returns xml data.

EDIT: From looking at the logs when starting wireguard I found an error: RTNETLINK answers: Permission denied
Searching for it online, some was hinting that adding the following to /etc/sysctl.conf would solve the problem. In my case this did not help either:

net.ipv6.conf.all.disable_ipv6 = 0
net.ipv6.conf.default.disable_ipv6 = 0
net.ipv6.conf.lo.disable_ipv6 = 0

@Dokw0N
Copy link

Dokw0N commented Nov 19, 2023

Update the 10.13.13.2 in the above to be the IP of your peer_plexServer. This will forward port traffic from 32400 to that internal peer.

Just to make sure, are we talking about the public, or the internal IP address @ShipkaChalk?

@parnexcodes
Copy link

Update the 10.13.13.2 in the above to be the IP of your peer_plexServer. This will forward port traffic from 32400 to that internal peer.

Just to make sure, are we talking about the public, or the internal IP address @ShipkaChalk?

It's the IP address in your peer config.
Try connecting with your peer config on your windows/mac wireguard client.

Your ports are probably blocked. Send all the configs here.

@Dokw0N
Copy link

Dokw0N commented Nov 19, 2023

Thanks @parnexcodes
Here are my configs:

VPS (Server)
compose

version: '3'
services:
  wireguard:
    image: linuxserver/wireguard
    container_name: wireguard
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Etc/UTC
      - SERVERURL=HETZNER_IP # Replace with your server's public domain or IP
      - SERVERPORT=51820
      - PEERS=plexServer # Replace with peer names, this is chosen by you. Do not use any special characters like _
      - PEERDNS=9.9.9.9
      - INTERNAL_SUBNET=10.13.13.0
      - LOG_CONFS=true
    ports:
      - "51820:51820/udp"
      - "32400:32400"
    volumes:
      - /home/user/repos/plexwireguard/config:/config
    sysctls:
      - net.ipv4.conf.all.src_valid_mark=1
    restart: unless-stopped

wg0

[Interface]
Address = 10.13.13.1
ListenPort = 51820
PrivateKey = ServerPrivateKey

PostUp = iptables -A FORWARD -i %i -j ACCEPT
PostUp = iptables -A FORWARD -o %i -j ACCEPT
PostUp = iptables -t nat -A POSTROUTING -o eth+ -j MASQUERADE
PostUp = iptables -t nat -A PREROUTING -p tcp --dport 32400 -j DNAT --to-destination 10.13.13.2 # IP Of peer below

PostDown = iptables -D FORWARD -i %i -j ACCEPT
PostDown = iptables -D FORWARD -o %i -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -o eth+ -j MASQUERADE
PostDown = iptables -t nat -A PREROUTING -p tcp --dport 32400 -j DNAT --to-destination 10.13.13.2 # IP Of peer below

[Peer]
# peer_plexServer
PublicKey = HetznerPublicKey
PresharedKey = PresharedKey
AllowedIPs = 10.13.13.2/32

Hetzner (Client)
compose

services:
  wireguard:
    image: lscr.io/linuxserver/wireguard
    container_name: wireguard
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Berlin
    volumes:
      - /home/user/plexwireguard/wireguard-client:/config
      - /lib/modules:/lib/modules
    sysctls:
      - net.ipv4.conf.all.src_valid_mark=1
    ports:
      - 32400:32400
    restart: unless-stopped

  plex:
    image: linuxserver/plex
    container_name: plex
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Berlin
      - VERSION=docker
      - PLEX_CLAIM= #lasts 4 minutes get from plex.tv/claim
    volumes:
      - /home/user/plexwireguard/plex/config:/config
      - /mnt/gmedia:/gmedia
    network_mode: service:wireguard
    restart: unless-stopped

wg0

[Interface]
Address = 10.13.13.2
PrivateKey = HetznerPrivateKey
ListenPort = 51820
DNS = 8.8.8.8

PostUp = iptables -t nat -A POSTROUTING -o wg+ -j MASQUERADE
PreDown = iptables -t nat -D POSTROUTING -o wg+ -j MASQUERADE
PostUp = FORWARDEDPORT=32400; iptables -A INPUT -i wg0 -p udp --dport $FORWARDEDPORT -j ACCEPT; iptables -A INPUT -i wg0 -p tcp --dport $FORWARDEDPORT -j ACCEPT;
PreDown = FORWARDEDPORT=32400; iptables -D INPUT -i wg0 -p udp --dport $FORWARDEDPORT -j ACCEPT; iptables -D INPUT -i wg0 -p tcp --dport $FORWARDEDPORT -j ACCEPT;

[Peer]
PublicKey = ServerPublicKey
PresharedKey = PresharedKey
Endpoint = VPS_SERVER_IP:51820
AllowedIPs = 0.0.0.0/0

I basically cannot reach the internet from within the containers. Neither icanhazip nor 8.8.8.8 can successfully be curled.

@ShipkaChalk
Copy link
Author

If you can't reach the internet from within the Wireguard container on the VPS then you have a problem as this should always get out to the internet. Looks like an issue on step 3 of the troubleshooting.

If you're on a box with other items on, make sure you don't have any firewalls etc breaking it. I'd recommend spinning up a quick box on something like digital ocean and test if you can get it working there.

@Dokw0N
Copy link

Dokw0N commented Nov 19, 2023

No sorry I should have described this better. Wireguard on the VPS can reach the internet from within Docker without an issue.
My problems are on the Hetzner side. As VPS:32400 (from my home computer) leads to a timeout I tend to check the Plex container on Hetzner to curl domains and IPs for troubleshooting.

EDIT: Are we actually talking about pinging or curling 8.8.8.8 (from within VPS wg container)?
The latter just waits for further input it seems, pinging is successful with 0% packets lost.

@ShipkaChalk
Copy link
Author

I don't know enough about DNS's but it's possible that as you're using PEERDNS=9.9.9.9 it won't let you hit 8.8.8.8. Did you try with PEERDNS=auto? If you can ping Icanhazip and you get the IP back then your VPS Should be okay.

What you need to do now is check that the wireguard on your home machine is connected with the VPS. You can do this by going to the VPS and exec'ing into the container, sudo wg show wg0 should then hopefully show your home vps trying to connect, if you see nothing then it looks like it's just not being connected to.

What you can try for debugging if connecting directly to the vps from your home machine using the wire guard client you can either create a new config with PEERS=plexServer,homeMachine or try and use the plex server config.

If your home machine can connect and your ip is changed to the VPS then we can narrow down the issue to the docker containers on your home machine.

@Dokw0N
Copy link

Dokw0N commented Nov 21, 2023

Okay, so I tried to connect to wg from my home computer with windows: as soon as I connect to the network my internet connection is gone.
Apart from that I found out that ionos has a hardware firewall in place that you need to configure via the cloudpanel. I did, however I am still now able to connect to plex via browser at ionos_ip:32400.
Troubleshooting throught your points @ShipkaChalk I am now only left with one problem on the VPS side (3c): if I exec into the wg container on the vps, I cannot curl localhost:32400. Getting a curl: (7) Failed to connect to localhost port 32400 after 0 ms: Couldn't connect to server.
When Im testing, I actually uninstall ufw, and allow all traffic through iptables, flushing any residual rules. So at this point I have no idea why port 32400 is not accessible.

@ShipkaChalk
Copy link
Author

Well if you connected to wg from your home machine and lost internet connection then it means your WG on the VPS is not working.

Please try on another VPS, you can spin up a digital ocean for an hour for pennies.

@dmnchild
Copy link

Can anyone comment on upgrading? I thought it was as simple as stopping and starting the container but that didnt work. I did the docker pull and it seems to have grabbed the latest but doesnt seem to be using it. Looks like there was a 2/24/2024 update im not able to apply.

@ShipkaChalk
Copy link
Author

@dmnchild
run

docker compose pull

docker compose down

docker compose up

It can take a few minutes for plex to come back due to the reconnection with the wireguard.

@dmnchild
Copy link

dmnchild commented Feb 18, 2024

@ShipkaChalk
edit: docker compose -p plex pull worked. seems all good, thanks for setting me in right direction!

@Iliannnn
Copy link

Iliannnn commented Mar 9, 2024

Hey, I have some questions. I've never done something like this.

So, in step three:

  • What should SERVERURL be set to? Should this be set to the VPS IP or the Hetzner server IP?
  • Should INTERNAL_SUBNET=10.13.13.0 be changed to another value because this IP gets copied over in the wg0.conf file, if yes to which IP?

In step four:

  • What IP should come after --to-destination? The VPS IP or the Hetzner IP?
  • The following PostUp and PostDown lines are in the wg0.conf file by default under PrivateKey, should those be replace by the ones mentioned in step four or should those stay there?
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth+ -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth+ -j MASQUERADE

Thank you for the help in advance

@sovajri7
Copy link

sovajri7 commented Mar 9, 2024

@Iliannnn maybe my gist will help you better as I modified it a little bit to be easier for beginners, just copy/paste and fill your informations : https://gist.github.com/sovajri7/856f75833f3d8764c5dc36e19ff5d0aa

@Iliannnn
Copy link

Iliannnn commented Mar 9, 2024

@Iliannnn maybe my gist will help you better as I modified it a little bit to be easier for beginners, just copy/paste and fill your informations : https://gist.github.com/sovajri7/856f75833f3d8764c5dc36e19ff5d0aa

I will check it out, thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment