Wherein I set up OpenVPN on my VPS so that I can access my home network (which is behind forced NAT and can't accept inbound connections of any kind) while I'm away from home.
I live in student accommodation where I receive 'free Internet' (indirectly paid for through exorbitant rent fees) provided by KeySurf/KeyCom. This is accessible in two different ways:
Connecting to either of these gets you a captive portal where you must log in with your KeySurf account. You can also use the web interface to add specific devices by MAC address, which is necessary for stuff like the Nintendo 3DS.
I'm 99% sure that everybody in the building shares the same external IP address, though I haven't confirmed this for sure -- I know that my devices definitely do. Regardless, there is no way to set up port forwarding of any kind... so good luck getting remote access!
A friend gave me a TP-Link TL-WR710N router running OpenWRT (which I've since upgraded to LEDE 17.01.4). This has allowed me to set up a miniature home network, which is quite useful as it means that my laptop and desktop (plus VMs running on the latter) can communicate with each other reliably.
Of course, this only works when I'm actually physically there. Can I remotely access the network so that I can work on my desktop and access files when I'm not at home? The answer is yes -- but it took me the better part of a day to figure out the correct series of magical incantations (and a couple of experiments with magical "it just works" software packages that didn't end up actually working, like ZeroTier One and SoftEther VPN).
I'll spare you the details of how I actually got there and just describe the setup I ended up with, and how it works...
The router is running LEDE 17.01.4 and is accessing the Internet through the WAN interface. I've configured IP addressing as follows:
I assigned static leases to my machines to make working with them easier, but this isn't strictly necessary for the OpenVPN setup to function.
Note: I've got the subnet mask set to
255.255.254.0 rather than the somewhat
255.255.255.0 as a leftover from one of my failed experiments
(following somebody else's guide to set up ZeroTier One). The latter would
probably work as well, but I'm hesitant to change now that I have things
My VPS is currently running OpenVPN 2.4 on Arch Linux.
I used easy-rsa to create a certificate infrastructure with keys for the server, router and laptop. This is a fairly standard setup; there are plenty of guides for this.
The following files from the process are in
dh.pem, as well as the following
port 1194 proto udp dev tun ca ca.crt cert server.crt key server.key dh dh.pem server 10.8.0.0 255.255.255.0 ifconfig-pool-persist ipp.txt client-config-dir ccd client-to-client keepalive 10 120 tls-crypt ta.key cipher AES-256-CBC compress lz4-v2 push "compress lz4-v2" persist-key persist-tun status openvpn-status.log verb 3
Note about the setup -- the OpenVPN network is on
10.8.0.0 with subnet mask
255.255.255.0. The OpenVPN server automatically assigns itself IP
Additionally, you need to create a client configuration directory at
/etc/openvpn/server/ccd, containing the following files.
Note that the name of the file needs to match the 'common name' specified when
you created the certificate for that device. No extension!
ifconfig-push 10.8.0.200 10.8.0.1 iroute 10.99.4.0 255.255.254.0 push "route 10.8.0.0 255.255.255.0 10.8.0.1"
ifconfig-push command assigns the router to
10.8.0.200 on the OpenVPN
iroute command tells the OpenVPN server to route all packets on the
10.99.4.0 subnet (my home network) towards this device.
push route command tells the router to route all OpenVPN network packets
towards the OpenVPN server.
ifconfig-push 10.8.0.100 10.8.0.1 push "route 10.99.4.0 255.255.254.0 10.8.0.1"
ifconfig-push command assigns the laptop to
10.8.0.100 on the OpenVPN
push route command tells the laptop to route all home network packets
through the OpenVPN server.
iroute is needed because the only packets going to the laptop are
destined for the laptop itself -- this is in contrast to the router, where
packets going to the home network need to be explicitly directed towards it.
This is a modified and pruned version of the template client configuration. I'm using it with Tunnelblick on macOS, but I see no reason it wouldn't work on other platforms as well.
The following files are included alongside the configuration:
client dev tun proto udp remote tres.wuffs.org 1194 resolv-retry infinite nobind persist-key persist-tun ca ca.crt cert laptop.crt key laptop.key tls-crypt ta.key verb 3
Getting OpenVPN to work on the router is pretty straightforward, thankfully.
The following files should be in
ta.key, along with the following configuration in
client dev tun proto udp remote tres.wuffs.org 1194 resolv-retry infinite nobind persist-key persist-tun ca ca.crt cert router.crt key router.key tls-crypt ta.key verb 3
/etc/init.d/openvpn start and with any luck, OpenVPN will start.
You may find it helpful when debugging to simply run OpenVPN in the foreground
openvpn /etc/openvpn/vpn.conf and view the log messages - this goes
for the setup on the other devices too, not just the router.
Once all of this has been set up, you should have both devices connected to
the VPN and you should be able to ping across the OpenVPN network: the router
should be able to ping the laptop at
10.8.0.100, and the laptop should be
able to ping the router at
However, to make the home network accessible, you'll need to set up forwarding on the firewall. Thankfully this is pretty straightforward via the firewall settings in LEDE's LuCI.
From Network > Interfaces, select Add new interface, and enter the following:
Now go to Network > Firewall. Create a new Zone, with the following settings:
Save and apply everything.
If all has gone well you should now be able to access devices on the home
10.99.4.x subnet) while connected to the VPN, no matter where
There are a couple of issues I didn't bother trying to troubleshoot and fix because I was already tired of OpenVPN/firewall configuration and I'm not particularly bothered by them.
SMB (Windows file sharing) appears to work fine over the network, but names
are not resolved automatically so you must for example access
OpenVPN client 1 (the laptop) can access the
10.99.4.x subnet, but the
server itself can't. This is probably pretty straightforward to fix by adding
extra routing rules but I didn't want the hassle.
Let me know on Twitter (@_Ninji) or through some other means if you found this useful!
Previous Post: An Unholy Combination: Closure Compiler, Preact and JSX
Next Post: Mouse Adventures #1: Introduction