Wireguard Proxy Service for Pterodactyl

- 4 min to read


Hey 👋!

I had some compute capacity problem a while ago. A friend wanted to play heavily modded Minecraft with some friends and asked me if I could provide a server. Because I didn’t want to buy a new Public VPS I looked into hosting them on my own hardware. I didn’t have a publicly accessible IP-Address tho… A proxy service was needed. I decided to use a WireGuard network connected to my mid-tier Public VPS.

The whole setup consists of 3-Parts:

After setting those up, he could finally play lag free on a dedicated node with plenty of RAM and compute.

🌐 The public node

First step was installing WireGuard on the public node and set-up some keys to make connections possible.

Most of my servers run Debian or a Debian-Based Distro so install WireGuard is as simple as sudo apt install wireguard. To make the clients able to connect to WireGuard I need to generate a Key-Pair, which the public node uses to identify itself.

Create a config file at /etc/wireguard/wg0.conf:

(umask 077 && printf "[Interface]\nPrivateKey = " | sudo tee /etc/wireguard/wg0.conf > /dev/null)

And generate a key-pair. The public key will be outputted to your shell (Will look something like: GwrLJ9tAUFRBquARBBemSj05/Q5SmBmZCOIm/FSQinA=) remember/save it, you’ll need it to connect your client nodes. Remember, you can always regenerate it from your private key if you ever loose it. Your private key will be appended to your config file.

wg genkey | sudo tee -a /etc/wireguard/wg0.conf | wg pubkey | sudo tee /etc/wireguard/publickey

Add a ListenPort and an Address to your config using nano /etc/wireguard/wg0.conf or your tool of choice.

[Interface]
PrivateKey= CLQo7eg4bnfXigEIm28vR+2Bp4jMMHroT2fcxWtXIkw=
ListenPort = 55107
Address = 192.168.4.1

# optional - this will allow WireGuard to work as a gateway VPN e.g. client nodes can access the internet through the public node
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

It’s ready for launch now! 3… 2… 1… Liftoff!

sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0

These might also be helpful for managing WireGuard.

sudo systemctl stop wg-quick@wg0
sudo systemctl restart wg-quick@wg0
wg syncconf wg0 <(wg-quick strip wg0)

🧑‍💻 The client nodes

Of course I’ll need to install WireGuard again on the client node: sudo apt install wireguard I’ll also need another keypair. You know it by now:

  • Create config: (umask 077 && printf "[Interface]\nPrivateKey = " | sudo tee /etc/wireguard/wg0.conf > /dev/null)
  • Create keypair: wg genkey | sudo tee -a /etc/wireguard/wg0.conf | wg pubkey | sudo tee /etc/wireguard/publickey (Don’t forget to remember your public key, you’ll need it.)

Now it gets interesting again!

I’ll need to connect the public node with the client nodes. Editing /etc/wireguard/wg0.conf again:

[Interface]
PrivateKey = <private key should already be here>
Address = 192.168.4.2 # This can be replace with the IP you want your client to have

# fixes broken handshakes for example ones with minecrafts new Authentication servers: "Minecraft: Authentication servers are down. Please try again later. sorry! - https://api.minecraftservices.com/publickeys"
PostUp = iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
PostDown = iptables -t mangle -D FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

[Peer]
PublicKey = <paste the public key from your server here>
AllowedIPs = 192.168.4.1/32 # /32 referes to the netmasks size - it allows only this specific IP to connect.
# AllowedIPs = 0.0.0.0/0, ::/0 # This can be done to route the whole internet connection through the tunnel, optional "PostUp" and "PostDown" on the public node need to be enabled
Endpoint = <public IP of your public node>:55107
PersistentKeepalive = 25

That’s it!

sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0

🛰️ The proxy service

To make sure both servers are configured correctly. We’ll ping 192.168.4.2. This can be done on either the wg-server or the wg-client (but change the IP accordingly).

The proxy of course runs on the public node, so that’s where it’s configured. Now I went down two different paths: IP-Tables routing and an Nginx proxy. I had some issues with IP-Tables after longer testing so I’ll start with Nginx even though it’s (for me not significantly) slower.

Nginx Proxy

It’s pretty straight forward. If you haven’t already install Nginx. Create a link to your new config files in /etc/nginx/nginx.conf

stream {
    include /etc/nginx/services-enabled/*;
}

Create a config file at /etc/nginx/servicees-enabled/example

# service 1 - tcp
server {
    listen          25565;
    proxy_pass      192.168.4.2:25565; # will forward to your 
}

Reload service nginx reload. Done.

IP-Tables routing

If you already did Nginx your done. This is an alternative to Nginx proxying that’s a bit more complicated, but might be worth it if you need the speed/flexibility.

To allow IP forwarding edit ``/etc/sysctl.conf``` and uncomment the following line:

net.ipv4.ip_forward=1

Then apply the changes:

sudo sysctl -p
sudo sysctl --system

To keep the next few changes persistent across restarts I recommend installing the netfilter-persistent.service using sudo apt-get install iptables-persistent. This package will load rules from a directory, so you save your rules there using sudo iptables-save > /etc/iptables/rules.v4 any time you know you have made some WORKING changes.

Now configure the actual forwarding rules. For every port you’ll need two rules. One for incoming and one outgoing traffic:

# Forward traffic from eth0 to wg0 on specified ports
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 25565 -j DNAT --to-destination 192.168.4.2
# Forward traffic back to eth0 from wg0 on specified ports
sudo iptables -t nat -A POSTROUTING -o wg0 -p tcp --dport 25565 -d 192.168.4.2 -j SNAT --to-source 192.168.4.1

That’s it, don’t forget to test your changes and then save them.