Configure Linux system firewall with nftables and security hardening

Intermediate 45 min Apr 03, 2026 1,554 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

</code><h2><code>Log rotation will be handled by logrotate</code></h2></pre>
</div>

<div class="step">
### Create logrotate configuration
<p>Configure log rotation for nftables logs to prevent disk space issues. This ensures logs are compressed and rotated regularly.</p>
<pre class="terminal"><code>/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 { 

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 

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

इसे खुद मैनेज नहीं करना चाहते?

हम उन businesses के लिए infrastructure संभालते हैं जो uptime पर निर्भर हैं। Fully managed, एक fixed contact के साथ जो आपके setup को जानता है।

आपको एक निश्चित contact मिलता है जो आपके setup को जानता है

Rotterdam 05:58 · एक message में पहुंचें, कोई ticket form नहीं