VPNs are a way of accessing application which sit on a separate network using an encrypted tunnel. Contrary to popular belief, they are not designed to anonymize your internet habits. Whilst VPNs are designed to enable a client to access the servers network, it’s possible to use them to provide a server to access to its client’s network. With this, and a simple HTTP server, it’s possible to open up applications on your home network to the internet, without the need for a static IP, or a port forward!

Network layout


As with any other VPN network, you’ll need two devices, a server and a client


The VPS will act as the VPN server, and the external gateway to your internal network. I’ll be using Ubuntu Server, but any distribution which supports OpenVPN Access Server will also work.

#Internal device

The internal device will connect to the VPN, and allow access to your internal network. A Raspberry Pi works great for this, which is what I’ll be using, but anything which supports the OpenVPN client will work fine; It doesn’t need to be a distinct device. As this device will only handle routing traffic and connecting to the VPN, it doesn’t have to be powerful. My setup uses a single-core Pi and it never bottlenecks.


#Install OpenVPN Access Server

The first step is to install OpenVPN Access Server. The exact command differs depending on the distribution, but they can all be found on the OpenVPN website. After installation, be sure to run the ovpn-inittool as prompted. At the prompts, answer the questions as below. Many of them, such as the port numbers, can be changed, just substitute them in later on.

Will this be the primary Access Server node?
(enter 'no' to configure as a backup or standby node)
> Press ENTER for default [yes]: yes

Please specify the network interface and IP address to be
used by the Admin Web UI:
(1) all interfaces:
(2) ens3: xxx.xxx.xxx.xxx
Please enter the option number from the list above (1-2).
> Press Enter for default [2]: 1

Please specify the port number for the Admin Web UI.
> Press ENTER for default [943]: 943

Please specify the TCP port number for the OpenVPN Daemon
> Press ENTER for default [443]: 443

Should client traffic be routed by default through the VPN?
> Press ENTER for default [yes]: yes

Should client DNS traffic be routed by default through the VPN?
> Press ENTER for default [yes]: no

Use local authentication via internal DB?
> Press ENTER for default [yes]: yes

Should private subnets be accessible to clients by default?
> Press ENTER for default [yes]: yes

Do you wish to login to the Admin UI as "openvpn"?
> Press ENTER for default [yes]: yes

OpenVPN Access Server is free for two concurrent users. For this, we only need, so no need to enter a licence key.

Once the script has finished, you’ll need to set the password for the builtin user. Run sudo passwd openvpn to do this. Open the “Admin UI” URL displayed after the init script. It’s probably https://<ip>:943/admin. Here, you can log in as the openvpn user.

Landing page for OpenVPN admin panel

#Create the client account

Once logged in, click “User Permissions” in the sidebar, and create a new user. The user needs to have “Allow Auto-login” enabled, and should not be an admin, for security reasons. Once created, update the running server, and open the “More Settings” tab for the newly created user and set their password. Be sure to save the settings afterwards.

#Setting up the VPN user

The new VPN user needs to be told to allow traffic to flow to other devices on its network. To do this, we need to enable a feature called “VPN Gateway”. Under the user settings, switch the related radio button to Yes, and enter the subnets you want to be accessible. These should be one per line, and in the format You will also need to enable access from “all server side private subnets” and “all other VPN clients”.

Make sure your user settings look roughly like this.

#Set up the client device

The client device dependency installation is much simpler. Simply install the OpenVPN client, and you’re good to go!

#Getting the client configuration

The OpenVPN client configuration can be downloaded from the access server web UI. Visit https://<ip>:943/ and log in using the client account. Here you can download the auto-login connection profile, which needs to be placed on the Pi.

#Correctly installing the client configuration

To ensure the connection to the VPN is restarted whenever the Pi is, it needs a systemd service. The OpenVPN client installs a one by default, which can be used with configuration files. The config file needs to be placed at /etc/openvpn/proxy.conf. This VPN process can be controlled using the service openvpn@proxy (note the filename is the same as everything after the @).

Once the file is installed, you need to both start it, and make it start at boot:

sudo systemctl enable openvpn@proxy
sudo systemctl start openvpn@proxy

Check sudo systemctl status openvpn@proxy to make sure the connection was successful. You can also check the “Current Users” tab in the access server admin.

#Testing the connection

At this point, you should be able to connect to your home network from your VPN. SSH into your VPN, and run ip route. You should see an entry with the subnet you wish to forward. Test it by pinging the local IP of your Pi, and you should have a connection.

Bash Session
$ ping -c 1
PING ( 56(84) bytes of data.
64 bytes from icmp_seq=1 ttl=64 time=17.9 ms

--- ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 17.936/17.936/17.936/0.000 ms

#Enabling access to the rest of your network (Optional)

This step may not be required, but was for me, and came after the result of many hours of internet scouring. Now that you can ping your Pi, you should be able to ping the rest of your network. If you can’t, then this bit is for you.

There’s a thread online describing exactly this issue, and the solution is, as with most of these things, iptables. The below command allows the traffic to be routed using NAT to other devices on the interfaces network.

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

Replace eno1 with the ethernet interface of your Pi, not the VPN one. iptables clears its configuration on reboot, so to make sure this rule is automatically applied, you’ll need to set up something like iptables-persistent.

#Setting up a reverse proxy

Now that the subnet is accessible on your VPN server, as if it were inside your home network, you can just create a reverse proxy configuration, and put in the local IP of your devices. Be sure to assign them static IPs if you don’t want to keep changing the configuration. The below NGINX config will proxy requests to the address http://foo.example.com to your internal device at

Nginx configuration file
server {
    listen 80;
    server_name foo.example.com;

    location / {
        proxy_set_header Host $host;

And that’s it! No port forwarding, no device enumeration, no service enumeration, no hacks. Any device on your network can be made accessible to the world, but only when you want them to. And because it’s forwarding using a VPN, it doesn’t have to be simply HTTP traffic!

Share this page

Similar content

View all →

Opening Port 22

2 minutes

My university has a development sever, which it uses to host our coursework without the need to set up a development environment locally. It also enables lecturers to mark our work in a controlled environment, without needing to spin up an environment, and run untrusted code on their machines, a…

WireGuard HAProxy Gateway

4 minutes

Last year, I wrote a post on setting up a gateway to a private network, powered by OpenVPN-AS. I ran this network setup for quite a while with a lot of success, exposing services on my home network to the public internet, securely. Unfortunately, there were a couple issues with…


State of the Apps 2023

It's that time of year again, time to steal some of Cortex's search rankings to talk about my own "State of the Apps" - the applications and setups I use to make my life what it is. Since my last post, and in fact in just the last few weeks,…