🐛 Debugging and Troubleshooting
Rules Not Working? Check These 5 Things First
iptables rules not taking effect is the most frustrating problem for beginners. Go through this checklist one by one:
| # | Check Item | Command | Common Cause |
|---|---|---|---|
| 1 | Rule order | iptables -L -v -n --line-numbers | Allow rules are placed after deny rules, never matching |
| 2 | Correct table | iptables -t nat -L -n | NAT rules written to filter table, or vice versa |
| 3 | Default policy | iptables -L -n | head -5 | Default policy is ACCEPT, making all rules pointless |
| 4 | Other program interference | iptables -L -v -n | grep -c "" | Docker/ufw/firewalld automatically inserted rules |
| 5 | Network path | traceroute -T targetIP | Packets never reach this machine (firewall in between) |
Docker and iptables: A Troubled History
Docker automatically modifies iptables rules when it starts (creates DOCKER chains, modifies FORWARD policy, etc.). This is the culprit behind many "mysteriously disappearing iptables rules."
bash
# View rules inserted by Docker
iptables -L DOCKER -v -n
iptables -L DOCKER-USER -v -n
# Add custom rules in the DOCKER-USER chain (Docker won't clear it)
# Note: Must use DOCKER-USER, not INPUT!
iptables -I DOCKER-USER -s 10.0.0.0/8 -j ACCEPT
iptables -I DOCKER-USER -j DROP
# Completely prevent Docker from modifying iptables (use with caution, container networking will be affected)
# Set in /etc/docker/daemon.json:
# { "iptables": false }⚠️ Warning: ⚠️ Hard-earned lesson: Many tutorials teach you to add rules in the INPUT chain to restrict Docker container ports. But Docker port mapping goes through PREROUTING → DOCKER chain, completely bypassing INPUT. Adding rules there is useless! You must operate in the DOCKER-USER chain.
Quick Reference for Common Troubleshooting Commands
bash
# View rule counters (see which rules matched traffic)
iptables -L -v -n
# Rules with non-zero pkts column are working
# Rules with pkts=0 either had no traffic or were intercepted by a rule above them
# View detailed info for a specific chain (with line numbers)
iptables -L INPUT -v -n --line-numbers
# View raw table (before connection tracking)
iptables -t raw -L -v -n
# View mangle table (packet modification)
iptables -t mangle -L -v -n
# Real-time rule matching monitor (watch refreshes every 2 seconds)
watch -n 2 'iptables -L -v -n | head -20'
# Use tcpdump to verify packets (check if packets reach this machine)
tcpdump -i eth0 port 80 -nn -c 10
# Use iptables NFLOG with ulogng2 for analysis
iptables -A INPUT -j NFLOG --nflog-group 1
ulogd2 -c /etc/ulogd.conf # Requires ulogd2 installation