Port forwarding behind NAT (Using Only WireGuard)

things from boards above, but in an international language
Post Reply
User avatar
samo Offline
Posts: 8
Joined: Sun Jul 21, 2024 10:15 pm
Description: ja som samo (pochopitelne).
Contact:

Port forwarding behind NAT (Using Only WireGuard)

Post by samo »


So this is alternative version to this tutorial where NGINX is used alongside WireGuard. Recently we've have changed our internet provider to another one that provides 1Gbit symmetric (1000Mbps Down / 1000Mbps Up).
very fast car - fabia - depicting my internet speed
very fast car - fabia - depicting my internet speed
fabia-vvrm.gif (99.14 KiB) Viewed 43 times
Sadly if you don't pay for business type of connection (which is slower and more expensive, but provides public IPv4 address) you are still stuck behind NAT.

As a example I will show how to setup QBittorrent LXC behind NAT

You need:
  • VPS or some kind of server somewhere with public IP that has connection same or higher than your WAN speed (Oracle provides free tier ARM servers, with 4Gbit WAN connection, but they are very hard to get) and close to you so the latency won't suck
  • Server at home (I will focus on Linux only in this tutorial, but it should be applicable to Windows as well)

Update and installation
This is section is for both servers (VPS and QB)
Update packages:

Code: Select all

root@server:~# apt update && apt upgrade -y
Install WireGuard:

Code: Select all

root@server:~# apt install wireguard -y
Next, generate config files (/etc/wireguard/wg0.conf) :

Code: Select all

root@server:~# (umask 077 && printf "[Interface]\nPrivateKey= " | sudo tee /etc/wireguard/wg0.conf > /dev/null)
Next, generate private and public key (public key will be shown in your console log, copy it and save it somewhere):

Code: Select all

root@server:~# wg genkey | sudo tee -a /etc/wireguard/wg0.conf | wg pubkey | sudo tee /etc/wireguard/publickey

Configuration

We need our VPS WAN interface name:

Code: Select all

root@vps:~# ip a
Output will look like this:

Code: Select all

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc mq state UP group default qlen 1000
    link/ether XX:XX:XX:XX:XX:XX brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.36/24 brd 10.0.0.255 scope global enp0s3
       valid_lft forever preferred_lft forever
    inet6 fe80::17ff:fe03:25a2/64 scope link
       valid_lft forever preferred_lft forever
...
Some entries were removed, yours might look different

My WAN interface is called enp0s3

Edit WireGuard’s config file:

Code: Select all

root@vps:~# nano /etc/wireguard/wg0.conf

Code: Select all

[Interface]
PrivateKey= <your generated very secret private key from your VPS>
ListenPort = 51115 #Choose random port
Address = 192.168.33.1/24

PostUp = iptables -A INPUT -p tcp --dport 51115 -j ACCEPT
PostUp = iptables -A OUTPUT -p tcp --sport 51115 -j ACCEPT
PostUp = iptables -A FORWARD -p tcp --dport 51115 -j ACCEPT
PostUp = iptables -A INPUT -p udp --dport 51115 -j ACCEPT
PostUp = iptables -A OUTPUT -p udp --sport 51115 -j ACCEPT
PostUp = iptables -A FORWARD -p udp --dport 51115 -j ACCEPT
#Allow TCP/UDP traffic on port 51115

[Peer]
PublicKey = <your PUBLIC key from your SERVER (NOT from VPS)>
AllowedIPs = 192.168.33.2/32
#For more peers just increment the IP
Now you need to open ports in your firewall (on VPS), im using UFW:

Code: Select all

root@vps:~# ufw allow 51115
root@vps:~# ufw allow 51115/udp
If your VPS provider (like Oracle) has its own subnet managment, you need to open all of the ports you will be using (WG port, your service port, etc..)


Now the peer (QB) configuration:
Edit WireGuard’s config file:

Code: Select all

root@qb:~# nano /etc/wireguard/wg0.conf

Code: Select all

[Interface]
PrivateKey= <your generated very secret private key from your server>
Address = 192.168.33.2/32 #Same IP address as you chosen in VPS config

[Peer]
PublicKey = <your PUBLIC key from your VPS(NOT from SERVER)>
AllowedIPs = 0.0.0.0/0 #This will forward all of the LXC traffic trough the VPS
Endpoint = <VPS IP>:<VPS PORT>
PersistentKeepalive = 25
Now run on both:

Code: Select all

root@server:~# systemctl enable wg-quick@wg0
root@server:~# systemctl start wg-quick@wg0
Check if WG is running on both:

Code: Select all

root@server:~# systemctl status wg-quick@wg0
Service should be green/active

Code: Select all

root@server:~# ip a
You should now see new entry in the output of the command (it wont look the same but similiar).

VPS:

Code: Select all

10: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 8920 qdisc noqueue state UNKNOWN group default qlen 1000
    link/none
    inet 192.168.33.1/24 scope global wg0
       valid_lft forever preferred_lft forever
QB:

Code: Select all

3: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
    link/none
    inet 192.168.33.3/32 scope global wg0
       valid_lft forever preferred_lft forever
Now we can try to ping the VPS from the QB server:

Code: Select all

root@QB:~# ping 192.168.33.1
PING 192.168.33.1 (192.168.33.1) 56(84) bytes of data.
64 bytes from 192.168.33.1: icmp_seq=1 ttl=64 time=22.2 ms
64 bytes from 192.168.33.1: icmp_seq=2 ttl=64 time=22.4 ms
64 bytes from 192.168.33.1: icmp_seq=3 ttl=64 time=22.5 ms
64 bytes from 192.168.33.1: icmp_seq=4 ttl=64 time=22.2 ms
^C
--- 192.168.33.1 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 22.174/22.328/22.536/0.142 ms
Congratulations, you now have a VPN tunnel :krava:

