Changzao Heka Fei avatar

Linux Networking Mastery Series Part 5: Firewalls and Packet Filtering

x9ed1732b

Published: 15 Feb 2026 › Updated: 15 Feb 2026Linux Networking Mastery Series Part 5: Firewalls and Packet Filtering

Linux Networking Mastery Series Part 5: Firewalls and Packet Filtering

Welcome back to Linux Networking Mastery!
In previous parts we built a strong foundation:

  • Part 1 – network stack basics and inspection tools
  • Part 2 – interface and IP configuration (temporary + persistent via Netplan, nmcli, systemd-networkd)
  • Part 3 – routing tables, static/policy routing, namespaces, simple router setup
  • Part 4 – name resolution, systemd-resolved, per-link/global DNS, troubleshooting

Now we add a critical security layer: firewalls.

We'll focus on the modern nftables framework (the successor to iptables), look at higher-level front-ends (firewalld on RHEL/Fedora family and ufw on Ubuntu/Debian), write practical rules for common services, and understand stateful connection tracking.

By the end you'll be able to secure a server, allow only necessary traffic, and understand the transition away from legacy iptables.

From iptables to nftables – Why the Change?

iptables (and ip6tables, arptables, ebtables) served Linux for ~20 years but had serious limitations:

  • Multiple separate tables/chains per protocol/family
  • Difficult rule ordering and complex matching
  • Performance issues with very large rulesets
  • No atomic updates (rules applied one-by-one)

nftables (kernel 3.13+, userspace since ~2014) replaces all of them with:

  • Single framework, unified syntax
  • Tables → chains → rules
  • Sets, maps, verdicts, concatenations, incremental updates
  • Better performance and atomic rule-set replacement
  • Native IPv4 + IPv6 + bridge + netdev support

Most distributions switched as default in 2019–2022:

  • Fedora → nftables default since Fedora 32 (2020)
  • Ubuntu → nftables backend default since 22.04 (2022), though ufw still uses iptables-nft compatibility layer by default
  • Debian → nftables default since Debian 11 (bullseye, 2021) in many contexts

iptables-nft / ip6tables-nft provide a compatibility layer so old iptables commands still work (they translate to nft).

Working Directly with nftables

Basic Structure

table inet myfilter {           # inet = IPv4 + IPv6
    chain input {
        type filter hook input priority 0; policy drop;
        # rules here
    }

    chain forward {
        type filter hook forward priority 0; policy drop;
    }

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

Common hooks:

  • input → packets to local processes
  • forward → packets being routed through the machine
  • output → packets originating from local processes
  • prerouting / postrouting → used in nat table

Quick Practical Example – Minimal Secure Server

Allow established/related, loopback, SSH, HTTP/HTTPS, drop everything else:

#!/usr/bin/env bash
# Reset to clean state
sudo nft flush ruleset

sudo nft -f - <<EOF
table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;

        ct state established,related accept comment "Allow return traffic"
        ct state invalid drop

        iifname "lo" accept comment "Loopback"

        tcp dport 22 ct state new accept comment "SSH"
        tcp dport { 80, 443 } ct state new accept comment "Web"

        # Optional: allow ping (careful in production)
        icmp type echo-request limit rate 5/second accept

        # Log dropped packets (optional, noisy)
        # log prefix "DROPPED: " drop
    }

    chain forward {
        type filter hook forward priority 0; policy drop;
        # If this is not a router → keep drop
    }

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

Apply: sudo chmod +x firewall.sh && sudo ./firewall.sh

List rules:

sudo nft list ruleset

Persistent nftables Rules

  • Debian/Ubuntu: save with sudo nft list ruleset > /etc/nftables.conf
    Enable: sudo systemctl enable nftables

  • Fedora/RHEL: /etc/sysconfig/nftables.conf or use firewalld (recommended)

Higher-Level Front-Ends

firewalld (default on Fedora, RHEL, CentOS Stream, Rocky, AlmaLinux)

Zone-based firewall – very convenient for servers with changing roles.

Common zones: public, internal, trusted, drop, block, home, work, dmz, external

Quick examples:

# See active zone
sudo firewall-cmd --get-active-zones

# Allow SSH on public interface permanently
sudo firewall-cmd --permanent --zone=public --add-service=ssh
sudo firewall-cmd --reload

# Allow web server
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https

# Rich rule example: allow SSH only from specific IP
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.42" service name="ssh" accept'

# Port forward 8080 → internal 80
sudo firewall-cmd --permanent --add-forward-port=port=8080:proto=tcp:toport=80:toaddr=192.168.100.50

# Masquerade (NAT) for LAN clients
sudo firewall-cmd --permanent --zone=external --add-masquerade

List everything: sudo firewall-cmd --list-all-zones

ufw (Uncomplicated Firewall) – Ubuntu/Debian favorite

Very simple interface over iptables-nft (or pure nftables in newer versions).

sudo ufw default deny incoming
sudo ufw default allow outgoing

sudo ufw allow ssh               # or 22/tcp
sudo ufw allow http
sudo ufw allow https
sudo ufw allow from 203.0.113.0/24 to any port 3306 proto tcp comment 'MySQL from office'

# Rate limiting
sudo ufw limit ssh

# See status with numbers
sudo ufw status numbered

# Delete rule by number
sudo ufw delete 3

# Enable (careful – make sure SSH is allowed first!)
sudo ufw enable

Connection Tracking and Stateful Filtering

Both nftables and firewalld/ufw use the conntrack (connection tracking) module.

Key states:

  • NEW
  • ESTABLISHED
  • RELATED
  • INVALID

Rule of thumb for servers:

  • Allow ESTABLISHED,RELATED early
  • Allow NEW only for services you want to expose
  • Drop INVALID

Hands-On Exercises

  1. nftables minimal firewall

    • Flush current ruleset
    • Apply the example script above (adjust ports)
    • Test: can you still SSH? Can external hosts reach a web server? Try curl from another machine.
  2. firewalld zone switch (if on Fedora/RHEL family)

    • Move interface to drop zone → test connectivity
    • Move back to public, add ssh/http services
  3. ufw rate-limit (Ubuntu/Debian)

    • Enable ufw with SSH allowed
    • Add rate limit on SSH
    • Try many rapid SSH attempts from another host

Safety warning: Always allow SSH (or have console/rescue access) before enabling strict policies!

What's Next?

In Part 6 we will configure and harden common network services: SSH server (keys, no password, fail2ban basics), lightweight web servers (Nginx/Apache), file sharing (NFS and Samba), and a simple DHCP server.

Leave Linux Networking Mastery Series Part 5: Firewalls and Packet Filtering to:

Written by

Wire: u9ed1732b

Read more #computernetworks posts


Best Posts From Changzao Heka Fei

We have not curated any of x9ed1732b's posts yet. But you can encourage our curation team to review posts by visiting them regularly and by referring other readers. Because we give priority to frequently read content.

More Posts From Changzao Heka Fei