Chapter 17Lesson 01~88 minutes

Firewalls with nftables, iptables, firewalld, and ufw

Design and operate Linux host firewalls safely by understanding Netfilter hooks, stateful policy, nftables rule structure, compatibility tools, distribution front ends, and rollback-aware remote changes.

Netfilter and nftablesStateful policySafe firewall operations

Learning objectives

By the end of this lesson

  • Explain how packets traverse Linux Netfilter hooks and base chains.
  • Distinguish nftables, iptables compatibility tooling, firewalld, and ufw.
  • Build a stateful least-access host policy with explicit management safeguards.
  • Validate candidate rules before activation and prepare an automatic rollback.
  • Collect evidence for dropped traffic without creating an unbounded logging incident.

1. A Linux firewall is policy attached to packet-processing hooks

Linux packet filtering is implemented in the kernel through Netfilter. User-space tools create rules that are evaluated at hooks such as input, output, forward, prerouting, and postrouting. A host firewall protects traffic addressed to or originated by the host; a router or container node also needs forwarding policy. The rule engine is not a substitute for binding services to the correct interfaces, authenticating clients, patching software, or segmenting networks.

Netfilter packet path
flowchart TD
  N["Packet enters interface"] --> P["Prerouting"]
  P --> D{"Destination local?"}
  D -- yes --> I["Input chain"]
  I --> S["Local process"]
  S --> O["Output chain"]
  D -- no --> F["Forward chain"]
  F --> Q["Postrouting"]
  O --> Q
  Q --> E["Packet leaves interface"]

Rules should express an intended security state: which sources, destinations, protocols, ports, interfaces, and connection states are allowed. Avoid accumulating exceptions without ownership and expiration. A default-deny input policy is useful only after required access paths—including emergency administration—have been identified and tested.

2. Choose one policy owner

nftables is the modern packet-filter framework and command language. It supports tables, typed sets, maps, counters, stateful expressions, atomic ruleset replacement, IPv4/IPv6 families, and reusable objects. iptables remains common in scripts and products; on many current distributions its commands use an nftables compatibility backend. That does not make arbitrary mixing safe. firewalld provides zones, services, policies, runtime/permanent configuration, and commonly uses nftables underneath. ufw provides a simpler policy interface, especially on Ubuntu systems.

Avoid competing managers

Do not independently manage the same host with raw nftables files, firewalld, ufw, orchestration agents, and hand-written iptables commands. Determine which component owns policy, how it persists changes, and how other software—Docker, Kubernetes, VPN clients, or cloud agents—modifies packet filtering.

# Read-only discovery. Run with appropriate privileges where required.
command -v nft iptables firewall-cmd ufw 2>/dev/null || true
systemctl is-active firewalld nftables ufw 2>/dev/null || true

# Inspect the active nftables ruleset and compatibility views.
sudo nft list ruleset
sudo iptables-save
sudo ip6tables-save

# firewalld and ufw state, if installed.
sudo firewall-cmd --state 2>/dev/null || true
sudo firewall-cmd --get-active-zones 2>/dev/null || true
sudo ufw status verbose 2>/dev/null || true

3. Build a minimal stateful nftables policy

An nftables ruleset groups rules into tables and chains. A base chain attaches to a hook and has a priority and policy. The inet family can handle IPv4 and IPv6 together. Stateful filtering usually accepts traffic belonging to established or related connections before evaluating new inbound requests. Loopback traffic must be handled deliberately. Invalid connection-tracking state is commonly dropped.

cat > /tmp/devops-academy-firewall.nft <<'EOF'
flush ruleset

table inet host_filter {
  set admin_ipv4 {
    type ipv4_addr
    elements = { 192.0.2.10 }
  }

  chain input {
    type filter hook input priority filter; policy drop;

    iifname "lo" accept
    ct state invalid drop
    ct state established,related accept

    ip protocol icmp icmp type echo-request limit rate 5/second accept
    ip6 nexthdr ipv6-icmp accept

    ip saddr @admin_ipv4 tcp dport 22 ct state new accept
    tcp dport { 80, 443 } ct state new accept

    limit rate 5/second burst 10 packets counter log prefix "nft-input-drop: "
    counter drop
  }

  chain output {
    type filter hook output priority filter; policy accept;
  }
}
EOF

# Parse and validate without applying the candidate ruleset.
sudo nft --check --file /tmp/devops-academy-firewall.nft

The documentation addresses in 192.0.2.0/24 are examples, not real administration sources. Replace them only after discovering the actual trusted source path. Explicitly consider DHCP, DNS, NTP, monitoring, configuration management, overlay networks, IPv6 neighbor discovery, and the difference between locally terminated and forwarded traffic.

4. Treat remote firewall changes as controlled deployments

Firewall mistakes can remove the connection needed to repair them. Before activation, preserve the current rules, establish a second verified session, schedule an independent rollback, and apply the candidate atomically where possible. The rollback mechanism must not depend on the session being modified.

backup="/root/nft-backup-$(date -u +%Y%m%dT%H%M%SZ).nft"
sudo nft list ruleset | sudo tee "$backup" >/dev/null

