Configure Linux system firewall with nftables and security hardening

Intermediate 45 min Apr 03, 2026 36 views
Ubuntu 24.04 Ubuntu 22.04 Debian 12 AlmaLinux 9 Rocky Linux 9 Fedora 41

Learn how to configure nftables firewall with advanced security rules, rate limiting, and fail2ban integration. This tutorial covers migration from iptables, logging configuration, and production-grade security hardening for modern Linux systems.

Prerequisites

  • Root or sudo access
  • Basic understanding of networking concepts
  • SSH access to the server

What this solves

nftables is the modern replacement for iptables in Linux, offering improved performance, better syntax, and advanced filtering capabilities. This tutorial shows you how to configure a production-ready firewall with nftables, including port-based access control, rate limiting, logging, and fail2ban integration for comprehensive security hardening.

Step-by-step configuration

Update system and install nftables

Start by updating your system and installing nftables. Most modern distributions include nftables by default, but we'll ensure it's properly installed and configured.

sudo apt update && sudo apt upgrade -y
sudo apt install -y nftables
sudo dnf update -y
sudo dnf install -y nftables

Stop and disable iptables services

Before configuring nftables, disable any existing iptables services to prevent conflicts. This ensures nftables has full control over packet filtering.

sudo systemctl stop ufw
sudo systemctl disable ufw
sudo systemctl mask iptables
sudo systemctl mask ip6tables
sudo systemctl stop firewalld
sudo systemctl disable firewalld
sudo systemctl mask iptables
sudo systemctl mask ip6tables

Create basic nftables configuration

Create a comprehensive nftables configuration file with separate tables for filtering and NAT. This configuration includes basic security rules, logging, and connection tracking.

#!/usr/sbin/nft -f

Clear existing rules

flush ruleset

Define variables for common ports and networks

define SSH_PORT = 22 define HTTP_PORT = 80 define HTTPS_PORT = 443 define TRUSTED_NETS = { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 }

Main filter table

