Set Up a Network Wide VPN Using Ubuntu Server
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!
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.
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:
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
Next, note down your VPN username and password in
An example credential file would be something like this:
Save and exit. Now edit
/etc/openvpn/<VPN name here>.conf and look for the following line:
Change it to:
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:
And put a
# in front of it to disable it:
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
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
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 126.96.36.199 188.8.131.52
You’re free to use any DNS nameservers you like. Personally, I like the new CloudFlare
184.108.40.206s. 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.
sudo sysctl -p
Congratulations! Now we need to configure the firewall and routing.
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.
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.
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!