# Schedule a rollback in a transient systemd unit after five minutes.
sudo systemd-run \
  --unit=devops-academy-firewall-rollback \
  --on-active=5m \
  /usr/sbin/nft -f "$backup"

# Apply the already checked candidate atomically.
sudo nft -f /tmp/devops-academy-firewall.nft

# Validate from an independent session and inspect counters.
sudo nft list ruleset
ss -lntup

# Cancel rollback only after every required path is verified.
sudo systemctl stop devops-academy-firewall-rollback.timer

On systems managed by firewalld or ufw, use their supported transaction and persistence model rather than loading a parallel raw ruleset. Confirm whether a runtime change survives reboot. Reboot testing belongs in a maintenance window because a syntactically valid persistent rule can still block required traffic.

5. firewalld zones and ufw rules are policy abstractions

firewalld associates interfaces or source networks with zones and exposes named services. Runtime and permanent configurations are distinct. UFW presents ordered allow, deny, reject, route, and application-profile rules. Both are useful when their abstractions match the host role; neither removes the need to inspect resulting behavior.

# firewalld: inspect first, then make explicit runtime changes.
sudo firewall-cmd --get-active-zones
sudo firewall-cmd --zone=public --list-all
sudo firewall-cmd --zone=public --add-service=https
# Persist only after runtime validation:
sudo firewall-cmd --runtime-to-permanent

# UFW: inspect numbered rules and add a source-restricted SSH rule.
sudo ufw status numbered
sudo ufw allow from 192.0.2.10 to any port 22 proto tcp
sudo ufw allow 443/tcp
sudo ufw status verbose
Cloud controls are another layer

Security groups, network ACLs, load balancers, Kubernetes policies, and host firewalls may all filter the same connection. Document each enforcement point. Opening a host port does not guarantee reachability, and a permissive cloud rule does not bypass a host deny.

6. Diagnose drops with counters and bounded logs

Start with counters, rule handles, socket listeners, routes, and packet captures. Logging every dropped packet can consume CPU, storage, and downstream logging capacity during scans or attacks. Rate-limit logs, add a distinctive prefix, and define retention. A reject verdict actively reports failure; a drop is silent. Choose based on protocol behavior and threat model rather than treating silence as automatically more secure.

# Counters and rule handles make policy behavior observable.
sudo nft --handle list ruleset

# Confirm that the service is actually listening on the expected address.
ss -lntup
ip address show
ip route show

# Follow bounded kernel firewall messages for a short interval.
timeout 30s journalctl -k -f --grep='nft-input-drop'

# Capture only the management flow in a disposable troubleshooting window.
sudo timeout 30s tcpdump -ni any 'host 192.0.2.10 and tcp port 22' 

7. Hands-on lab: review and compile a host policy

Use a disposable VM console, not an irreplaceable remote server. First collect the current owner and ruleset. Create a candidate file, run nft --check, and review every allowed flow. Applying it is optional and requires a console or tested rollback.

lab="$HOME/devops-academy/linux/chapter17/lesson01"
mkdir -p "$lab"

{
  date -u --iso-8601=seconds
  uname -a
  systemctl is-active firewalld nftables ufw 2>/dev/null || true
  command -v nft iptables firewall-cmd ufw 2>/dev/null || true
} > "$lab/firewall-owner.txt"

sudo nft list ruleset > "$lab/active-ruleset.nft" 2> "$lab/nft-errors.txt" || true
sudo nft --check --file /tmp/devops-academy-firewall.nft \
  > "$lab/candidate-check.txt" 2>&1

sha256sum "$lab"/* > "$lab/SHA256SUMS"
printf 'Review evidence in %s\n' "$lab"

Verification checklist

8. Common firewall mistakes

Enabling default deny before preserving management access

Build and test the allow path first, keep a second session, and schedule rollback.

Mixing policy managers

Rules may be reordered, overwritten, or interpreted through compatibility layers. Establish one owner.

Ignoring IPv6

Disabling or forgetting IPv6 is not equivalent to filtering it correctly. Inspect actual addressing and service bindings.

Logging every drop

Unbounded logging turns background scans into resource exhaustion. Prefer counters and rate-limited diagnostic logs.

9. Knowledge check

Why is accepting ct state established,related near the beginning of an input chain useful?

What is the operational danger of managing a host simultaneously with firewalld and unrelated raw nft commands?

What must exist before changing a remote host to a default-drop policy?

10. Summary

  • Netfilter hooks provide the kernel enforcement points; nftables is the modern rule framework.
  • firewalld and ufw are policy managers, not separate security layers from the underlying packet filter.
  • Use stateful least-access rules and identify one policy owner.
  • Compile-check, back up, schedule rollback, apply atomically, and verify from outside.
  • Use counters and bounded logging to investigate drops without creating a logging denial of service.

11. Further reading

Next lesson

SELinux and AppArmor Concepts

Add mandatory access control to ordinary Unix permissions by understanding labels, profiles, enforcement modes, denials, and safe policy refinement.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.