Bypassing CGNAT Like a Chad

Or, How to port forward when you don't have your own public ip A guide by Bread

Table of Contents

Requirements

  • A device that can connect to the internet
  • A VPS with access to a public IP

My setup

I will be using an oracle cloud instance running Ubuntu 22.04 for my VPS and the clients are windows and linux.

Set up the VPS

Enable Forwarding of IP

Edit line 28 of the file /etc/sysctl.conf, removing the comment.
#net.ipv4.ip_forward = 1 => net.ipv4.ip_forward = 1
If you also want to use IPv6 traffic, you can remove the comment on line 33 as well, but I won't be using it, so I'm not going to bother.
#net.ipv6.conf.all.forwarding = 1 => net.ipv6.conf.all.forwarding = 1

Install Wireguard

https://www.wireguard.com/install/

Create a public / private key pair

You make get a waring like this when running these commands: Warning: writing to world accessible file. Consider setting the umask to 077 and trying again. This is becuase the files are set to have readable permissions, you can fix it by either setting umask to 077, or by changing the permissions to 600, which is what I will be doing.

wg genkey > server-private-key
wg pubkey < server-private-key > server-public-key

Cat these out and copy paste them or write them down, we will need them soon.

cat server-private-key
cat server-public-key

Create the config file

vim wg0.conf

There are 2 parts to this file, the [Interface] block with the info for the server, and the [Peer] blocks, for the clients you want to connect to the VPN.


[Interface]
PrivateKey = <private key of the server>
Address = 10.0.0.1/24
ListenPort = 51820

[Peer]
PublicKey = <public key of the client> // You will put the key here after you generate it on the client's end
AllowedIPs = 10.0.0.2/32

[Peer]
PublicKey = <public key of another client>
AllowedIPs = 10.0.0.3/32


In this block, PrivateKey is the Private key of the server (duh).

In the Address field we specified the address to assign to the interface in the VPN together with the subnet mask using the CIDR notation. In this case we used 10.0.0.1/24, so our Wireguard “server” address inside the VPN will be 10.0.0.1, which is in the available range of addresses that goes from 10.0.0.1 to 10.0.0.254.

In the ListenPort field, we will point our client's configuration to this port, when we set those up. You can use any unused port, the guide I followed just used this one.

Save the file and exit.

Now we can change those permissions and move them into the wireguard main directory.
chmod 600 server-public-key server-private-key wg0.conf
sudo mv server-private-key server-public-key wg0.conf /etc/wireguard

Because these files don't have write / execute permissions you can't tab to autocomplete them, but they're still there. At least I think that's why I couldn't.

Now would be a good time to #set up the client, so that you can put the client's public key into the the wg0.conf file.

