Set up a network wide VPN using Ubuntu Server

!
Warning: This post is over 365 days old. The information may be out of date.

As a foreigner living in China, you crave Netflix and YouTube, but hate toggling over to your VPN app over and over just to watch censored content. So waht’s the solution?

Enter the network-wide VPN gateway - your very own server that you will set up to tunnel your entire home’s network!

Prerequisites

You will need:

  • A VPN provider that gives out OpenVPN configurations. Other protocols will probably also work, but they are not covered in this tutorial.
  • A server or a VM running Ubuntu Server. Using the latest version is recommended. I used 16.04 LTS at the time of writing this blog post.
  • Some Linux and networking knowledge
  • (optional, but recommended) A router that supports setting the default gateway in the DHCP server

Without proper Linux and networking knowledge, you will have a broken LAN someday with no way to troubleshoot or debug! Make sure you know what you are doing before following this tutorial.

A router that supports setting the default gateway on the DHCP server is important. Without it, you will have to manually go around each device and set up the proper configuration so it’ll route the traffic through your new Linux router! At that point, you might as well set up the VPN on each device, but the benefit of setting this up at all without a supported router is still great that you should consider setting it up anyway. Some devices that do not support native VPN (such as the Chromecast, Roku Fire sticks, your smart robot cleaner) will now connect through the VPN through a simple configuration change.

So whether you’re serious about this, or it’s just a fun experiment, it’s definitely worth it to set it up. Just understand the risks before you move on. If any problems arise, you should be able to debug them.

VPN setup

Grab the OpenVPN file from your VPN provider. The page should also list your unique username and password for OpenVPN. Grab that too.

(NOTE: If it does not show your unique username and password, then it might be your VPN provider’s account username and password. Experiment and see if it works.)

Now, depending on your VPN provider, they will give you one, in-line OpenVPN file, or separated files consisting of the client keys and server certificates. The former is better, since you won’t have to monkey around with key configurations.

Jumping onto your VM, execute this command:

ifconfig

This will show your current network configuration. Note down the interface name on the left side. For example, my network was:

enp2s0    Link encap:Ethernet  HWaddr <obfuscated>  
            inet addr:192.168.0.100  Bcast:192.168.0.255  Mask:255.255.255.0
            <truncated>
            
lo        Link encap:Local Loopback  
            inet addr:127.0.0.1  Mask:255.0.0.0
            <truncated>

Some things to note here. First, your Ethernet interface is enp2s0, and your IP address is 192.168.0.100. These will be important later on.

Now, let’s install OpenVPN:

sudo apt install openvpn

Once it’s installed, let’s configure it. Copy the sample configuration file:

sudo cp <VPN name here>.ovpn /etc/openvpn/<VPN name here>.conf

At this point, if you have keys included with the .ovpn file, look at the keys. They will be named like ca.rsa.2048.crt or similar, depending on what key size your VPN provider uses. Simply find the key files and copy them with this command:

sudo cp ca.rsa.2048.crt crl.rsa.2048.pem /etc/openvpn

If your provider is smart enough to provide inline certificate files (OpenVPN configuration files that have the certificates attached inside), you can skip the above command. Continue down below.

Now you might be wondering why we renamed that .ovpn file to .conf. It’s because this is the only way we can use systemd to control OpenVPN. With this change, the configuration file gets registered to systemctl, and you can enable them with OpenVPN@VPN-name-here.

Next, note down your VPN username and password in /etc/openvpn/login:

username-here
password-here

An example credential file would be something like this:

ericswpark
examplepassword12345

Save and exit. Now edit /etc/openvpn/<VPN name here>.conf and look for the following line:

auth-user-pass

Change it to:

auth-user-pass /etc/openvpn/login

Now, if you have separate key files copied from above, you will need to do one more step. Find these lines:

ca ca.rsa.2048.crt
crl-verif crl.rsa.2048.pem

And change them into:

