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.
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)
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:
(umask 077 && printf "[Interface]\nPrivateKey = " | sudo tee /etc/wireguard/wg0.conf > /dev/null)
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
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.
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.
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.