Wireguard VPN to Network Behind a CGNAT

November 30, 2020

I recently moved from the place where I was staying at to my own studio. In addition, since I was building a computer, I wanted to be able to access remotely to its capabitities, as well as any other device I have at home. Thus, I thought: let’s set up a VPN!

The problem arised when I went to the configuration of my router and saw that my WAN IP was in the format 172.xxx.xxx.xxx. I immediately knew that that was a private IP. On my ignorance, I decided to search why I didn’t have an actual public IP.

Well, apparently there’s a thing called Carrier Grade NATs (CGNATs) which are gigantic NATs that Internet providers decided to create in order to band aid the shortage of IPv4s in many places. So I thought, once again, “let’s see if I have an IPv6”. I open test-ipv6.com and for my surprise (or not) I see a score of 0 out of 10. No public IP for me.

Since the contract with the ISP is not mine, there’s not much I can do. I already contacted the agency where I’m renting the studio. They usually reply quickly, but I haven’t heard from them about this for a few days already. Pretty sure it’s an unusual request. In the meanwhile, I decided to go for a different strategy.

The new strategy is to have a VPS with a public IP somewhere where I can have a Wireguard VPN running. Then, in my home network, I can have a Raspberry Pi connected to that same VPN which exposes my local network. Sounds good? Let’s see how we can do that!


You will need the following to successfully follow this guide:

  • A Linux host with a public IP. I will be using a VPS.
  • A Linux host inside your network. I will be using a Raspberry Pi.
  • The device you want to connect to your home network while you’re away.

I am not covering installation steps. The official documentation explains how to install Wireguard and its tools on most OSes. For the Raspberry Pi, please follow this amazing guide.

Key generation

First of all, we need to generate the public and private keys of all devices that will be connected in this network. For that, we can use the following sequence of commands:

wg genkey | tee vps_privatekey | wg pubkey > vps_publickey
wg genkey | tee pi_privatekey | wg pubkey > pi_publickey
wg genkey | tee client_privatekey | wg pubkey > client_publickey

The public host (aka VPS)

Configuration file /etc/wireguard/wg0.conf:

Address =
PrivateKey = <vps_privatekey>
ListenPort = 37466                  

# Do not forget to change eth0 to the interface that is connected to the Internet!
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

# This is the peer inside the local subnet we want to have access to.
# For that to happen, you need to add your local subnet to the AllowedIPs
# option just like I did below.
PublicKey = <pi_publickey>
AllowedIPs =,

# A client...
PublicKey = <client_publickey>
AllowedIPs =

# An additional client...
PublicKey = <some other public key>
AllowedIPs =

Now, you need to setup IP forwarding on the machine (you may need to also uncomment the line on /etc/sysctl.conf so it persists across reboots):

$ sysctl net.ipv4.ip_forward=1

And start the Wireguard server:

$ wg-quick up wg0

You can also turn it on on boot:

$ sudo systemctl enable [email protected]

To check if everything looks fine:

$ sudo wg show

Don’t forget to open the ListenPort on your VPS’ firewall.

The local host (aka the Raspberry Pi)

For the host in the local network, we will create a file /etc/wireguard/wg0-client.conf with the following configuration:

Address =                  
PrivateKey = <pi_privatekey>
DNS =                 # you can also use your own DNS server

PublicKey = <vps_publickey>
Endpoint = <vps ip>:37466     # do not forget to put your VPS IP here
AllowedIPs =, ::/0
PersistentKeepalive = 25      # keep connections alive across NAT

You have to add two iptables rules permanently. Since the command is temporary and does not persist reboots, I recommend adding them to the file /etc/rc.local.

$ iptables -A FORWARD -i wg0-client -j ACCEPT
$ iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

Similarly to what we did on the public host, we need to enable IP forwarding. Do not forget to make it permanent.

$ sysctl net.ipv4.ip_forward=1

Set up the Wireguard client:

$ wg-quick up wg0-client

And enable it on boot:

$ sudo systemctl enable [email protected]

So far, from the VPS, you should be able to ping any device on your local network. If that works, then the setup is working and we now only need to setup the third client, the client that you will connect to the Wireguard when you’re outside your home and need to access some of your devices.

The client

The client (your smartphone, computer, etc) is the easiest. Here’s the configuration:

PrivateKey = <client_privatekey>
Address =
DNS =                     # you can use your own!

PublicKey = <vps_publickey>
AllowedIPs =
Endpoint = <vps ip>:37466
PersistentKeepalive = 25

On your phone, it can be easily added through the Wireguard app. The same on the computer. This will create a full tunnel VPN. However, if you just want to access your local network, while using your current Internet connection for everything else, you can create a split tunnel client. For that, you just need to change the AllowedIPs field to your network subnet:

And you’re done! From your smartphone you should be able to ping and access any device on your private network by their local IP. I want to thank to the many guides like this that I found online and helped me with this!

I recently moved from the place where I was staying at to my own studio. In addition, since I was building a computer, I wanted to be able to access remotely to its capabitities, as well as any other device I have at home. Thus, I thought: let's set up a VPN!

Interactions (6)
Anonymous Anonymous said: In order to get it to work, I had to open the port on my Vultr firewall AND add this line. "sudo ufw allow 37466/udp" Working great now! Thanks for the write-up!08 Apr 2022 14:01
Anonymous Anonymous said: I have setup things as described - however after after installing some OS updates on the VPS despite having set the client to work with full tunnel, all traffic that does not go to the local subnet now gets routed to the internet using the VPS ip. Any idea what might cause this?29 Jan 2022 22:20
Henrique Dias Henrique Dias said: Weirdly enough, the name Tailscale caught my eye and I decided to investigate what it is. I checked their website and it seems that they use Wireguard to do the kind of configuration I explained some time ago. I’m curious: besides the easyness of use, what other advantages do you see on using Tailsc…20 Oct 2021 17:58
codebreaker101 codebreaker101 said: I'm looking to create a small box, probably raspberry pi, that I will give to my clients that will allow me to connect to their local network and have access to heir devices on the network. All that they need to do is plugin power and ethernet. It should not require to have any ports open or require…06 Sep 2021 10:13
Anonymous Anonymous said: Are you sure this line is correct: sudo systemctl enable [email protected] Perhaps your blogging platform auto-added the link?09 May 2021 13:50
Anonymous Anonymous said: Dont forget to open the used Port in the Settings of the VPS!11 Mar 2021 20:49