Very basic diagram:
before forwarding
before forwarding
basic-diag.png (14.67 KiB) Viewed 43 times

Config for forwarding

After we have confirmed that the tunnel pings, we can start with the actual forwarding to our services and clients.

For example we want port 48888 as our QB port for seeding.

Edit WireGuard’s config file on VPS:

Code: Select all

root@vps:~# nano /etc/wireguard/wg0.conf
Add following:

Code: Select all

[Interface]
PrivateKey= <your generated very secret private key from your VPS>
ListenPort = 51115
Address = 192.168.33.1/24

PostUp = iptables -A INPUT -p tcp --dport 51115 -j ACCEPT
PostUp = iptables -A OUTPUT -p tcp --sport 51115 -j ACCEPT
PostUp = iptables -A FORWARD -p tcp --dport 51115 -j ACCEPT
PostUp = iptables -A INPUT -p udp --dport 51115 -j ACCEPT
PostUp = iptables -A OUTPUT -p udp --sport 51115 -j ACCEPT
PostUp = iptables -A FORWARD -p udp --dport 51115 -j ACCEPT


PostUp = sysctl -w net.ipv4.ip_forward=1

PostUp = iptables -t nat -A POSTROUTING -o enp0s3 -j MASQUERADE
PostUp = iptables -t nat -A PREROUTING -i enp0s3 -p tcp --dport 48888 -j DNAT --to-destination 192.168.33.2:48888 
PostUp = iptables -t nat -A PREROUTING -i enp0s3 -p udp --dport 48888 -j DNAT --to-destination 192.168.33.2:48888 
PostUp = iptables -A FORWARD -p tcp -d 192.168.33.2 --dport 48888 -j ACCEPT
PostUp = iptables -A FORWARD -p udp -d 192.168.33.2 --dport 48888 -j ACCEPT
PostUp = iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

PostDown = iptables -t nat -D POSTROUTING -o enp0s3 -j MASQUERADE
PostDown = iptables -t nat -D PREROUTING -i enp0s3 -p tcp --dport 48888 -j DNAT --to-destination 192.168.33.2:48888 
PostDown = iptables -t nat -D PREROUTING -i enp0s3 -p udp --dport 48888 -j DNAT --to-destination 192.168.33.2:48888 
PostDown = iptables -D FORWARD -p tcp -d 192.168.33.2 --dport 48888 -j ACCEPT
PostDown = iptables -D FORWARD -p udp -d 192.168.33.2 --dport 48888 -j ACCEPT
PostDown = iptables -D FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT


[Peer]
PublicKey = <your PUBLIC key from your SERVER (NOT from VPS)>
AllowedIPs = 192.168.33.2/32
I will explain what all of that means:
PostUp - Means command will be run at tunnel startup (eg.: systemctl start wg-quick@wg0)
PostDown - Means command will be run at tunnel shutdown (eg.: systemctl stop wg-quick@wg0)

Code: Select all

PostUp = sysctl -w net.ipv4.ip_forward=1
This enables kernel IPv4 forwarding (since this command is not persistent, and will default to 0 after reboot)

Code: Select all

PostUp = iptables -t nat -A POSTROUTING -o enp0s3 -j MASQUERADE
This enables NAT so VPN clients can access the internet through enp0s3.

Code: Select all

PostUp = iptables -t nat -A PREROUTING -i enp0s3 -p tcp --dport 48888 -j DNAT --to-destination 192.168.33.2:48888 
PostUp = iptables -t nat -A PREROUTING -i enp0s3 -p udp --dport 48888 -j DNAT --to-destination 192.168.33.2:48888 
Any traffic hitting <VPS Public>:48888 will be forwarded to 192.168.33.2:48888

Code: Select all

PostUp = iptables -A FORWARD -p tcp -d 192.168.33.2 --dport 48888 -j ACCEPT
iptables -A FORWARD -p udp -d 192.168.33.2 --dport 48888 -j ACCEPT
These rules allow forwarded traffic to actually pass through the firewall.

Code: Select all

PostUp = iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
This allows reply packets (responses from 192.168.33.2 can go back out)

Every PostDown rule removes ("-D" flag) the corresponding rule added by PostUp. This ensures there are no leftover firewall rules and cleanly shutdown the interface.

Now we also need to allow the port 48888 in our provider subnet firewall as well as UFW.

Restart WG on both systems:

Code: Select all

root@server:~# systemctl restart wg-quick@wg0
You can install Speedtest on your QB server to test the connection and speed (with these settings over the vpn)
after forwarding
after forwarding
forwarded-diag.png (27.89 KiB) Viewed 43 times
qb.png
qb.png (2.46 KiB) Viewed 41 times
Last edited by samo on Sun Feb 15, 2026 2:59 pm, edited 2 times in total.
:trol:
User avatar
samo Offline
Posts: 8
Joined: Sun Jul 21, 2024 10:15 pm
Description: ja som samo (pochopitelne).
Contact:

Re: Port forwarding behind NAT (Using WireGuard and Nginx Reverse Proxy) - Restored Version

Post by samo »

I'm sorry for any grammatical mistakes or incorrect info, dm or email @: samuel@370.network me if you find anything wrong :D
:trol:
Post Reply