You will need a home client that you want to assign IP from a VPS. This IP can not be the primary IP of the VPS, as you will take over all the traffic from it, and send it to your home client. Taking over the IP is so we can access websites on the home client.
PS: This setup will only allow for one VPN client, as all returning traffic to the public IP will redirect directly to the home client. If you want to combine this with a VPN service, you will need to set up a separate VPN server listening on a different port.
- A home client running Linux (Ubuntu, Debian e.g.).
- A VPS running Linux with a public IP.
This VPS must handle running OpenVPN Server.
- An extra (floating) public IP assigned to the VPS
- IPtables installed and available for configuration on the VPS
Restarts required: No
Time to finish: Approximately 20 minutes
- Interface = A network interface, holding it’s own IP Address
- VPS = Virtual Private Server
What is OpenVPN?
OpenVPN is a software or a tool that you can use to create Virtual Private Networks (VPN). You can use a VPN to access services you own, without having to expose these publically. You just connect your client to a self-hosted OpenVPN server, and you get access to any other client connected to it – through a local network interface.
Where this is the “main” purpose use of a VPN, it is not limited to use the VPN as a solution combined with other systems or setups – such as we are going to explain. Companies may use OpenVPN to expose internal services to their employees.
You can read more about OpenVPN here: https://openvpn.net/faq/what-is-openvpn/
Continuing in this article, we will use “OVPN” as an alias of OpenVPN.
Part 1: Installing OpenVPN
The OVPN Client is the program you use to connect to your OVPN Server. When the client connects, you have access to all services where the OVPN Server is hosted (VPS).
Installing the OpenVPN Client
On the home-client, you can quickly install it from the official repositories using:
$ sudo apt install openvpn -y
And that’s it! We will get back to the configuration of it a bit later.
Installing the OpenVPN Server
The VPS that we have with two public IPs, will handle the routing and orchestrating of the connections. We will install the OVPN server with ease by using a public script to help us. I located the compilation at https://github.com/nyr/openvpn-install – The commands I used, are in the readme:
$ wget https://git.io/vpn -O openvpn-install.sh $ chmod +x openvpn-install.sh
The above commands download the bash script that will assist you with the installation and then make it executable. I always recommend you to verify and check that the file is the file you expect. Review it in an editor like “vim” or “nano”:
$ nano openvpn-install.sh
When you are done verifying, you can execute it:
It will ask you the following questions:
- To which IP you want to listen. Select the main VPS IP and not the IP you want to use for the connections later. In our example case, that is 22.214.171.124
- Which protocol you wish to use. I recommend going with UDP, as OVPN has its layer of control regarding packet loss and re-initiation of these lost packets. UDP is slightly faster than TCP
- Which port do you want the OpenVPN server to listen to – we will select the default one which is 1194
- Select a DNS of your choice. 126.96.36.199 is Cloudflare’s DNS, while 188.8.131.52 if you f.ex want to use google. Or you can stick with your default system resolvers currently on the system.
- Client name – This will be the name of the client and the OpenVPN client file you will use. Remember this for later.
Download the generated
[client_name].ovpn file that the bash script generated for you. This is the file you need to use when you connect from the client.
Upload it to your home-client you want to connect at
Part 2: Connecting the client and the server together
Testing the connection
Now that we have installed the OVPN Client and the OVPN Server, we can verify that our connection works. Go to your home-client, and connect to your VPS by launching the following command:
$ sudo openvpn --config /etc/openvpn/[client_name].ovpn > /dev/null & bg
The > /dev/null
& bg at the end makes the command run in the background. If you need to stop it, write
fg in the terminal, then press
Lets check what our public IP is. We expect it to be the main interface of the VPS, as we haven’t done any routing yet:
$ dig +short myip.opendns.com @resolver1.opendns.com
For this example, it should return
184.108.40.206 as which is our
eth0. That means you have connected your home-client to the OVPN server, and successfully used your VPS IP!
If you do
ip addr | grep "net " on the home-client, you will see that you have an IP that is likely to be
10.8.0.2. This is the internal IP you have. The VPS will be on
10.8.0.1 as it is the gateway and it has the OpenVPN server.
At the moment this is just a regular VPN. If you have a website on your home-client, you will not be able to open this from outside (the public web) yet. The floating IP has to be forwarded and used for this purpose.
But first, we need to make sure that the internal VPN IP for our home-client always stays the same. Let us go make that OVPN IP static in the next section.
Part 3: Configuring our VPN to use the floating IP
This section is where iptables come in. We need to tell the VPS the following:
- “All traffic you send out from the OVPN client should always be sent out from 220.127.116.11“
- “All traffic that reaches 18.104.22.168, should always be forwarded to the OVPN client at 10.8.0.2″
To achieve this, you need to use iptables to “POSTROUTE” and “PREROUTE” the traffic.
But there is one issue with this – namely the local VPN IP 10.8.0.2. It is not statically set and can change if you are unlucky. Before we apply the iptables rules, we need to configure OPVPN server
Set static OVPN client IP
OVPN Server may assign you a random IP every time you connect because it is not static by default. In order for our routing to work in iptables, we need to know exactly where the traffic should go each time. Start out by going to (on your VPS)
/etc/openvpn. Be aware that you may have the folders “client” and “server” there – so adjust accordingly.
See if you can locate a file called
server.conf – It looks like this:
local 22.214.171.124 #This is where the server listens port 1194 proto udp #if you selected UDP in the setup dev tun ca ca.crt cert server.crt key server.key dh dh.pem auth SHA512 tls-crypt tc.key topology subnet server 10.8.0.0 255.255.255.0 server-ipv6 fddd:1194:1194:1194::/64 push "redirect-gateway def1 ipv6 bypass-dhcp" ifconfig-pool-persist ipp.txt 0 push "dhcp-option DNS 126.96.36.199" push "dhcp-option DNS 188.8.131.52" keepalive 10 120 cipher AES-256-CBC user nobody group nogroup persist-key persist-tun status openvpn-status.log verb 3 crl-verify crl.pem explicit-exit-notify
Make sure that
ifconfig-pool-persist ipp.txt 0 is defined as above. It tells the server to read from the file.
And also add this to the top of the server.conf:
The CCD directory will let us define our client IP’s.
Please make the CCD directory with:
$ mkdir -p /etc/openvpn/server/ccd
Do you remember the name you made for the client when you made the client file? Now, you need the name. Create a client file by using the following command, replace
$ touch /etc/openvpn/server/ccd/[client_name]
Inside this file, you need to add this to assign 10.8.0.2 to the client:
ifconfig-push 10.8.0.2 10.8.0.3
Please note that the ranges have to match the ranges you have set up on your VPS. You can check this by running
ip addr | grep tun | grep inet to see what you currently have. My result is:
inet 10.8.0.1/24 brd 10.8.0.255 scope global tun0
Save and close the client_name file. Now, ensure permissions are set correctly on the folder and files we created by running:
sudo chown nobody:nogroup -R /etc/openvpn/server/ccd
If you face issues with permissions or that the IP’s aren’t set correctly, check this: https://forums.openvpn.net/viewtopic.php?t=13289
Then, restart the OpenVPN service
$ systemctl restart openvpn
Set up iptables rules
This is the magic configuration we need, to forward all the traffic we get on our secondary interface to our internal IP 10.8.0.2. Exciting!
Step 1: Stop the running default configuration using:
sudo systemctl stop openvpn-iptables.service
When you installed the OVPN server, the script generated some iptables rules for you. You can check these rules by going to systemd and find the service file. Locate the file at
Step 2: Open it in your editor. The service file should look like this:
[Unit] Before=network.target [Service] Type=oneshot ExecStart=/sbin/iptables -t nat -A POSTROUTING -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to 184.108.40.206 ExecStart=/sbin/iptables -I INPUT -p udp --dport 1194 -j ACCEPT ExecStart=/sbin/iptables -I FORWARD -s 10.8.0.0/24 -j ACCEPT ExecStart=/sbin/iptables -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT ExecStop=/sbin/iptables -t nat -D POSTROUTING -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to 220.127.116.11 ExecStop=/sbin/iptables -D INPUT -p udp --dport 1194 -j ACCEPT ExecStop=/sbin/iptables -D FORWARD -s 10.8.0.0/24 -j ACCEPT ExecStop=/sbin/iptables -D FORWARD -m state --state RemainAfterExit=yes [Install] WantedBy=multi-user.target
You can see that the service file is having rules, to make sure all open VPN connections are going to our main interface (18.104.22.168). Keep in mind that it may also contain rules for your IPV6 interface in case you have this.
Step 3: What we need to do, is to modify this to only to forward traffic back and forth from our client. You can replace the entire file with the values below. Remember to adjust the values to what YOU have set up for internal IP and interface:
[Unit] Before=network.target [Service] Type=oneshot #Add rules on start ExecStart=/sbin/iptables -t nat -A POSTROUTING -s 10.8.0.2 -j SNAT --to-source 22.214.171.124 ExecStart=/sbin/iptables -t nat -A PREROUTING -d 126.96.36.199 -j DNAT --to-destination 10.8.0.2 #Remove rules on stop: ExecStop=/sbin/iptables -t nat -D PREROUTING -d 188.8.131.52 -j DNAT --to-destination 10.8.0.2 ExecStop=/sbin/iptables -t nat -D POSTROUTING -s 10.8.0.2 -j SNAT --to-source 184.108.40.206 RemainAfterExit=yes [Install] WantedBy=multi-user.target
Step 4: Save the contents and exit the editor. Reload the daemon with:
sudo systemctl daemon-reload
Step 5: Start the new configuration by running
sudo systemctl start openvpn-iptables and make sure the rules are changed and correct by running:
iptables-save. It will print the current rules in the terminal for you.
Now, we’re done with the essential configuration for our setup. We have made sure to:
- Route all outbound traffic to our secondary interface
- Route all inbound traffic from our secondary interface to our client which is at home
If you now go to the client, to test this, again run:
$ sudo openvpn --config /etc/openvpn/[client_name].ovpn > /dev/null & bg # and then run this to check your public IP: $ dig +short myip.opendns.com @resolver1.opendns.com # Result: 220.127.116.11
Yes! Now, test the reverse connection routing us back to the home client. Spin up a web service, or test your SSH access from the outside:
$ ssh [user]@18.104.22.168 -p 22
And this should log you in to your SSH on the home client.
If by any chance this is NOT the result you see, and you are 100% sure you followed the instructions, you can leave a comment below. I will read the comments and get back to you.
How to enable this on every boot, and run it as a service?
Good question! The final part you may want to do, is to set this up to be completely automatic on every boot. This is why we placed the [client_name].ovpn file under
/etc/openvpn earlier. Go to your home client shell, and edit the following file:
the line saying #
AUTOSTART= in this file. You may enter the [client_name] there, and uncomment the line. Save.
Stop your currently running OpenVPN connection if it is still open.
Now, restart openvpn service:
$ systemctl restart openvpn
Reboot your Home Client. The result we expect, is that the OpenVPN connection starts automatically, and it will run as a service named:
[email protected][client_name] . You can stop / start it using systemctl.
OpenVPN feels slow. Do you know why?
Yes, it will likely saturate 100mbps connections.Here are some documentation on exactly this. (Click)
You also need to make sure you’re not having too high latency and that you have the necessary network capacity.
Roundup: Are SSH tunnels a good alternative?
After hosting things from home for two years using SSH tunnels, I must say that I am thrilled with it. Considering I do not have any access to my NAT (as for now), I can still circumvent this by accessing my content on a “relay” host with public IP. You simply forward the ports with SSH and access them on the VPS. I have gone in detail why and how here: https://floof.cc/2020/01/05/nextcloud-reverse-proxy-with-autossh/
But still, the ssh solution may be cumbersome. Let me explain:
- You have to create new ssh tunnels for every new port you need to expose.
- It is not very dynamic, meaning that you need to change several config files every time you want to change a port or a service.
- It can not forward UDP traffic, unfortunately, which is inconvenient with game servers and content streaming.
- You have to forward origin-ip’s between the relays/webservers in order to avoid all connections appearing as they are from 127.0.0.1
Positive sides with the ssh solution:
- Remarkably reliable by using a tool called autossh – tunnels may lose connection, but the services remain operational since autossh creates a new tunnel immediately.
- You get to set up every part of the forwarding on your own.
- You get to learn a lot about SSH.
- Very convenient and secure if you have few services to expose.