OpenVPN – Use secondary VPS IP to access your home-hosted websites and game servers

Here is a visualization over how we want the setup to look like

You may ask – what are we trying to solve? With a setup as explained above, you can host game servers, websites and share content from a local “home” server, without exposing its IP to the world. Everything going to and from the server or website, will all relay through the VPS (Blue square).
While OpenVPN is a good alternative for most people, it is not necessarily the only solution. There are other tools you can use, such as ZeroTier, OpenConnect and WireGuard. This guide does not go into these tools.

Prerequisites

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.

  1. A home client running Linux (Ubuntu, Debian e.g.).
  2. A VPS running Linux with a public IP.
    This VPS must handle running OpenVPN Server.
  3. An extra (floating) public IP assigned to the VPS
  4. IPtables installed and available for configuration on the VPS

Restarts required: No
Time to finish: Approximately 20 minutes
Complexity: Intermediate

Definitions:

  • Interface = A network interface, holding it’s own IP Address
  • VPS = Virtual Private Server

A good read: https://fredrik.space/posts/setting-up-virtual-private-network/

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:

$ ./openvpn-install.sh

It will ask you the following questions:

  1. 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 159.120.120.10
  2. 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
  3. Which port do you want the OpenVPN server to listen to – we will select the default one which is 1194
  4. Select a DNS of your choice. 1.1.1.1 is Cloudflare’s DNS, while 8.8.8.8 if you f.ex want to use google. Or you can stick with your default system resolvers currently on the system.
  5. 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 /etc/openvpn/[client_name].ovpn


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 CTRL+C.

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 159.120.120.10 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:

  1. All traffic you send out from the OVPN client should always be sent out from 112.16.32.11
  2. All traffic that reaches 112.16.32.11, 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 159.120.120.10  #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 1.1.1.1"
push "dhcp-option DNS 1.0.0.1"
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:
client-config-dir /etc/openvpn/server/ccd
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 [client_name]:

$ 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 /etc/systemd/system/openvpn-iptables.service
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 159.120.120.10
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 159.120.120.10
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 (159.120.120.10). 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 112.16.32.11
ExecStart=/sbin/iptables -t nat -A PREROUTING -d 112.16.32.11 -j DNAT --to-destination 10.8.0.2
#Remove rules on stop:
ExecStop=/sbin/iptables  -t nat -D PREROUTING -d 112.16.32.11 -j DNAT --to-destination 10.8.0.2
ExecStop=/sbin/iptables -t nat -D POSTROUTING -s 10.8.0.2 -j SNAT --to-source 112.16.32.11
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.


Finishing up

Now, we’re done with the essential configuration for our setup. We have made sure to:

  1. Route all outbound traffic to our secondary interface
  2. 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: 112.16.32.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]@112.16.32.11 -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: /etc/default/openvpn

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:
openvpn@[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:

  1. You have to create new ssh tunnels for every new port you need to expose.
  2. 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.
  3. It can not forward UDP traffic, unfortunately, which is inconvenient with game servers and content streaming.
  4. 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:

  1. Remarkably reliable by using a tool called autossh – tunnels may lose connection, but the services remain operational since autossh creates a new tunnel immediately.
  2. You get to set up every part of the forwarding on your own.
  3. You get to learn a lot about SSH.
  4. Very convenient and secure if you have few services to expose.

4 Replies to “OpenVPN – Use secondary VPS IP to access your home-hosted websites and game servers”

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.