If you’re like many who face the frustrating limitations of Carrier-Grade NAT (CGNAT), you might struggle to expose services hosted on your home server to the internet. CGNAT makes it challenging to access your server remotely because you don’t have a public IP address. In this guide, I’ll walk you through a method to route traffic through a Virtual Private Server (VPS) using WireGuard. This solution ensures reliable and secure connectivity, even behind CGNAT.
Overview
The goal is to use a VPS with a public IP address as a relay point for your traffic. We’ll use WireGuard, a fast and lightweight VPN, to create a secure tunnel between the VPS and your home server. Once the tunnel is established, we’ll configure iptables
on the VPS to forward traffic to your home server. This guide is based on this excellent tutorial but adapted for clarity and specific use cases.
The steps in this guide assume both the VPS and the home server are running Ubuntu (version 20.04 or later).
To better understand the flow of traffic in this setup, here’s a visual representation of how the connection between the user, VPS, and home server is established and maintained. The VPS acts as a bridge, routing traffic between the internet and your home server via a WireGuard tunnel:
What You’ll Need
- A VPS with a public IP: Make sure your VPS provider supports Kernel-based Virtual Machines (KVM). I recommend these providers:
- A home server behind CGNAT: This can be any device on your local network. I like to use HP’s Elite Desk Mini PCs such as this one.
- WireGuard installed on both VPS and home server.
- Basic understanding of Linux commands and networking.
Check VPS Networking Configuration
Before proceeding, ensure your VPS provider does not have firewall rules or networking restrictions that could block traffic. Some providers enforce default firewall settings that might prevent incoming connections to your VPS’s public IP or interfere with forwarding traffic through the WireGuard tunnel. Check your VPS control panel or contact your provider to confirm:
- Inbound rules: Ensure the necessary ports (e.g.,
55107
for WireGuard and ports for HTTP/SSH) are open. - Outbound rules: Ensure your VPS can establish outbound connections to your home server through the WireGuard tunnel.
Without the proper configuration, your setup may fail to work as expected. Adjust these settings as needed before proceeding.
Enable IP Forwarding on the VPS
IP forwarding allows the VPS to route traffic between its interfaces.
-
Check if IP forwarding is enabled:
1cat /proc/sys/net/ipv4/ip_forward
If it outputs
0
, it’s disabled. -
Enable IP forwarding temporarily:
1sudo sysctl -w net.ipv4.ip_forward=1
-
Make IP forwarding persistent across reboots:
1echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.conf 2sudo sysctl -p
Install WireGuard
Install WireGuard on both the VPS and the Home Server:
1sudo apt install wireguard
Configure WireGuard
On both the VPS and the Home Server, generate WireGuard keys:
-
Create the initial configuration file:
1umask 077 && printf "[Interface]\nPrivateKey = " | sudo tee /etc/wireguard/wg0.conf > /dev/null
-
Generate private and public keys:
1wg genkey | sudo tee -a /etc/wireguard/wg0.conf | wg pubkey | sudo tee /etc/wireguard/publickey
wg0.conf
: Stores the private key for WireGuard.publickey
: Contains the public key for sharing.
-
Note down both public keys. These will be used to configure the tunnel between the VPS and the Home Server.
On the VPS:
Edit /etc/wireguard/wg0.conf
:
1[Interface]
2PrivateKey = YOUR_VPS_PRIVATE_KEY
3ListenPort = 55107
4Address = 192.168.4.1/24
5
6[Peer]
7PublicKey = YOUR_HOME_SERVER_PUBLIC_KEY
8AllowedIPs = 192.168.4.2/32
On the Home Server:
Edit /etc/wireguard/wg0.conf
:
1[Interface]
2PrivateKey = YOUR_HOME_SERVER_PRIVATE_KEY
3Address = 192.168.4.2/24
4
5[Peer]
6PublicKey = YOUR_VPS_PUBLIC_KEY
7AllowedIPs = 192.168.4.1/32
8Endpoint = VPS_PUBLIC_IP:55107
9PersistentKeepalive = 25
Start WireGuard
Run these commands on both the VPS and the Home Server to start WireGuard:
-
Start WireGuard:
1sudo systemctl start wg-quick@wg0
-
Enable it to start on boot:
1sudo systemctl enable wg-quick@wg0
-
Verify the connection:
1sudo wg show
If the setup is correct, you should see a handshake between the VPS and the Home Server.
Forward Traffic Using iptables
This step should be performed on the VPS to forward incoming traffic to your Home Server.
Forwarding HTTP Traffic (Port 80)
-
Add the following
iptables
rules:1sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 192.168.4.2:80 2sudo iptables -t nat -A POSTROUTING -o wg0 -p tcp --dport 80 -d 192.168.4.2 -j SNAT --to-source 192.168.4.1 3sudo iptables -A FORWARD -i eth0 -o wg0 -p tcp --dport 80 -m conntrack --ctstate NEW,ESTABLISHED,RELATED -j ACCEPT 4sudo iptables -A FORWARD -i wg0 -o eth0 -p tcp --sport 80 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-
Save the rules with
netfilter-persistent
to make them persistent:1sudo apt install iptables-persistent 2sudo netfilter-persistent save 3sudo netfilter-persistent reload
Forwarding SSH Traffic
This step should be performed on the VPS to allow SSH access to your Home Server. SSH forwarding allows you to connect to your Home Server by first connecting to your VPS and having the VPS route the SSH traffic through the WireGuard tunnel.
Configure SSH Forwarding
-
Add these
iptables
rules:1sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 2222 -j DNAT --to-destination 192.168.4.2:22 2sudo iptables -t nat -A POSTROUTING -o wg0 -p tcp --dport 22 -d 192.168.4.2 -j SNAT --to-source 192.168.4.1 3sudo iptables -A FORWARD -i eth0 -o wg0 -p tcp --dport 22 -m conntrack --ctstate NEW,ESTABLISHED,RELATED -j ACCEPT 4sudo iptables -A FORWARD -i wg0 -o eth0 -p tcp --sport 22 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-
Test SSH to your Home Server via the VPS:
1ssh -p 2222 <username>@<VPS_PUBLIC_IP>
Remember to save the rules with netfilter-persistent
to make them persistent.
Retain Direct Access to the VPS
The SSH forwarding rules won’t affect your ability to SSH directly to the VPS via its default port (22). If needed, explicitly allow direct SSH access:
1sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
Testing the Setup
Verify HTTP traffic by navigating to your VPS’s public IP in a browser:
1http://<VPS_PUBLIC_IP>
Test SSH by connecting to the VPS:
1ssh <username>@<VPS_PUBLIC_IP>
SSH into your Home Server via the VPS:
1ssh -p 2222 <username>@<VPS_PUBLIC_IP>
By following this guide, you’ve successfully exposed a Home Server behind CGNAT using WireGuard and a VPS. This setup allows you to securely forward traffic to your Home Server, including HTTP and SSH, while retaining direct access to your VPS.