How to get a static IP for any device
Many users face a common problem: their ISP assigns a dynamic IP or uses CGNAT, making it impossible to accept incoming connections. Renting a static IP costs money, and sometimes it's not even available. The solution is to set up a WireGuard VPN server on a VPS with port forwarding. In this article, we'll cover how to configure such a server and connect clients to it.
Why You Need WireGuard with Port Forwarding
There are many scenarios where you need to accept incoming connections to a device behind your ISP's NAT:
- Game servers — hosting Minecraft, CS2, Valheim, and other games on your home PC
- Remote access — connecting to your home computer via RDP, SSH, or VNC
- Web development — demonstrating local projects to clients
- IoT and smart home — accessing cameras, controllers, and sensors from outside
- File servers — FTP, SFTP, Nextcloud on your home NAS
- Mobile proxies — setting up incoming connections to proxy servers on modems
WireGuard is ideal for this task thanks to its high performance, minimal latency, and ease of configuration. Unlike OpenVPN, WireGuard operates at the Linux kernel level and provides throughput close to native.
How It Works
The solution architecture looks as follows:
When an external client connects to the VPS IP address on a port in the 64000–64199 range, the server forwards the traffic through the WireGuard tunnel to your device (10.8.0.2). Your application receives the connection as if the client connected directly.
Requirements
For the Server (VPS)
- VPS with a public IP address (a minimal plan from $3-5/month will work)
- Ubuntu 20.04/22.04/24.04 or Debian 11/12
- Root access
- Open UDP port 51820 (for WireGuard)
- Open TCP/UDP ports for forwarding (in our example: 64000–64399)
For the Client
- Any OS with WireGuard support: Windows, Linux, macOS, Android, iOS
- WireGuard client installed
Installing WireGuard on the Server
Connect to the server via SSH and run the following commands:
1. Update the System
apt update && apt upgrade -y
2. Install WireGuard
apt install wireguard wireguard-tools -y
3. Enable IP Forwarding
This is a critical step — without it, port forwarding won't work:
# Enable immediately
echo 1 > /proc/sys/net/ipv4/ip_forward
# Make it persistent after reboot
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p
4. Generate Server Keys
# Create the config directory (if it doesn't exist)
mkdir -p /etc/wireguard
cd /etc/wireguard
# Generate server private and public keys
wg genkey | tee server_private.key | wg pubkey > server_public.key
# Set secure permissions
chmod 600 server_private.key
# View the keys
echo "Server private key:"
cat server_private.key
echo "Server public key:"
cat server_public.key
Important: save the server's public key — you'll need it for client configuration.
5. Generate Client Keys
# Keys for client 1
wg genkey | tee client1_private.key | wg pubkey > client1_public.key
# Keys for client 2
wg genkey | tee client2_private.key | wg pubkey > client2_public.key
# View
echo "=== Client 1 ==="
echo "Private: $(cat client1_private.key)"
echo "Public: $(cat client1_public.key)"
echo "=== Client 2 ==="
echo "Private: $(cat client2_private.key)"
echo "Public: $(cat client2_public.key)"
Server Configuration
Create the WireGuard configuration file:
nano /etc/wireguard/wg0.conf
Paste the following config, replacing the keys with your own:
[Interface]
# Server IP address in the VPN network
Address = 10.8.0.1/24
# Port for client connections
ListenPort = 51820
# Server private key (from server_private.key file)
PrivateKey = YOUR_SERVER_PRIVATE_KEY
# Don't overwrite config on shutdown
SaveConfig = false
# ============================================
# NAT for client internet access
# ============================================
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT
PostUp = iptables -A FORWARD -o wg0 -j ACCEPT
PostUp = iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT
PostDown = iptables -D FORWARD -o wg0 -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
# ============================================
# Port forwarding for client 1 (10.8.0.2)
# Range: 64000–64199 (200 ports)
# ============================================
# TCP
PostUp = iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 64000:64199 -j DNAT --to-destination 10.8.0.2
PostDown = iptables -t nat -D PREROUTING -i eth0 -p tcp --dport 64000:64199 -j DNAT --to-destination 10.8.0.2
# UDP
PostUp = iptables -t nat -A PREROUTING -i eth0 -p udp --dport 64000:64199 -j DNAT --to-destination 10.8.0.2
PostDown = iptables -t nat -D PREROUTING -i eth0 -p udp --dport 64000:64199 -j DNAT --to-destination 10.8.0.2
# ============================================
# Port forwarding for client 2 (10.8.0.3)
# Range: 64200–64399 (200 ports)
# ============================================
# TCP
PostUp = iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 64200:64399 -j DNAT --to-destination 10.8.0.3
PostDown = iptables -t nat -D PREROUTING -i eth0 -p tcp --dport 64200:64399 -j DNAT --to-destination 10.8.0.3
# UDP
PostUp = iptables -t nat -A PREROUTING -i eth0 -p udp --dport 64200:64399 -j DNAT --to-destination 10.8.0.3
PostDown = iptables -t nat -D PREROUTING -i eth0 -p udp --dport 64200:64399 -j DNAT --to-destination 10.8.0.3
# ============================================
# Clients
# ============================================
# Client 1
[Peer]
PublicKey = CLIENT_1_PUBLIC_KEY
AllowedIPs = 10.8.0.2/32
# Client 2
[Peer]
PublicKey = CLIENT_2_PUBLIC_KEY
AllowedIPs = 10.8.0.3/32
⚠️ Important Notes on the Config:
- eth0 — the network interface name. On your server, it might be different (ens3, enp0s3, etc.). Check with the
ip acommand - SaveConfig = false — must be set to false, otherwise WireGuard will overwrite the config on shutdown and iptables rules will be lost
- -i eth0 in PREROUTING rules — specifies the incoming interface, improves security
Determining the Network Interface Name
# Find the interface with the external IP
ip route get 8.8.8.8 | grep -oP 'dev \K\S+'
If the command returns something other than eth0, replace eth0 in the config with the returned value.
Starting WireGuard
# Start WireGuard
wg-quick up wg0
# Enable auto-start on system boot
systemctl enable wg-quick@wg0
# Check status
wg show
You should see information about the wg0 interface and registered peers.
Client Configuration
On the client device, create a configuration file. For Windows and macOS, this is done through the WireGuard GUI application ("Add Tunnel" → "Add empty tunnel").
Config for Client 1 (receives ports 64000–64199)
[Interface]
# Client private key (from client1_private.key file)
PrivateKey = CLIENT_1_PRIVATE_KEY
# Client IP address in the VPN network
Address = 10.8.0.2/32
# DNS server (optional, can be removed)
DNS = 1.1.1.1
[Peer]
# Server public key (from server_public.key file)
PublicKey = SERVER_PUBLIC_KEY
# Route all traffic through VPN
AllowedIPs = 0.0.0.0/0, ::/0
# IP address and port of your VPS
Endpoint = YOUR_SERVER_IP:51820
# Keep connection alive (important for NAT)
PersistentKeepalive = 25
Config for Client 2 (receives ports 64200–64399)
[Interface]
PrivateKey = CLIENT_2_PRIVATE_KEY
Address = 10.8.0.3/32
DNS = 1.1.1.1
[Peer]
PublicKey = SERVER_PUBLIC_KEY
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = YOUR_SERVER_IP:51820
PersistentKeepalive = 25
???? AllowedIPs Options
The AllowedIPs parameter determines which traffic goes through the VPN:
0.0.0.0/0, ::/0— all traffic (IPv4 and IPv6) through VPN. Your external IP will change to the server's IP.0.0.0.0/1, 128.0.0.0/1, ::/1, 8000::/1— same thing, but without hijacking the default route (solves issues with some systems)10.8.0.0/24— only traffic to the VPN network. Internet goes directly, but port forwarding still works
PersistentKeepalive — Why It's Needed
The PersistentKeepalive = 25 parameter makes the client send keepalive packets to the server every 25 seconds. This is necessary for two reasons:
- NAT traversal — home routers "forget" UDP connections after 30-120 seconds of inactivity. Keepalive maintains the mapping active.
- Incoming connections — the server needs to know the client's current endpoint to send traffic. Without keepalive, the server will "lose" the client after idle time.
Firewall Configuration
Make sure the necessary ports are open on the server:
For UFW (Ubuntu)
# WireGuard port
ufw allow 51820/udp
# Ports for forwarding (client 1)
ufw allow 64000:64199/tcp
ufw allow 64000:64199/udp
# Ports for forwarding (client 2)
ufw allow 64200:64399/tcp
ufw allow 64200:64399/udp
# Apply changes
ufw reload
# Check status
ufw status
For iptables (without UFW)
# WireGuard port
iptables -A INPUT -p udp --dport 51820 -j ACCEPT
# Ports for forwarding
iptables -A INPUT -p tcp --dport 64000:64399 -j ACCEPT
iptables -A INPUT -p udp --dport 64000:64399 -j ACCEPT
# Save rules
apt install iptables-persistent -y
netfilter-persistent save
Checking on the Hosting Provider
Some VPS providers have an additional firewall in their control panel. Check the settings in your hosting dashboard and open ports 51820/udp and 64000–64399 tcp/udp there.
Testing
1. Checking Client Connection
After connecting the client, run on the server:
wg show
You should see information about the connected peer with the latest handshake:
interface: wg0
public key: xxxxx
private key: (hidden)
listening port: 51820
peer: CLIENT_PUBLIC_KEY
endpoint: CLIENT_IP:PORT
allowed ips: 10.8.0.2/32
latest handshake: 5 seconds ago
transfer: 1.25 MiB received, 3.50 MiB sent
2. Testing Port Forwarding
On the client device, start a test server:
# Python 3 (simple HTTP server on port 64100)
python3 -m http.server 64100
# Or netcat for TCP
nc -l -p 64100
From another device (not connected to the VPN), try to connect:
# Via browser
http://YOUR_SERVER_IP:64100
# Or via curl
curl http://YOUR_SERVER_IP:64100
# Or netcat
nc YOUR_SERVER_IP 64100
3. Testing UDP
# On the client (listening for UDP)
nc -u -l -p 64100
# From an external device
echo "test" | nc -u YOUR_SERVER_IP 64100
4. Checking iptables Rules on the Server
# View NAT rules
iptables -t nat -L -n -v
# You should see DNAT rules for your port ranges
Troubleshooting
Client Won't Connect
- Check if WireGuard is running on the server:
systemctl status wg-quick@wg0 - Check if port 51820/udp is open on the server firewall
- Make sure the server's public key in the client config matches the key on the server
- Verify the server IP address in Endpoint is correct
Connected but Port Forwarding Doesn't Work
- Check IP forwarding:
cat /proc/sys/net/ipv4/ip_forward(should be 1) - Check the network interface name in the config (eth0, ens3, etc.)
- Make sure ports are open on the firewall
- Check if the application on the client is listening on the required port
Connection Drops Periodically
- Make sure PersistentKeepalive is set in the client config
- Try reducing the value to 15-20 seconds
Slow Speed
- Try changing MTU in the [Interface] section:
MTU = 1420 - Check CPU load on the server
- Choose a VPS geographically closer to you
Viewing Logs
# WireGuard logs
dmesg | grep wireguard
# System logs
journalctl -u wg-quick@wg0 -f
# iptables debugging (DNAT logging)
iptables -t nat -I PREROUTING -p tcp --dport 64000:64199 -j LOG --log-prefix "DNAT: "
dmesg | grep DNAT
Scaling: Adding New Clients
To add a new client:
- Generate a new key pair
- Choose an available IP (10.8.0.4, 10.8.0.5, etc.)
- Choose an available port range (64400–64599, etc.)
- Add the [Peer] section and iptables rules to the server config
- Restart WireGuard:
wg-quick down wg0 && wg-quick up wg0
Example of adding client 3:
# Add to /etc/wireguard/wg0.conf
# Port forwarding for client 3 (10.8.0.4)
PostUp = iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 64400:64599 -j DNAT --to-destination 10.8.0.4
PostDown = iptables -t nat -D PREROUTING -i eth0 -p tcp --dport 64400:64599 -j DNAT --to-destination 10.8.0.4
PostUp = iptables -t nat -A PREROUTING -i eth0 -p udp --dport 64400:64599 -j DNAT --to-destination 10.8.0.4
PostDown = iptables -t nat -D PREROUTING -i eth0 -p udp --dport 64400:64599 -j DNAT --to-destination 10.8.0.4
# At the end of the file
[Peer]
PublicKey = CLIENT_3_PUBLIC_KEY
AllowedIPs = 10.8.0.4/32
Conclusion
WireGuard with port forwarding is an elegant solution for getting a "static IP" without having to pay your ISP or change your plan. A single inexpensive VPS can serve dozens of clients, each receiving their own set of ports for incoming connections.
Advantages of this approach:
- Cost savings — a VPS for $3-5/month is cheaper than a static IP from most ISPs
- Flexibility — you can quickly change port ranges and add clients
- Security — all traffic is encrypted, real IP is hidden
- Performance — WireGuard provides minimal overhead
- Reliability — connection automatically recovers after disconnections
If you use mobile proxies from mobileproxy.space, this setup allows you to organize stable access to proxy servers running on modems behind the ISP's NAT.
Frequently Asked Questions
Can I forward port 80 or 443?
Yes, but many hosting providers block these ports by default. Also keep in mind that some ISPs filter incoming traffic on standard ports.
How many clients can connect to one server?
Theoretically — thousands. Practically, the limitation is determined by the server's bandwidth and the number of available ports (65535 minus system ports).
Does this work with IPv6?
Yes, but additional ip6tables configuration is required. In this article, we covered IPv4 only.
What if I have multiple network interfaces on the server?
Specify the specific interface in iptables rules using the -i parameter for PREROUTING and -o for POSTROUTING.