Special case for Oracle Cloud (you can skip this if you're not using it)

CIDR / Subnet was chosen when server was set up. Look at in your Oracle Dashboard and then Virtual Cloud Networks > Click on vcn similar to "vcn-20221212-1313" > Click on the subnet similar to "subnet-20221212-1313". Copy the info for IPv4 CIDR Block info.

And since we are here, lets add a firewall rule. Click on the Security List below "Default Security List for vcn-20221212-1313". Add Ingress Rules: Check Stateless, Source CIDR: 0.0.0.0/0, IP Protocol: ALL, Destination Port Range: YOUR CHOOSEN WIREGUARD PORT. For example 51820. (I did the same for egress rules as well.)

You also need to append PostUP and PostDown rules to the [Interface] block in the wg0.conf file that call some shell scripts (I don't know why, these just worked. If you can get away with not doing this, good for you) I also commented out the IPv6 lines, becuase I won't be using them.

PostUp = /etc/wireguard/helper/add-nat-routing.sh
PostDown = /etc/wireguard/helper/remove-nat-routing.sh


Contents of /etc/wireguard/helper/add-nat-routing.sh:
#!/bin/bash
IPT="/sbin/iptables"
IPT6="/sbin/ip6tables"

IN_FACE="ens3"                   # NIC connected to the internet
WG_FACE="wg0"                    # WG NIC
SUB_NET="10.0.0.1/24"          # WG IPv4 sub/net aka CIDR
WG_PORT="51820"                  # WG udp port
SUB_NET_6="fd42:42:42::/64"      # WG IPv6 sub/net

## IPv4 ##
$IPT -t nat -I POSTROUTING 1 -s $SUB_NET -o $IN_FACE -j MASQUERADE
$IPT -I INPUT 1 -i $WG_FACE -j ACCEPT
$IPT -I FORWARD 1 -i $IN_FACE -o $WG_FACE -j ACCEPT
$IPT -I FORWARD 1 -i $WG_FACE -o $IN_FACE -j ACCEPT
$IPT -I INPUT 1 -i $IN_FACE -p udp --dport $WG_PORT -j ACCEPT

## IPv6 (Uncomment) ##
$IPT6 -t nat -I POSTROUTING 1 -s $SUB_NET_6 -o $IN_FACE -j MASQUERADE
$IPT6 -I INPUT 1 -i $WG_FACE -j ACCEPT
$IPT6 -I FORWARD 1 -i $IN_FACE -o $WG_FACE -j ACCEPT
$IPT6 -I FORWARD 1 -i $WG_FACE -o $IN_FACE -j ACCEPT

Contents of /etc/wireguard/helper/remove-nat-routing.sh
#!/bin/bash
IPT="/sbin/iptables"
IPT6="/sbin/ip6tables"

IN_FACE="ens3"                   # NIC connected to the internet
WG_FACE="wg0"                    # WG NIC
SUB_NET="10.66.66.0/24"          # WG IPv4 sub/net aka CIDR
WG_PORT="59075"                  # WG udp port
SUB_NET_6="fd42:42:42::/64"      # WG IPv6 sub/net

# IPv4 rules #
$IPT -t nat -D POSTROUTING -s $SUB_NET -o $IN_FACE -j MASQUERADE
$IPT -D INPUT -i $WG_FACE -j ACCEPT
$IPT -D FORWARD -i $IN_FACE -o $WG_FACE -j ACCEPT
$IPT -D FORWARD -i $WG_FACE -o $IN_FACE -j ACCEPT
$IPT -D INPUT -i $IN_FACE -p udp --dport $WG_PORT -j ACCEPT

# IPv6 rules (uncomment) #
$IPT6 -t nat -D POSTROUTING -s $SUB_NET_6 -o $IN_FACE -j MASQUERADE
$IPT6 -D INPUT -i $WG_FACE -j ACCEPT
$IPT6 -D FORWARD -i $IN_FACE -o $WG_FACE -j ACCEPT
$IPT6 -D FORWARD -i $WG_FACE -o $IN_FACE -j ACCEPT

Launch Wireguard on the server

If you haven't configured your client and put it's public key into the config file, you won't be able to connect to it. (You can come back to this later after you've done so)

For distros running systemd: (If you don't know what that means, don't worry about it, you're probably using it)
sudo systemctl start wg-quick@wg0

Enable it to start automatically on boot if you want:
sudo systemctl enable wg-quick@wg0

If you messed it up, and it gives you an error saying that it couldn't start, check what happened:
sudo systemctl status wg-quick@wg0
Usually it will just be a typo in your config (or in the script if you're using oracle like I am)

After you think you've fixed it, or you just want to update the config, you can restart it:
sudo systemctl restart wg-quick@wg0

You can check up on what wireguard is doing by using sudo wg. It should return something like this
$ sudo wg
interface: wg0
public key: <server's public key>
private key: (hidden)
listening port: 51820

peer: <peer's public key>
allowed ips: 10.0.0.2/32

Set up the Client

Remember, if the server's config doesn't have the client's public key, or if the client doesn't have the server's public key, it won't be able to connect.

Linux

https://www.wireguard.com/install/

For the client on linux, it's basically identical, the only difference being that you don't need to enable ipv4 forwarding, and the content of the wg0.conf file is going to look like this instead:


[Interface]
PrivateKey = <private key of the client>
Address = 10.0.100.2/32

[Peer]
PublicKey = <public key of the server>
AllowedIPs = 0.0.0.0/1, 128.0.0.0/1
Endpoint = <Public IP of your server>:<your port (in this guide, we've been using 51820)>


Make sure that you remember to put the client's public key in the server's [Peer] block, and the server's public key in the client's [Peer] block.

As a checklist, here are the steps:

  • Make public and private keys
  • Paste the public key into the [Peer] block on the server
  • Make the wg.conf file
  • Set permissions to 600 and move to /etc/wireguard
  • Use systemctl to start the service

Now you should be able to #launch wireguard on the server, and use the same process on the client to connect the two.

Windows

https://www.wireguard.com/install/

After opening the program, there should be a button at the bottom left that says "Add Tunnel" with a drop down menu next to it. Expand the menu and click "Add empty tunnel"

This will bring up a window with an option to name the tunnel (name it whatever you want), you client's public key (which you need to put in the server's [Peer] block), and a text box for the configuration.

You should enter something like this


[Interface]
PrivateKey = <private key of the client>
Address = 10.0.100.2/32

[Peer]
PublicKey = <public key of the server>
AllowedIPs = 0.0.0.0/1, 128.0.0.0/1
Endpoint = <Public IP of your server>:<your port (in this guide, we've been using 51820)>


Now you should be able to #launch wireguard on the server, then click "Activate" in the GUI to connect.

Port Forwarding using IPTables

First, make sure you know what your wan interface is named. You can check it using ip a. Make sure you use the one that says BROADCAST, not LOOPBACK or POINTTOPOINT (that's wireguard). In my case, it's called ens3, becuase oracle is weird but yours will probably be something like eth0.

We're going to be using this command to open ports.
sudo iptables -t nat -A PREROUTING -i ens3 -p tcp --dport 8000 -j DNAT --to-destination 10.0.0.2
after -i, you need to put your WAN interface, after -p, you need to put the protocol you want to forward, in my case TCP, but if you need UDP you can use that. --dport specifies what port to open, and --to-destination should be the "local" ip through the vpn of your client machine hosting the application.

You can also use the -m multiport and --dports instead of --dport to specify multiple ports to save some time.
sudo iptables -t nat -A PREROUTING -i ens3 -p tcp -m multiport --dports 8000,8080 -j DNAT --to-destination 10.0.0.2

I don't really know what all the other stuff does, but if you want to learn more about how this works, you can use man iptables and read through what does what.

Guides I used

https://www.wireguard.com/quickstart/
https://linuxconfig.org/how-to-create-a-vpn-on-ubuntu-20-04-using-wireguard
https://www.reddit.com/r/WireGuard/comments/oxmcvx/cant_seem_to_get_wireguard_working_on_oracle/
https://serverfault.com/questions/1067746/port-forwarding-with-wireguard

Edit
Pub: 15 Apr 2023 05:22 UTC
Edit: 24 Aug 2024 12:04 UTC
Views: 228