table inet filter { # Chain for input packets chain input { type filter hook input priority filter; policy drop; # Accept loopback traffic iif "lo" accept # Accept established and related connections ct state established,related accept # Drop invalid connections ct state invalid drop # Accept ICMP (ping) ip protocol icmp icmp type { echo-request, destination-unreachable, time-exceeded } limit rate 5/second accept ip6 nexthdr icmpv6 icmpv6 type { echo-request, destination-unreachable, time-exceeded, nd-neighbor-solicit, nd-neighbor-advert } limit rate 5/second accept # SSH with rate limiting tcp dport $SSH_PORT ct state new limit rate 3/minute burst 3 packets accept # HTTP and HTTPS tcp dport { $HTTP_PORT, $HTTPS_PORT } ct state new accept # Log dropped packets (rate limited) limit rate 10/minute burst 5 packets log prefix "nftables-dropped: " # Default drop (implicit due to policy) } # Chain for forward packets (for routers/gateways) chain forward { type filter hook forward priority filter; policy drop; # Accept established and related connections ct state established,related accept # Log dropped forwards limit rate 5/minute burst 3 packets log prefix "nftables-forward-drop: " } # Chain for output packets chain output { type filter hook output priority filter; policy accept; # Generally allow all outbound traffic # Add restrictions here if needed } }

NAT table for network address translation

table ip nat { chain prerouting { type nat hook prerouting priority dstnat; policy accept; } chain postrouting { type nat hook postrouting priority srcnat; policy accept; # Example: masquerade outbound traffic (uncomment if needed) # oifname "eth0" masquerade } }

Enable and start nftables service

Enable nftables to start automatically on boot and load the configuration. The service will parse and apply the rules from the configuration file.

sudo systemctl enable nftables
sudo systemctl start nftables
sudo systemctl status nftables

Create advanced security rules with rate limiting

Add sophisticated rate limiting and security rules to protect against common attacks. Create a separate configuration file for advanced rules.

#!/usr/sbin/nft -f

Advanced security rules - append to existing configuration

Create sets for dynamic blocking

table inet security { set blocked_ips { type ipv4_addr flags timeout timeout 1h } set rate_limit_ips { type ipv4_addr flags timeout timeout 10m } # Security chain with advanced rules chain security_input { type filter hook input priority -10; policy accept; # Block IPs in blocked set ip saddr @blocked_ips drop # Rate limiting per IP tcp dport { 80, 443 } add @rate_limit_ips { ip saddr limit rate over 50/minute burst 100 packets } drop # Protect against port scanning tcp flags & (fin|syn|rst|ack) == syn ct state new limit rate 10/second burst 20 packets accept # Block TCP flood attacks tcp flags & (fin|syn|rst|ack) == syn limit rate 25/second burst 50 packets accept # Block UDP flood meta l4proto udp limit rate 25/second burst 50 packets accept # Log suspicious activity tcp flags & (fin|syn|rst|ack) == (fin|syn) log prefix "TCP-scan: " drop tcp flags & (fin|syn|rst|ack) == (fin|rst) log prefix "TCP-scan: " drop } }

Configure logging and monitoring

Set up proper logging for nftables events. Configure rsyslog to handle nftables logs separately from other system logs.

# nftables logging configuration
:msg,contains,"nftables" /var/log/nftables.log
& stop

Separate file for dropped packets

:msg,contains,"nftables-dropped" /var/log/nftables-dropped.log & stop

Log rotation will be handled by logrotate

Create logrotate configuration

Configure log rotation for nftables logs to prevent disk space issues. This ensures logs are compressed and rotated regularly.

/var/log/nftables*.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    create 0640 root adm
    postrotate
        /usr/lib/rsyslog/rsyslog-rotate
    endscript
}

Restart logging services

Restart rsyslog to apply the new logging configuration and create the initial log files.

sudo systemctl restart rsyslog
sudo touch /var/log/nftables.log /var/log/nftables-dropped.log
sudo chown root:adm /var/log/nftables*.log
sudo chmod 640 /var/log/nftables*.log

Install and configure fail2ban with nftables

Install fail2ban and configure it to work with nftables for automatic IP blocking based on log analysis.

sudo apt install -y fail2ban
sudo dnf install -y fail2ban

Configure fail2ban for nftables

Create fail2ban configuration that integrates with nftables. This configuration monitors SSH attempts and adds repeat offenders to the blocked IPs set.

[DEFAULT]

Default settings

bantime = 3600 findtime = 600 maxretry = 3 backend = systemd

Use nftables for banning

banaction = nftables-multiport banaction_allports = nftables-allports [sshd] enabled = true port = ssh logpath = %(sshd_log)s maxretry = 3 bantime = 3600 [nginx-http-auth] enabled = false filter = nginx-http-auth logpath = /var/log/nginx/error.log maxretry = 3 bantime = 3600 [nginx-limit-req] enabled = false filter = nginx-limit-req logpath = /var/log/nginx/error.log maxretry = 10 bantime = 600

Create nftables action for fail2ban

Create a custom fail2ban action that adds banned IPs to our nftables blocked set. This integrates fail2ban seamlessly with our nftables configuration.

[Definition]

Fail2ban nftables action for blocked IPs set

actionstart = actionstop = actioncheck = actionban = nft add element inet security blocked_ips { timeout 1h } actionunban = nft delete element inet security blocked_ips { } [Init] name = blocked-ips table = inet security timeout = 3600

Enable and start fail2ban

Enable fail2ban service and verify it's working correctly with nftables integration.

sudo systemctl enable fail2ban
sudo systemctl start fail2ban
sudo systemctl status fail2ban

Create backup and restore scripts

Create scripts to backup and restore your nftables configuration. This is essential for production environments and configuration management.

#!/bin/bash

nftables backup script

BACKUP_DIR="/var/backups/nftables" DATE=$(date +"%Y%m%d-%H%M%S") BACKUP_FILE="$BACKUP_DIR/nftables-$DATE.conf"

Create backup directory

mkdir -p "$BACKUP_DIR"

Export current ruleset

sudo nft list ruleset > "$BACKUP_FILE"

Compress older backups

find "$BACKUP_DIR" -name "*.conf" -mtime +7 -exec gzip {} \;

Remove backups older than 30 days

find "$BACKUP_DIR" -name "*.conf.gz" -mtime +30 -delete echo "Backup created: $BACKUP_FILE"

Create restore script

Create a restoration script that can quickly restore nftables configuration from backup files.

#!/bin/bash

nftables restore script

if [ $# -eq 0 ]; then echo "Usage: $0 " echo "Available backups:" ls -la /var/backups/nftables/ exit 1 fi BACKUP_FILE="$1" if [ ! -f "$BACKUP_FILE" ]; then echo "Backup file not found: $BACKUP_FILE" exit 1 fi echo "Restoring nftables configuration from: $BACKUP_FILE"

Clear current rules and restore from backup

sudo nft flush ruleset sudo nft -f "$BACKUP_FILE" echo "Configuration restored successfully"

Make scripts executable and create cron job

Set proper permissions for the backup scripts and create a daily backup cron job for automated configuration backups.

sudo chmod 755 /usr/local/bin/nftables-backup.sh /usr/local/bin/nftables-restore.sh

Create daily backup cron job

echo "0 2 * root /usr/local/bin/nftables-backup.sh" | sudo tee /etc/cron.d/nftables-backup

Migrate existing iptables rules

If you have existing iptables rules, use the iptables-translate tool to convert them to nftables format. This tool helps migrate complex rulesets.

# Install translation tools
sudo apt install -y iptables-nftables-compat

Translate existing iptables rules

sudo iptables-save > /tmp/iptables-rules.txt sudo iptables-restore-translate -f /tmp/iptables-rules.txt

For ip6tables

sudo ip6tables-save > /tmp/ip6tables-rules.txt sudo ip6tables-restore-translate -f /tmp/ip6tables-rules.txt

Verify your setup

Test your nftables configuration and verify all components are working correctly.

# Check nftables status
sudo systemctl status nftables

List current ruleset

sudo nft list ruleset

Check fail2ban status

sudo fail2ban-client status sudo fail2ban-client status sshd

Test SSH rate limiting (from another machine)

ssh user@example.com (repeat quickly to trigger rate limit)

Check logs

sudo tail -f /var/log/nftables.log sudo tail -f /var/log/fail2ban.log

Verify backup script

sudo /usr/local/bin/nftables-backup.sh

Check blocked IPs set

sudo nft list set inet security blocked_ips

Common issues

SymptomCauseFix
Service won't startSyntax error in configsudo nft -c -f /etc/nftables.conf to check syntax
Can't SSH after setupBlocked by rate limitingWait 10 minutes or add IP to whitelist in config
Fail2ban not blockingWrong backend or actionCheck sudo fail2ban-client status and logs
Logs not appearingRsyslog not restartedsudo systemctl restart rsyslog
Rules not persistentService not enabledsudo systemctl enable nftables
Port still accessibleRule order issueCheck rule priority with nft -a list table inet filter

Next steps

Automated install script

Run this to automate the entire setup

#nftables #firewall #security #iptables #fail2ban

Need help?

Don't want to manage this yourself?

We handle infrastructure for businesses that depend on uptime. From initial setup to ongoing operations.

Talk to an engineer