nftables is the modern replacement for iptables, ip6tables, arptables, and ebtables, and it ships in the RHEL 8 kernel by default. It uses a single unified rule language, supports atomic rule set replacement, and performs better at scale due to its netlink-based architecture. While firewalld can use nftables as its backend, many system administrators prefer to manage nftables rules directly for precise control. This tutorial walks through checking the nftables version, editing the default configuration file, creating tables and chains, adding practical firewall rules, persisting the configuration, and understanding how to safely co-exist with firewalld when needed.
Prerequisites
- RHEL 8 server with root or sudo access
- An active SSH session with a console fallback open before modifying firewall rules
- Basic understanding of network filtering concepts (tables, chains, hooks, priorities)
- firewalld stopped or managed separately — do not run raw nftables rules while firewalld is active unless you understand the interaction
Step 1 — Verify nftables Availability
Check that the nft binary is installed and the kernel module is loaded.
nft --version
lsmod | grep nf_tables
On a default RHEL 8 installation, nft is available without any additional package installation. If it is missing for any reason, install it with sudo dnf install -y nftables.
Step 2 — Stop firewalld to Avoid Conflicts
When writing raw nftables rules, stop firewalld so its auto-generated chains do not overlap with your own.
sudo systemctl disable --now firewalld
sudo systemctl mask firewalld
# Enable the nftables service so it starts on boot
sudo systemctl enable nftables
Masking ensures firewalld cannot be started by other services or administrators accidentally during rule testing.
Step 3 — Create a Table and Base Chains
nftables rules live inside tables. The inet address family covers both IPv4 and IPv6 simultaneously, which is the recommended approach for modern dual-stack servers.
# Create an inet table called filter
sudo nft add table inet filter
# Add an input chain with a drop policy
sudo nft add chain inet filter input '{ type filter hook input priority 0; policy drop; }'
# Add a forward chain with a drop policy
sudo nft add chain inet filter forward '{ type filter hook forward priority 0; policy drop; }'
# Add an output chain with an accept policy
sudo nft add chain inet filter output '{ type filter hook output priority 0; policy accept; }'
The priority 0 value places these chains at the default netfilter priority. Lower numbers run first. The policy drop on the input chain means any packet that does not match an explicit rule is silently discarded.
Step 4 — Add Firewall Rules
Add rules in the correct order. Rules are evaluated top to bottom within a chain, so allow rules must come before any drop actions they should precede.
# Allow loopback traffic
sudo nft add rule inet filter input iif lo accept
# Allow established and related connections
sudo nft add rule inet filter input ct state established,related accept
# Allow SSH (TCP port 22)
sudo nft add rule inet filter input tcp dport 22 accept
# Allow HTTP (port 80) and HTTPS (port 443)
sudo nft add rule inet filter input tcp dport { 80, 443 } accept
# Allow ICMPv4 ping
sudo nft add rule inet filter input ip protocol icmp icmp type echo-request accept
# Allow ICMPv6 (required for IPv6 neighbour discovery)
sudo nft add rule inet filter input ip6 nexthdr icmpv6 accept
Step 5 — List and Verify the Rule Set
Confirm the full rule set looks correct before saving.
sudo nft list ruleset
The output should show your inet filter table with all three chains and their rules. Verify that your SSH session remains active. If you are locked out, reboot the server — nftables rules added with nft add are not persistent until saved.
# List only the input chain
sudo nft list chain inet filter input
Step 6 — Persist the Rule Set via /etc/nftables.conf
Export the current live rule set to the system configuration file, then verify the nftables service will load it on boot.
# Write current ruleset to the default config file
sudo nft list ruleset | sudo tee /etc/nftables.conf
# Test that the config file parses without errors
sudo nft -c -f /etc/nftables.conf
# Apply rules from the file to verify it works
sudo nft -f /etc/nftables.conf
# Start and verify the nftables service
sudo systemctl start nftables
sudo systemctl status nftables
The -c flag performs a dry-run syntax check without actually loading the rules, which is useful for validating configuration file edits before applying them. The nftables systemd service reads /etc/nftables.conf on start.
Conclusion
You have verified nftables availability on RHEL 8, disabled firewalld to take direct control, created an inet filter table with drop-default input and forward chains, added rules for loopback, established connections, SSH, HTTP, HTTPS, and ICMP, and persisted the configuration to /etc/nftables.conf for automatic loading at boot. The unified inet address family means these rules protect both IPv4 and IPv6 traffic from a single rule set.
Next steps: Configure iptables Firewall Rules on RHEL 8, Use SELinux with nftables Logging for Intrusion Detection on RHEL 8, and Audit Your Firewall Configuration with Lynis on RHEL 8.