Remotely Accessing a Home Computer behind Double NAT

I used to host websites and web app services at home. However, as I recently moved and the Internet setup at the new house is quite different—my ISP at home uses a giant central router to divide Internet access to each room. That is, a classic Double NAT scenerio. This is not a big deal if you are not trying to access your devices from outside the local network. However, when you need to do that, you will find it impossible because you have no access to the port forwarding features of the central router of the ISP.

Therefore, I rented a server to host my website. However, the disk spaces I can rent under my budget is tiny. As I still want to host some space consuming services, I needed to find a way to build a system to access my local computer.

The plan is like this: whenever a connection is initiated, it will be sent to the rented server, the server will then route the connection to my computer, and the computer will handle the request. When it is time to return anything, the connection will be sent through the same route back.

This may sound straight-forward, but the correct tools are required to get this done. Basically, I need a tool to set up a special tunnel between my computer and the rented server—and the tool I am using is Wireguard.

Wireguard is basically a VPN app that can allow you to set up a direct tunnel between your server and your computer. It works like this, you assign an IP to the server (let’s say, 192.168.4.1) and assign another to the home computer (let’s say, 192.168.4.2). This solution is inspired by this blog post.

On the server side, the setup of Wireguard looks like this:

[Interface]
PrivateKey = <Private key of the server goes here>
ListenPort = <Any Port>
Address = 192.168.4.1

[Peer]
PublicKey =  <Public key of the home computer goes here>
AllowedIPs = 192.168.4.2/32

On the home computer side, the configuration looks like this:

[Interface]
PrivateKey = <Private key of the home computer goes here>
Address = 192.168.4.2

[Peer]
PublicKey = <Public key of the server goes here>
AllowedIPs = 192.168.4.1/32
Endpoint = <Server URL>:<ListeningPort above>
PersistentKeepalive = 25

After both sides are set up and enabled, both sides will be able to ping each other with 192.168.4.1 (to server) and 192.168.4.2 (to home computer).

As I use my server to host multiple other dockerized services, I already setup a system to use Apache2’s ProxyPass to serve different contents based on the URL. Therefore, on the server side, I then used the same feature to connect to the home computer. The setup looks something like this:

<VirtualHost *:80>
    ProxyPass / http://192.168.4.2:3000/
    ProxyPassReverse / http://192.168.4.2:3000/
</VirtualHost>

The setup above will route any connection to <Server IP>:80 to the <home computer>:3000. As I host multiple services on my server, I use different URL to differentiate services. For example, let’s say I want this to be accessed at https://site.example.com/, I will add it to the server name field like this:

<VirtualHost *:80>
    ServerName site.example.com
    ProxyPass / http://192.168.4.2:3000/
    ProxyPassReverse / http://192.168.4.2:3000/
</VirtualHost>

This will trigger the connection to go to the proxied address when such connection comes, but if you go to https://site.example.com/, it will not know where to bring you. Therefore, you will need to own the domain and add an DNS record to point the site subdomain to your server address (with an A record) or another address (with a CNAME record).

See this article if you need a more detailed explanation of how to make ProxyPass work.