Side by Side
| Aspect | UFW | firewalld | iptables | nftables |
|---|---|---|---|---|
| What it is | Front end | Front end | Rule language and tool (older) | Rule language and tool (current) |
| Where it is standard | Ubuntu (installed, off by default) | AlmaLinux, Rocky Linux, RHEL, Fedora | Older systems; kept for compatibility | Underneath current Debian, Ubuntu and RHEL |
| How you work | ufw allow 443/tcp | Zones and services | One rule per command, per table | A whole ruleset in one file |
| IPv4 and IPv6 | Both, from one command | Both, from one command | Separate tools (iptables, ip6tables) | One ruleset for both |
| Changes apply | At once | Runtime, or --permanent then reload | At once, lost on reboot unless saved | Atomically when the file is loaded |
| Choose it when | A simple server on Ubuntu or Debian | A Red Hat-family server | Following old instructions | You need sets, maps or full control |
The Kernel Layer: iptables and nftables
The filtering itself happens in the kernel's netfilter framework. iptables was its interface for two decades, with separate commands for IPv4, IPv6 and ARP and rules added one at a time. nftables replaced it with a single tool, a proper rule language, sets of addresses and ports, and atomic updates: a whole ruleset is loaded at once, so there is never a moment with half the rules in place.
On current systems the iptables command is usually a compatibility layer that writes nftables rules. Check which you have:
iptables -V # "nf_tables" = the compatibility layer, "legacy" = old iptables sudo nft list ruleset # every rule actually loaded, whoever wrote it
UFW
UFW (Uncomplicated Firewall) is Ubuntu's front end. It is installed but inactive on a fresh server. Allow SSH before turning it on, or you will lock yourself out:
sudo ufw allow OpenSSH sudo ufw allow 80,443/tcp sudo ufw enable sudo ufw status verbose
It is the easiest choice for a single server, and first steps on a new Linux server uses it. One known catch: ports published by Docker skip UFW's rules entirely, which UFW not working with Docker explains.
firewalld
firewalld is the standard on AlmaLinux, Rocky Linux, RHEL and Fedora. It groups interfaces into zones (such as public) and opens named services in them. Changes made without --permanent last only until the next reload, which is useful for testing:
sudo firewall-cmd --get-active-zones sudo firewall-cmd --permanent --add-service=http --add-service=https sudo firewall-cmd --reload sudo firewall-cmd --list-all
nftables Directly
Writing nftables yourself makes sense when you want one readable file for the whole firewall, or need sets (“these 40 addresses may reach port 5432”) and rate limits. The rules live in /etc/nftables.conf and load at boot with systemctl enable --now nftables. Disable UFW or firewalld first so nothing overwrites them.
Rules That Apply to All of Them
- Use one tool. Two front ends, or a front end plus hand-written rules, end in rules nobody can explain.
- Allow SSH (or Remote Desktop) before enabling anything with a default-deny policy.
- Keep a way in that does not depend on the network. On Virteche Cloud, the browser console on the server's page works even when the firewall blocks everything.
- Test from outside the server: a port that looks closed from the server itself may still be open to the internet.
A firewall in front of the server adds a second layer. The one in the Virteche Cloud dashboard runs on the host, so traffic you block never reaches the server at all, even if a rule inside it is wrong.