OpenVPN – Use secondary VPS IP to access your home-hosted websites and game servers
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.
- 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
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:
- 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
- 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. 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.
- 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:
- “All traffic you send out from the OVPN client should always be sent out from 112.16.32.11“
- “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:
- 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: 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:
- 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.
Great article, good job explaining it!
Great explanation my brother! I need to print this out and pack it in my bag.
Could add me i need contact you
Discord: OXALD#5876