Skip to main content
Back to Category

Port Forwarding and NAT Configuration: iptables Guide

NAT concepts, DNAT/SNAT rules, port forwarding with iptables and nftables, masquerading, and use cases: game servers, web servers behind NAT.

Read time: 13 min Security
port forwardingnatiptablesdnatsnatmasqueradelinuxnetwork configuration

Table of Contents

Port Forwarding and NAT Configuration: iptables Guide

Port forwarding and NAT (Network Address Translation) are fundamental tools for managing network traffic. You use these techniques to expose services behind a server to the outside, set up game servers, or manage multiple services over a single IP. This guide teaches you how to configure NAT and port forwarding with iptables and nftables.

What is NAT?

NAT (Network Address Translation) is a network technique that modifies the source or destination addresses of IP packets. There are two main types:

  • SNAT (Source NAT): Changes the source IP address — used for traffic going from internal network to outside
  • DNAT (Destination NAT): Changes the destination IP address — used to route incoming traffic to internal network
  • Masquerade: Special SNAT type for dynamic IPs

Basic Concepts

Internet → [Server: 203.0.113.1] → [Internal Network: 192.168.1.0/24]
                                         ↓
                                   [Web: 192.168.1.10:80]
                                   [DB: 192.168.1.20:3306]
                                   [Game: 192.168.1.30:27015]

Enabling IP Forwarding

IP forwarding must be enabled first for port forwarding:

hljs bash
# Enable temporarily
sudo sysctl -w net.ipv4.ip_forward=1

# Enable permanently
sudo nano /etc/sysctl.conf
# Add this line:
# net.ipv4.ip_forward=1

# Apply changes
sudo sysctl -p

# Verify
cat /proc/sys/net/ipv4/ip_forward
# Output: 1

Port Forwarding with iptables (DNAT)

Basic Port Forwarding

hljs bash
# Forward external port 80 to internal server
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.1.10:80

# Forward external port 443 to internal server
sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j DNAT --to-destination 192.168.1.10:443

# Forward to different port number (external 8080 → internal 80)
sudo iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.10:80

# Allow forwarded traffic
sudo iptables -A FORWARD -p tcp -d 192.168.1.10 --dport 80 -j ACCEPT
sudo iptables -A FORWARD -p tcp -d 192.168.1.10 --dport 443 -j ACCEPT

Forward Traffic from Specific IP

hljs bash
# Forward traffic only from specific IP
sudo iptables -t nat -A PREROUTING -s 203.0.113.5 -p tcp --dport 22 -j DNAT --to-destination 192.168.1.5:22

# Forward traffic from specific network interface
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 3306 -j DNAT --to-destination 192.168.1.20:3306

UDP Port Forwarding

hljs bash
# UDP port forwarding for game server
sudo iptables -t nat -A PREROUTING -p udp --dport 27015 -j DNAT --to-destination 192.168.1.30:27015
sudo iptables -A FORWARD -p udp -d 192.168.1.30 --dport 27015 -j ACCEPT

# DNS forwarding
sudo iptables -t nat -A PREROUTING -p udp --dport 53 -j DNAT --to-destination 192.168.1.5:53
sudo iptables -t nat -A PREROUTING -p tcp --dport 53 -j DNAT --to-destination 192.168.1.5:53

SNAT and Masquerade

hljs bash
# Masquerade — for dynamic IP (internet connection sharing)
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

# SNAT — for static IP (more efficient)
sudo iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source 203.0.113.1

# Masquerade traffic from specific network
sudo iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE

Complete NAT Configuration

hljs bash
# Complete NAT + port forwarding configuration

# 1. Clear existing rules
sudo iptables -F
sudo iptables -t nat -F
sudo iptables -t mangle -F

# 2. Default policies
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT

# 3. Loopback and established connections
sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

# 4. SSH access
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# 5. Port forwarding rules
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.1.10:80
sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j DNAT --to-destination 192.168.1.10:443
sudo iptables -t nat -A PREROUTING -p udp --dport 27015 -j DNAT --to-destination 192.168.1.30:27015

