iptables and nftables Firewall Configuration on Linux
Learn how to configure Linux firewalls with iptables and nftables, including rules, chains, NAT, and migration strategies.
What you'll learn
- ✓How iptables tables, chains, and rules work
- ✓Writing firewall rules for real server scenarios
- ✓nftables syntax and migrating from iptables
Prerequisites
- •Basic Linux command line
- •Basic understanding of TCP/IP and ports
Linux Firewall Fundamentals
Every Linux system has a built-in firewall powered by the kernel’s Netfilter framework. iptables has been the standard interface to Netfilter for over two decades, while nftables is its modern replacement. Both control which network packets are allowed, denied, or modified as they pass through your system.
Understanding these tools is essential for securing any Linux server.
iptables Architecture
iptables organizes rules into tables and chains:
Tables define the type of operation:
- filter — Default table for accepting or dropping packets
- nat — Network address translation (port forwarding, masquerading)
- mangle — Packet header modification
- raw — Exemptions from connection tracking
Chains define when rules are evaluated:
- INPUT — Packets destined for the local system
- OUTPUT — Packets originating from the local system
- FORWARD — Packets being routed through the system
- PREROUTING — Packets before routing decisions (nat/mangle)
- POSTROUTING — Packets after routing decisions (nat/mangle)
Viewing Current Rules
# List all rules in the filter table
sudo iptables -L -n -v
# List rules with line numbers
sudo iptables -L -n --line-numbers
# List NAT rules
sudo iptables -t nat -L -n -v
# Show rules as commands (useful for backup)
sudo iptables-save
The -n flag prevents DNS resolution, making the output much faster.
Writing iptables Rules
The basic syntax is:
sudo iptables -A <CHAIN> <match-criteria> -j <TARGET>
Common targets are ACCEPT, DROP (silently discard), REJECT (discard with error response), and LOG.
Allow SSH Access
# Allow incoming SSH connections
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# Allow SSH only from a specific subnet
sudo iptables -A INPUT -p tcp -s 10.0.0.0/24 --dport 22 -j ACCEPT
Basic Web Server Rules
# Allow HTTP and HTTPS
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
# Allow established and related connections
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Allow loopback
sudo iptables -A INPUT -i lo -j ACCEPT
# Drop everything else
sudo iptables -A INPUT -j DROP
Rate Limiting
# Rate limit SSH to prevent brute force (max 3 connections per minute)
sudo iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW \
-m limit --limit 3/min --limit-burst 3 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j DROP
Logging
# Log dropped packets before dropping them
sudo iptables -A INPUT -j LOG --log-prefix "IPT-DROP: " --log-level 4
sudo iptables -A INPUT -j DROP
A Complete Server Firewall Script
Here is a production-ready iptables script for a web server:
#!/bin/bash
# Flush existing rules
iptables -F
iptables -X
iptables -t nat -F
# Set default policies
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
# Allow loopback
iptables -A INPUT -i lo -j ACCEPT
# Allow established connections
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Allow SSH (rate limited)
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW \
-m limit --limit 5/min --limit-burst 5 -j ACCEPT
# Allow HTTP/HTTPS
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
# Allow ICMP (ping)
iptables -A INPUT -p icmp --icmp-type echo-request \
-m limit --limit 1/s --limit-burst 4 -j ACCEPT
# Log and drop everything else
iptables -A INPUT -j LOG --log-prefix "IPT-DROPPED: " --log-level 4
iptables -A INPUT -j DROP
NAT and Port Forwarding
NAT rules are essential for routers, VPNs, and container hosts:
# Enable IP forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
# Masquerade outbound traffic (basic NAT for a router)
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
# Port forward external port 8080 to internal host 192.168.1.100:80
sudo iptables -t nat -A PREROUTING -p tcp --dport 8080 \
-j DNAT --to-destination 192.168.1.100:80
sudo iptables -A FORWARD -p tcp -d 192.168.1.100 --dport 80 -j ACCEPT
Persisting Rules
iptables rules are lost on reboot. To make them persistent:
# Debian/Ubuntu
sudo apt install iptables-persistent
sudo netfilter-persistent save
# RHEL/CentOS
sudo service iptables save
# Rules saved to /etc/sysconfig/iptables
# Manual backup and restore
sudo iptables-save > /etc/iptables.rules
sudo iptables-restore < /etc/iptables.rules
Migrating to nftables
nftables is the successor to iptables, offering a cleaner syntax, better performance, and unified handling of IPv4, IPv6, ARP, and bridging. Most modern distributions ship with nftables as the default.
nftables Basics
nftables uses tables, chains, and rules, but with a different syntax:
# List all rules
sudo nft list ruleset
# Create a table
sudo nft add table inet my_filter
# Create a chain with a base hook
sudo nft add chain inet my_filter input { type filter hook input priority 0 \; policy drop \; }
# Add rules
sudo nft add rule inet my_filter input iif lo accept
sudo nft add rule inet my_filter input ct state established,related accept
sudo nft add rule inet my_filter input tcp dport 22 accept
sudo nft add rule inet my_filter input tcp dport { 80, 443 } accept
sudo nft add rule inet my_filter input counter drop
nftables Configuration File
The preferred approach is to write a configuration file at /etc/nftables.conf:
#!/usr/sbin/nft -f
flush ruleset
table inet firewall {
chain input {
type filter hook input priority 0; policy drop;
# Allow loopback
iif lo accept
# Allow established connections
ct state established,related accept
# Allow SSH (rate limited)
tcp dport 22 ct state new limit rate 5/minute accept
# Allow web traffic
tcp dport { 80, 443 } accept
# Allow ICMP
ip protocol icmp limit rate 4/second accept
ip6 nexthdr icmpv6 limit rate 4/second accept
# Log and drop
counter log prefix "NFT-DROP: " drop
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
Load and enable it:
sudo nft -f /etc/nftables.conf
sudo systemctl enable nftables
sudo systemctl start nftables
nftables Advantages Over iptables
- Sets for grouping IPs or ports:
define allowed_ips = { 10.0.0.1, 10.0.0.2 } - Maps for verdict lookups:
tcp dport vmap { 22 : accept, 80 : accept, 443 : accept } - Atomic rule replacement — the entire ruleset is applied at once
- Single tool for IPv4 and IPv6 (the
inetfamily) - Better performance with fewer kernel transitions
Translating iptables to nftables
If you have existing iptables rules, you can auto-translate them:
# Translate saved iptables rules to nftables format
iptables-save > /tmp/iptables-rules.txt
iptables-restore-translate -f /tmp/iptables-rules.txt > /etc/nftables.conf
Debugging Firewall Rules
# Watch packets hitting a chain in real time (iptables)
sudo iptables -A INPUT -j LOG --log-prefix "DEBUG: "
sudo journalctl -f | grep "DEBUG:"
# Count hits per rule (iptables)
sudo iptables -L -n -v
# Trace packet flow (nftables)
sudo nft add rule inet my_filter input meta nftrace set 1
sudo nft monitor trace
# Test connectivity
nc -zv hostname 80
curl -v http://hostname
Summary
Linux firewalls built on Netfilter give you complete control over network traffic. iptables remains widely used and understood, with its table/chain/rule structure. nftables is the modern replacement offering cleaner syntax, better performance, and unified IPv4/IPv6 handling. For new deployments, prefer nftables. For existing systems, you can translate your iptables rules automatically. The key principles remain the same: set default-deny policies, allow only what is needed, rate-limit sensitive services, and persist your rules across reboots.
Related articles
- Linux Linux iptables Firewall Basics
Learn iptables tables, chains, and rules. Build a working host firewall, understand NAT, and avoid the most common mistakes that lock you out.
- Linux SSH Tunneling and Port Forwarding Explained
Learn how to use SSH local, remote, and dynamic port forwarding to securely access services across networks.
- Linux Linux Network Namespaces Tutorial
Hands-on guide to Linux network namespaces. Create isolated network stacks, connect them with veth pairs, and understand how containers get networking.
- Linux Linux Networking with ip and ss: The Modern Toolkit
Replace ifconfig and netstat with ip and ss. Learn to inspect interfaces, routes, and sockets on modern Linux with clear examples.