Firewalls: iptables and nftables
iptables and nftables are two generations of the same kernel packet-filtering framework (netfilter) - most distros put a friendlier frontend like ufw or firewalld in front of whichever one they use.
Both tools configure netfilter, the packet-filtering framework built into the Linux kernel - they're interfaces to the same underlying mechanism, not competing implementations of separate ones.
iptables: the long-standing standard
iptables organizes rules into chains (INPUT, OUTPUT, FORWARD for
the filter table) processed in order, with a default policy for what
happens when nothing matches:
sudo iptables -L -v -n
Chain INPUT (policy DROP)
target prot opt source destination
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:22
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:443
A minimal example allowing SSH and HTTPS, dropping everything else inbound:
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
sudo iptables -P INPUT DROP
That ESTABLISHED,RELATED line matters: without it, reply traffic for
connections you initiated outbound gets dropped too, since each packet
is otherwise evaluated independently of any connection state.
Rules set this way don't survive a reboot on their own - persist them with
a distro-specific mechanism (iptables-persistent on Debian/Ubuntu,
saving to /etc/sysconfig/iptables and enabling the iptables service on
older RHEL-family systems).
nftables: the successor
nftables replaces iptables (and the separate ip6tables, arptables,
ebtables tools it required for IPv6 and non-IP protocols) with one
unified framework and syntax. It's the default backend on current Debian,
Ubuntu, Fedora, and RHEL - iptables commands on these systems are often
translated to nftables rules underneath via a compatibility layer
(iptables-nft), rather than using the original kernel implementation
directly.
sudo nft list ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
tcp dport 22 accept
tcp dport 443 accept
ct state established,related accept
}
}
nftables rules are typically written to a config file
(/etc/nftables.conf) and loaded as a set, rather than built up one
imperative command at a time the way iptables commands usually are -
closer to declaring the desired ruleset than scripting it.
Frontends most distros actually put in front of this
Writing raw rules directly is uncommon day-to-day - most distributions ship a simpler management layer:
-
ufw (Uncomplicated Firewall) - the default on Ubuntu, wraps iptables/nftables with a much simpler syntax:
sudo ufw allow 22/tcp sudo ufw allow ssh sudo ufw enable sudo ufw status verbose -
firewalld - the default on Fedora and RHEL, organizes rules into named zones (
public,home,internal, …) representing trust levels, with a runtime vs. permanent configuration distinction:sudo firewall-cmd --add-service=ssh --permanent sudo firewall-cmd --add-service=https --permanent sudo firewall-cmd --reload sudo firewall-cmd --list-allThe
--permanentflag matters - without it, a change applies only to the current runtime configuration and is lost on the next reload or reboot.
Checking what's actually active
Before assuming a connectivity problem is a firewall rule, confirm which tool is even managing it:
sudo ufw status
sudo firewall-cmd --state
sudo nft list ruleset
See Troubleshooting Connectivity for where firewall checks fit into a broader diagnostic process, and Hardening Basics for firewall configuration as part of baseline server hardening.