# 6. Forward rules
sudo iptables -A FORWARD -p tcp -d 192.168.1.10 --dport 80 -j ACCEPT
sudo iptables -A FORWARD -p tcp -d 192.168.1.10 --dport 443 -j ACCEPT
sudo iptables -A FORWARD -p udp -d 192.168.1.30 --dport 27015 -j ACCEPT

# 7. Masquerade
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

# 8. Save rules
sudo apt install iptables-persistent -y
sudo netfilter-persistent save

Port Forwarding with nftables

#!/usr/sbin/nft -f

flush ruleset

table ip nat {
    chain prerouting {
        type nat hook prerouting priority -100;
        
        # Web server port forwarding
        tcp dport 80 dnat to 192.168.1.10:80
        tcp dport 443 dnat to 192.168.1.10:443
        
        # Game server UDP forwarding
        udp dport 27015 dnat to 192.168.1.30:27015
        
        # Forward to different port number
        tcp dport 8080 dnat to 192.168.1.10:80
    }
    
    chain postrouting {
        type nat hook postrouting priority 100;
        oif eth0 masquerade
    }
}

table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;
        iif lo accept
        ct state established,related accept
        tcp dport 22 accept
    }
    
    chain forward {
        type filter hook forward priority 0; policy drop;
        ct state established,related accept
        ip daddr 192.168.1.10 tcp dport { 80, 443 } accept
        ip daddr 192.168.1.30 udp dport 27015 accept
    }
    
    chain output {
        type filter hook output priority 0; policy accept;
    }
}

Use Cases

Use Case 1: Game Server (CS2, Minecraft)

hljs bash
# CS2 server
sudo iptables -t nat -A PREROUTING -p udp --dport 27015 -j DNAT --to-destination 192.168.1.30:27015
sudo iptables -t nat -A PREROUTING -p tcp --dport 27015 -j DNAT --to-destination 192.168.1.30:27015
sudo iptables -A FORWARD -d 192.168.1.30 -p udp --dport 27015 -j ACCEPT
sudo iptables -A FORWARD -d 192.168.1.30 -p tcp --dport 27015 -j ACCEPT

# Minecraft server
sudo iptables -t nat -A PREROUTING -p tcp --dport 25565 -j DNAT --to-destination 192.168.1.31:25565
sudo iptables -A FORWARD -d 192.168.1.31 -p tcp --dport 25565 -j ACCEPT

Use Case 2: Web Server Behind NAT

hljs bash
# HTTP and HTTPS forwarding
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 192.168.1.10:80
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j DNAT --to-destination 192.168.1.10:443
sudo iptables -A FORWARD -i eth0 -d 192.168.1.10 -p tcp -m multiport --dports 80,443 -j ACCEPT

Use Case 3: SSH Port Remapping

hljs bash
# Forward external port 2222 to internal port 22
sudo iptables -t nat -A PREROUTING -p tcp --dport 2222 -j DNAT --to-destination 192.168.1.5:22
sudo iptables -A FORWARD -d 192.168.1.5 -p tcp --dport 22 -j ACCEPT

Making Rules Persistent

hljs bash
# With iptables-persistent
sudo apt install iptables-persistent -y
sudo netfilter-persistent save

# Manually
sudo iptables-save > /etc/iptables/rules.v4
sudo ip6tables-save > /etc/iptables/rules.v6

Troubleshooting

hljs bash
# View NAT table
sudo iptables -t nat -L -n -v

# View connection tracking table
sudo conntrack -L

# Monitor traffic on specific port
sudo tcpdump -i eth0 port 80

# Check IP forwarding
cat /proc/sys/net/ipv4/ip_forward

# Count rule matches
sudo iptables -t nat -L -n -v | grep -v "0     0"

After adding port forwarding rules, don't forget to add both PREROUTING (DNAT) and FORWARD rules. Adding only the DNAT rule is not enough — traffic must also be permitted in the FORWARD chain.

Conclusion

Port forwarding and NAT are fundamental components of Linux network management. By properly configuring DNAT, SNAT, and masquerade rules with iptables or nftables, you can expose game servers, web services, and other applications from behind NAT.