Security

iptables basics: list, allow, drop and save rules

Learn how iptables chains and rule order work, then build a small ruleset that allows SSH and web traffic, drops everything else and can be edited by line number.

IntermediateLinux server6 min read

iptables is the classic command-line tool for the Linux kernel firewall. Even if you later use UFW or firewalld, knowing how iptables reads its rules helps you understand every other Linux firewall. This guide shows you how to list rules, allow the traffic you need, drop the rest and remove rules you no longer want.

Before you start

  • A Linux VPS running Ubuntu 22.04/24.04, Debian 12, or AlmaLinux/Rocky Linux 8 or 9.
  • Root access or a user with sudo.
  • Only one firewall manager in charge. If UFW or firewalld is active, use that tool instead, or disable it first. Two managers writing rules at once causes confusing results.
  • Your SSH port number. It is 22 unless you changed it.

Warning: A default DROP policy without an SSH allow rule cuts you off the moment you apply it. Always add the SSH rule first. If you do get locked out, open the browser console from your VPS provider's control panel. It works without SSH.

How chains and rule order work

iptables groups rules into tables. The one you use most is the filter table, which has three built-in chains:

  • INPUT: packets addressed to the server itself, such as an SSH login.
  • OUTPUT: packets the server sends out.
  • FORWARD: packets passing through the server to another host, used for routers and VPN gateways.

Each chain is a list read from top to bottom. The first rule that matches a packet decides what happens to it, usually ACCEPT, DROP or REJECT. If no rule matches, the chain's policy applies. That is why order matters: a DROP rule placed above an ACCEPT rule wins.

On current distributions the iptables command usually talks to the nftables backend (iptables-nft). The commands in this guide are the same either way. Check which one you have:

Bash
sudo iptables --version

The output ends in (nf_tables) or (legacy).

List the current rules

Show the filter table with line numbers and numeric addresses:

Bash
sudo iptables -L -n -v --line-numbers
  • -L lists the chains.
  • -n skips DNS lookups, which makes the output fast.
  • -v adds packet and byte counters and interface names.
  • --line-numbers shows the position of each rule, which you need for deletes.

You can also print the rules in the same format you would type them:

Bash
sudo iptables -S

Build a basic ruleset

Add the rules in this order. Each -A appends to the end of the INPUT chain.

  1. Allow loopback traffic, which many local services rely on:
Bash
   sudo iptables -A INPUT -i lo -j ACCEPT
  1. Allow replies to connections the server already has open:
Bash
   sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
  1. Allow SSH. Change 22 if you use a custom port:
Bash
   sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
  1. Allow web traffic if the server hosts websites:
Bash
   sudo iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT
  1. Allow ping, which helps with troubleshooting:
Bash
   sudo iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
  1. Drop invalid packets before they reach other rules (optional but tidy):
Bash
   sudo iptables -I INPUT 2 -m conntrack --ctstate INVALID -j DROP

Only now, with SSH allowed, set the default policy for incoming traffic to DROP:

Bash
sudo iptables -P INPUT DROP

Leave OUTPUT on ACCEPT unless you have a reason to filter outgoing traffic. Leave FORWARD on DROP unless the server routes traffic for others.

Note: These rules cover IPv4 only. If your server has IPv6, repeat the same rules with ip6tables, using --icmpv6-type echo-request with -p ipv6-icmp for ping. IPv6 also needs ICMPv6 neighbour discovery, so the simplest safe choice is sudo ip6tables -A INPUT -p ipv6-icmp -j ACCEPT.

Allow a port only from one IP

Use -s to limit a rule to a source address or range. This allows MySQL only from one application server:

Bash
sudo iptables -A INPUT -p tcp -s 198.51.100.20 --dport 3306 -j ACCEPT

Delete and insert rules

List the chain with line numbers, then delete by position:

Bash
sudo iptables -L INPUT -n --line-numbers
sudo iptables -D INPUT 5

Line numbers shift after every delete, so list again before deleting another rule.

You can also delete by repeating the exact rule with -D instead of -A:

Bash
sudo iptables -D INPUT -p tcp --dport 3306 -s 198.51.100.20 -j ACCEPT

To place a rule above others, insert it at a position with -I. This blocks one address before the allow rules see it:

Bash
sudo iptables -I INPUT 1 -s 203.0.113.10 -j DROP

Warning: sudo iptables -F flushes every rule in the chain but keeps the DROP policy. On a live server that blocks SSH instantly. Set sudo iptables -P INPUT ACCEPT before you flush.

Save the rules

Rules you add with the iptables command live in memory and vanish at reboot. To export the current set:

Bash
sudo iptables-save > ~/iptables-backup.rules

To load them back:

Bash
sudo iptables-restore < ~/iptables-backup.rules

To load rules automatically at boot, follow Make iptables rules survive a reboot.

Check it works

  1. Keep your current SSH session open and start a second SSH session from your computer. If it connects, the SSH rule works.
  2. Check the counters grow on the rules you expect:
Bash
   sudo iptables -L INPUT -n -v
  1. From another machine, test a port that should be closed. It should time out:
Bash
   nc -vz -w 5 203.0.113.10 3306

Troubleshooting

  • SSH stopped working after setting the policy: the SSH rule is missing or uses the wrong port. Log in through the browser console, run sudo iptables -P INPUT ACCEPT, then fix the rule.
  • A website is unreachable but port 80 is allowed: a DROP or REJECT rule sits above the allow rule. List with --line-numbers and move or delete it.
  • Rules disappear after a reboot: they were never saved to a file the system loads at boot. Install the persistence package for your distro.
  • Rules look different after you run UFW or firewalld: those tools manage iptables or nftables themselves and overwrite manual changes. Pick one tool.
  • Outgoing updates fail: you set OUTPUT to DROP. Set it back with sudo iptables -P OUTPUT ACCEPT.

Next steps

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.