I keep seeing people overcomplicate their firewall setup with fancy wrappers and GUI tools. iptables is not that hard, and understanding it directly saves you when those wrappers break ( because they always do at the worst time ).

Here's how I set up iptables on every new server.

The Three Default Chains

iptables has three built-in chains: INPUT, OUTPUT, and FORWARD. INPUT handles traffic coming into the server, OUTPUT handles traffic going out, and FORWARD handles traffic being routed through the server ( which you only care about if it's a gateway ).

Rules are processed top to bottom. First match wins. That's the whole model.

Step 1: Set Default Policies

Before adding any rules, lock everything down. Accept all outbound, drop all inbound and forwarded.

iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

If you're doing this over SSH, congratulations you just locked yourself out. Add the SSH rule first. I'll get to that.

Step 2: Allow Established Connections

This one rule covers 90% of return traffic. Without it, your server can send requests out but can't receive the responses.

iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

Step 3: Allow Loopback

Local services talk on loopback. Break this and things get weird fast.

iptables -A INPUT -i lo -j ACCEPT

Step 4: Open the Ports You Need

SSH, HTTP, HTTPS. That's what most web servers need.

iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

If you changed your SSH port ( you should ), swap 22 for whatever you picked.

Step 5: Save the Rules

iptables rules vanish on reboot. On Debian/Ubuntu:

apt install iptables-persistent
netfilter-persistent save

On RHEL/CentOS:

iptables-save > /etc/sysconfig/iptables

Useful One-Liners

List all rules with line numbers ( so you can delete by number ):

iptables -L -n -v --line-numbers

Delete rule number 3 from INPUT:

iptables -D INPUT 3

Block a specific IP:

iptables -A INPUT -s 192.168.1.100 -j DROP

Rate-limit SSH ( max 3 connections per minute from any IP ):

iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --set
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --update --seconds 60 --hitcount 4 -j DROP

Conclusion

That's it. Five rules and your server is locked down. No ufw, no firewalld, no wrappers. Just iptables. If you need more complex stuff ( NAT, port forwarding, custom chains ), the same pattern applies: add the rule, test it, save it.

One gotcha: if you're on a VPS provider that offers a cloud firewall ( Hetzner, DigitalOcean, etc. ), use both. Defense in depth. The cloud firewall drops traffic before it even reaches your kernel.