Previously, I wrote about using a reverse SSH tunnel to escape a double NAT (specifically, the one provided by Xplornet). Without looking into why (maybe poor, intermittent connection and particularly awful uplink), my previous solution was not stable. Even with autossh, the connection kept dropping and not picking back up. I’m exclusively accessing this remotely, so when I notice the service being down I’m in pretty much the worst position to fix it.
Grab a public server with a static IP – for example a 5$/month Linode or Droplet. I’ve seen reference to cheaper international products, but I have no experience with them.

If you’ve picked Linode:
- deploy an Ubuntu image
- boot it up
- SSH to the machine
- do regular server stuff – make sure it’s up to date, generally read over Digital Ocean’s guide here for inspiration
Set up OpenVPN server
On the public computer (OpenVPN server/cloud instance):
The first time I did this, I set up OpenVPN myself. It’s not awful, there are some pretty comprehensive guides (like this one), but it definitely sucks enough to look for an alternative. Googling around shows two compelling public scripts – Nyr’s openvpn-install and Angristan’s version based off Nyr’s. Looking over the two, I ended up picking Angristan’s version without all that much consideration.
SSH to the machine and execute the script on your pubic server to set up the certificates and keys for your client. The defaults for the script all seem sensible – you don’t have to feel bad if you just mash enter until the name prompt comes up, then give your client a reasonable name
$ wget https://raw.githubusercontent.com/Angristan/OpenVPN-install/master/openvpn-install.sh
$ chmod +x openvpn-install.sh
$ ./openvpn-install.sh
You should notice at the end of the script execution a line that looks something like this:
...
Finished!
Your client config is available at /root/unifi-video-server.ovpn
If you want to add more clients, you simply need to run this script another time!
Take note of the location of your .ovpn file, as you’ll need it for the next step.
Set up OpenVPN client
On the private computer (machine that’s behind the double NAT):
On your client machine, get the OVPN configuration file that was generated from the previous step. scp is likely the easiest way to do this. From the client machine, you can retrieve the file like:
scp {server user}@{server host}:{remote path to ovpn} {local path}
For example:
$ scp root@37.48.80.202:/root/unifi-video-server.ovpn .
This will copy the file to the current directory on the machine. An extremely quick sanity check to ensure you can connect:
sudo openvpn unifi-video-server.ovpn
You should see:
Initialization Sequence Completed
once you do, you can ctrl + c your way out. If this wasn’t successful… something has gone wrong and you should fix it.
To make sure your client connects on start up:
- rename your
.ovpn file to be a .conf file
- move the
.conf file to /etc/ovpn
- Edit
/etc/default/openvpn to ensure AUTOSTART is configured to start your connection
At this stage, you have an OpenVPN server set up and an OpenVPN client that automatically connects to the server. All that’s left is to do the internet part.
Set up server traffic forwarding to client
On the public computer (OpenVPN server/cloud instance):
What we want now is to forward traffic that hits a particular port on the public server to the private computer. Not only that, but you want the private computer to think the traffic is coming from the public server, so it doesn’t respond directly to whoever sent the internet request.
First things first, toggle the server to allow forwarding traffic (if you don’t do this, you’ll end up insanely frustrated and convinced iptables is the devil:
sysctl -w net.ipv4.ip_forward=1
We need two pieces of information:
- the public WAN (internet) IP address of the server
- the virtual address of the OpenVPN client
Finding the public address can be done with:
$ curl ipinfo.io/ip
37.48.80.202
The virtual address of the OpenVPN client can be found in the OpenVPN status log with the client connected (see above for how to set up the connection for now). The log seems like it’s either in either /etc/openvpn/openvpn-status.log or /etc/openvpn/openvpn.log
$ cat /etc/openvpn/openvpn.log
OpenVPN CLIENT LIST
Updated,Sun Nov 5 01:37:33 2017
Common Name,Real Address,Bytes Received,Bytes Sent,Connected Since
unifi-video-server,37.48.80.202:49014,39837,52165,Sun Nov 5 01:02:05 2017
ROUTING TABLE
Virtual Address,Common Name,Real Address,Last Ref
10.8.0.2,unifi-video-server,37.48.80.202:49014,Sun Nov 5 01:36:54 2017
GLOBAL STATS
Max bcast/mcast queue length,1
END
Now we’ll need a source routing NAT rule and a destination routing NAT rule for every port that is going to be forwarded. They’ll look something like this:
iptables -t nat -A PREROUTING -d {server WAN IP} -p tcp --dport {port} -j DNAT --to-dest {client virtual address}:{port}
iptables -t nat -A POSTROUTING -d {client virtual address} -p tcp --dport {port} -j SNAT --to-source {server virtual address}
Practically speaking, with the following:
- public server whose Internet accessible IP address is
37.48.80.202
- public server whose OpenVPN virtual address is
10.8.0.1
- private computer whose OpenVPN virtual address is
10.8.0.2
- Forwarding port
7080 on the public server to port 7080 on the private computer
It’d look something like this:
iptables -t nat -A PREROUTING -d 37.48.80.202 -p tcp --dport 7080 -j DNAT --to-dest 10.8.0.2:7080
iptables -t nat -A POSTROUTING -d 10.8.0.2 -p tcp --dport 7080 -j SNAT --to-source 10.8.0.1
Now the only thing left is to make sure the routing rules persist across reboots.
$ sudo apt install iptables-persistent
$ sudo netfilter-persistent save
$ sudo netfilter-persistent reload
And that’s it. In my experience this seems to be both a more robust solution to the double NAT problem, and uses tools in a more conventional way. I visited 37.48.80.202:7080, and (subject to the awful uplink speed from Xplornet), my page loaded!