ca /etc/openvpn/ca.rsa.2048.crt
crl-verif crl.rsa.2048.pem

And you’re done!

Before you save, there’s some additional options you might want to configure. For example, you might want to disable persist-tun if you live in an environment where Internet connection is flaky. The VPN will destroy the tunnel interface when it restarts, forcing it to use your regular censored Internet for the VPN server lookup. This is handy because the VPN server lookup will fail over a dead tunnel interface.

Find this line:

persist-tun

And put a # in front of it to disable it:

# persist-tun

If you want the server to keep the connection alive, find or add these following two lines:

keepalive 10 30
resolv-retry infinite

The last line isn’t strictly needed, because the default is infinite. The first line tells the OpenVPN client to ping the server (--ping) every 10 seconds, and restart (--ping-restart) if there is no response for 30 seconds. This has been handy because the Great Firewall of China likes to send TCP RST packets everyonce in a while. Experiment with those values if you need a more reliable connection, but I’ve found 30 seconds is pretty adequate for a smooth network drop fix without unnecessarily straining the VPN server.

Save and now, we’ll have to test the VPN server. Since I’m in China, that’s super easy! Just ping Google. If you’re in a different country where that test is inconclusive, you could check ifconfig again.

Start the client:

sudo openvpn --config /etc/openvpn/<VPN name here>.conf

If you see Initialization Sequence Completed anywhere in the logs, congratulations! Your VPN is set up correctly! Press Ctrl-C to destroy the VPN tunnel and follow along with next steps.

Setting up a static IP (optional, but recommended)

At this point, you might want to set up a static IP for your VM. This is because you don’t want IPs shifting if you decide to add the IP to your default gateway settings in your router.

Log into your router administration page. The details should be underneath the router, printed out on a sticker. If you can’t find it, then just Google your router’s manufacturer and look for the IP. If that doesn’t work, check your computer’s default gateway, because usually routers push their IP through there. If all else fails then just type in addresses like 192.168.0.1 or 192.168.1.1.

If you find the IP, remember to write it down because it’ll be important later, and click on DHCP address reservations, or something named similar. Remember your MAC address from step 0? No? Then just do ifconfig again and jot down the MAC address for your Ethernet interface.

Assign it an address, then press OK. Remember that address, Now some more configurations on your VM! Edit this file, /etc/network/interfaces and find the lines:

auto enp2s0
iface enp2s0 inet dhcp

The interface name might be different. Just change it so that it looks like this (remember to keep the interface name that was in your file, NOT the ones shown here!):

auto enp2s0
iface enp2s0 inet static
    address 192.168.0.100
    netmask 255.255.255.0
    gateway 192.168.0.1
    dns-nameservers 1.1.1.1 1.0.0.1

You’re free to use any DNS nameservers you like. Personally, I like the new CloudFlare 1.1.1.1s. Remember to input the correct IP address and netmask! The IP address is the one you manually assigned on the router administration page, the netmask can be found by checking your network settings, and the gateway should be whatever it was before (check network settings on your computer) or your router’s administration IP, which is usually the default gateway on most routers.

The default gateway bit is important, because if you decide to forward the VM’s IP as the default gateway later in the DHCP push settings, your VM box will have a default gateway value set to itself. So make sure the default gateway is the current default gateway shown in your network settings.

Cool! Reboot the VM and the router and make sure both are accessible, and your Internet is working. Next!

Setting up the tunnel

First, let’s enable the OpenVPN service so it starts at boot.

sudo systemctl enable OpenVPN@<VPN name here>

Don’t write the .conf extension when you’re running this command! Then, let’s enable IPv4 forwarding. Edit this file - /etc/sysctl.conf - and find this line:

# net.ipv4.ip_forward = 1

Change it to:

net.ipv4.ip_forward = 1

Just remove that #, save and move on.

Next, reload sysctl!

sudo sysctl -p

Congratulations! Now we need to configure the firewall and routing.

iptables

