Exposing Services Behind a Firewall

Synopsis

Sometimes you may find yourself in a situation in which you would like to host a service but sometimes you're stuck behind a double NAT, or even just a firewall in which you do not control all of the rules for. Here I'm going to show you how to use Wireguard VPN to finagle around this issue and simply give your private server a public IP address. Important note: in order for this to work, you will need a publicly accessible VPS, preferably with a static IP address, i would recommend either AWS Lighsail or Linode as they are both cost-effective options with their cheapest tiers being bout $3.50/mo and $5/mo respectively (I like Linode's speed more, they aren't paying me to say this although I wish they were).

Initial Setup

First off, you're going to want to ensure that you have wireguard installed on both ends, thankfully wireguard is upstream in the linux kernel now so you should be able to install it with the package manager of your choice, here I'm going to use Ubuntu server on both ends since it's pretty ubiquitous, although most of these commands will be the same across operating systems with the exception of package installs. 

sudo apt install wireguard wireguard-tools

Run the following command on both ends to generate your public and private keys

wg genkey | tee privatekey | wg pubkey > publickey

From here you're going to create files names /etc/wireguard/wg0.conf on both ends that look like the following:

VPS:

[Interface]

PrivateKey = <privatekey>

ListenPort = <UDP_Port> (ex. 51820)

Address = <Desired_Gateway_IP_ADDR> (ex. 192.168.67.1)


[Peer]

PublicKey =  <Public_Key_of_HomeServ>

AllowedIPs = <Desired_HomeServ_IP> (ex. 192.168.67.2/32)

Home Server:

[Interface]

PrivateKey = <privatekey>

Address = <Desired_HomeServ_IP>  (ex. 192.168.67.2)


[Peer]

PublicKey =  <Public_Key_of_VPS>

Endpoint = <Public_Socket_of_VPS> (ex. 1.2.3.4:51820)

AllowedIPs = <Private_IP_of_VPS>(ex. 192.168.67.1/32)

PersistentKeepalive = 25

Start and enable wireguard on both machines (this will start it on every boot as well).

sudo systemctl enable --now wg-quick@wg0

Try a Quick ping on either side to ensure connectivity is good. Then we're going to start up a netcat listener on your home server to simulate a service being run with the following command if you already have a service, skip this step but figure out what port it listens on. 

netcat -l 2200

On your VPS were going  to need to run the following command to grab a couple network parameters that will be important for Iptables rules (mainly your interface name). 

sudo ip -4 addr show scope global

Here we're gong to set up some IPtables rules on the VPS

sudo iptables -P FORWARD DROP

sudo iptables -A FORWARD -i eth0 -o wg0 -p tcp --syn --dport 2200 -m conntrack --ctstate NEW -j ACCEPT

sudo iptables -A FORWARD -i eth0 -o wg0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

sudo iptables -A FORWARD -i wg0 -o eth0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 2200 -j DNAT --to-destination 192.168.67.2

sudo iptables -t nat -A POSTROUTING -o wg0 -p tcp --dport 2200 -d 192.168.67.2 -j SNAT --to-source 192.168.67.1

I know this is a lot of IP tables rules and it may not make sense initially, but what it's doing is pretty simple: here's a sequential run down

Try the following command aimed at the public IP of your VPS

netcat -vz <VPS_Public_IP> 2200

If you are prompted with a success, then you are good to go!

Extra Credit

IPtables rules are not persistent, so if you would like these rules to survive a reboot install the netfilter-persistent package, save the rules, then enable the service. 

sudo apt install netfilter-persistent

sudo netfilter-persistent save

sudo systemctl enable --now netfilter-persistent