When setting up port forwarding with iptables, it's easy to miss crucial components in the rule chain. Your current configuration shows two important rules but lacks the return path NAT configuration.
# Current rules you have:
-A PREROUTING -p tcp -m tcp --dport 8001 -j DNAT --to-destination 192.168.1.200:8080
-A FORWARD -m state -p tcp -d 192.168.1.200 --dport 8080 --state NEW,ESTABLISHED,RELATED -j ACCEPT
Here's the full set of rules needed for successful port forwarding between network interfaces:
# Enable IP forwarding in sysctl
echo 1 > /proc/sys/net/ipv4/ip_forward
# NAT prerouting rule
iptables -t nat -A PREROUTING -i ppp0 -p tcp --dport 8001 -j DNAT --to-destination 192.168.1.200:8080
# Forwarding rule
iptables -A FORWARD -p tcp -d 192.168.1.200 --dport 8080 -j ACCEPT
# Masquerade outbound traffic (important for response packets)
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
# Allow established connections
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
Several factors could still prevent your port forwarding from working:
- Firewall rules blocking the connection on either interface
- Missing kernel module (nf_nat or nf_conntrack)
- Incorrect interface names in your rules
To verify your setup:
# Check NAT table rules
iptables -t nat -L -n -v
# Monitor connections
conntrack -E
# Test connectivity
nc -zv your_public_ip 8001
For more complex scenarios where you need to preserve source IP information:
# Alternative to MASQUERADE that preserves source IP
iptables -t nat -A POSTROUTING -o eth0 -p tcp --dport 8080 -d 192.168.1.200 -j SNAT --to-source 192.168.1.1
# Additional logging for troubleshooting
iptables -N LOGGING
iptables -A INPUT -j LOGGING
iptables -A LOGGING -m limit --limit 2/min -j LOG --log-prefix "IPTables-Dropped: " --log-level 4
iptables -A LOGGING -j DROP
You're trying to forward incoming TCP connections on port 8001 (interface ppp0) to an internal server at 192.168.1.200:8080 (interface eth0). You've set up these iptables rules:
-A PREROUTING -p tcp -m tcp --dport 8001 -j DNAT --to-destination 192.168.1.200:8080
-A FORWARD -m state -p tcp -d 192.168.1.200 --dport 8080 --state NEW,ESTABLISHED,RELATED -j ACCEPT
But it's not working. Let's troubleshoot this systematically.
Based on the rules shown, there are several potential issues:
# 1. Missing interface specification in PREROUTING
-A PREROUTING -i ppp0 -p tcp -m tcp --dport 8001 -j DNAT --to-destination 192.168.1.200:8080
# 2. Missing MASQUERADE for return traffic
-A POSTROUTING -o eth0 -j MASQUERADE
# 3. Need to enable IP forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
Here's the complete set of rules that should work for your scenario:
# Enable IP forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
# Clear existing rules
iptables -F
iptables -t nat -F
# Default policies
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD DROP
# NAT and forwarding rules
iptables -t nat -A PREROUTING -i ppp0 -p tcp --dport 8001 -j DNAT --to-destination 192.168.1.200:8080
iptables -A FORWARD -p tcp -d 192.168.1.200 --dport 8080 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
# Allow established connections
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
After applying these rules, verify with:
# Check NAT rules
iptables -t nat -L -n -v
# Check forwarding
iptables -L FORWARD -n -v
# Test connection from external host
telnet your_public_ip 8001
To make these changes permanent:
# For Debian/Ubuntu
apt-get install iptables-persistent
iptables-save > /etc/iptables/rules.v4
# For CentOS/RHEL
service iptables save
# Enable IP forwarding permanently
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p
If it still doesn't work:
- Check interface names with
ip a
- Verify routing with
ip route
- Test internal connectivity first
- Check firewall logs with
dmesg | grep -i firewall