This part is extremely hard, probably the hardest in this tutorial. I don’t even understand most of it, but will try to explain it as best as I could.

First off, we want to allow the loopback traffic through the loopback device. Execute these two commands:

sudo iptables -A INPUT -i lo -m comment --comment "loopback-input" -j ACCEPT
sudo iptables -A OUTPUT -o lo -m comment --comment "loopback-output" -j ACCEPT

Then, we want to allow traffic coming in from the network, and traffic going out to the tunnel network. (If you don’t know these or forgot from earlier, run the VPN using the command way above, and run ifconfig to figure out the interfaces.) Execute these commands, making sure to substitute the interface names from earlier:

sudo iptables -I INPUT -i enp2s0 -m comment --comment "Local network" -j ACCEPT
sudo iptables -I OUTPUT -o tun0 -m comment --comment "VPN network" -j ACCEPT

Then we need to allow the OpenVPN traffic to pass through the box. Find the port number by looking at the .conf file we talked about earlier. It should be on the line that starts with remote. Then execute this command, making sure to replace that port number and interface name:

sudo iptables -A OUTPUT -o enp2s0 -p udp --dport 1194 -m comment --comment "OpenVPN traffic" -j ACCEPT

Next up, we need to allow certain services to operate. Execute these commands:

sudo iptables -A OUTPUT -o eth0 -p udp --dport 123 -m comment --comment "NTP service" -j ACCEPT
sudo iptables -A OUTPUT -p UDP --dport 67:68 -m comment --comment "DHCP service" -j ACCEPT
sudo iptables -A OUTPUT -o eth0 -p udp --dport 53 -m comment --comment "DNS service" -j ACCEPT

Almost there! You need to forward the traffic from the tunnel to the Ethernet interface. This bit is really important! Run these commands (and make sure to substitute the interface names):

sudo iptables -A FORWARD -i tun0 -o enp2s0 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i enp2s0 -o tun0 -m comment --comment "Local network to VPN" -j ACCEPT

Cool, one last thing. You need to set up MASQUERADE on the POSTROUTING table on your NAT, so that the Network Address Translation works across the VPN. Execute the final command (switch these interface names, remember):

sudo iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE

If you managed to follow this far, congratulations! But before you go and celebrate, you want to save these configurations so these don’t get lost over a reboot.

Run this:

sudo apt install iptables-persistent

And the installation will begin. If it asks you if it should save the current configuration, choose yes, and carry on. Let’s enable the service to run at boot:

sudo systemctl enable netfilter-persistent

If, in the far future, you add any more iptables rules, you can save them by running:

sudo netfilter-persistent save

And they will be saved.

One last, really important thing. If you want to back up these configurations, you can type:

sudo iptables-save > backup.txt

To save the rules inside a text file. This is also a handy way to edit these configurations should you decide to change them. Once you want to restore, use this command:

sudo iptables-restore < backup.txt

Nice! Your configuration is nearly finished!

Test the connection

Reboot the box. On the client device you want to test, change the default gateway’s IP address to the VM’s IP. It should start forwarding traffic through the VPN! Congratulations!

But this is tedious. I’m lazy. What should I do?

Set up router forwarding

If your router supports default gateway switching, you can do this. (Most routers support this)

Go to the router administration page (remember it?) and click on DHCP settings. Under the Default Gateway IP address, input the VM’s IP.

Now reboot the router. If it works, great!

In odd cases, the default gateway change might actually just change the administration page’s IP address. If that happens, there will be an address collision, and your VM box will either lose the IP address or lose access to the local network. In severe cases your router administration page might not come up. In that case, just disconnect the VM box, reboot the router and connect to the administration page to change the default gateway back. If this is the case, then your router does not support default gateway switching.

Connection-helping script

Now, since China is great for these TCP RST packets that drop your VPN connection sporadically (so you have to remote into your VM and fix it), I wrote a Python script that helps me out with the entire process.

Any improvements in the form of pull requests would be welcome!

comments