Firewall — iptables and ufw
The Linux firewall is built into the kernel. iptables has been the tool to configure it for decades. ufw makes the common cases much simpler. This post covers how it all fits together.
Series: Learning Linux from Scratch
- 1. Learning Linux from Scratch — After a Full IT Apprenticeship
- 2. What is Linux?
- 3. The Filesystem
- 4. Users and Permissions
- 5. Installing and Managing Software
- 6. Text Editors
- 7. Shell Scripting Basics
- 8. Process Management
- 9. Networking Fundamentals
- 10. SSH
- 11. systemd and Services
- 12. Disk Management
- 13. Users and Groups — In Depth
- 14. Cron and Scheduled Tasks
- 15. Firewall — iptables and ufw
- 16. Environment Variables and the Shell
- 17. Log Management
- 18. Kernel Module Management
- 19. The /proc Filesystem — In Depth
- 20. The /sys Filesystem and udev
- 21. Kernel Parameters and sysctl
- 22. Compiling and Installing a Custom Kernel
The Linux firewall is built into the kernel. It is called netfilter, and it filters every packet that enters, leaves, or passes through your machine. iptables is the traditional userspace tool for configuring it. ufw (Uncomplicated Firewall) is a frontend that makes it significantly less painful to work with.
How iptables works
iptables organises rules into tables, and tables contain chains. The most important table is filter, which has three built-in chains:
INPUT— packets destined for the local systemOUTPUT— packets originating from the local systemFORWARD— packets passing through (for routers)
Each chain contains an ordered list of rules. When a packet arrives, iptables checks it against each rule in order. The first matching rule wins. If no rule matches, the chain's default policy applies (usually ACCEPT or DROP).
Viewing current rules
sudo iptables -L -v -n-L— list rules-v— verbose (show packet and byte counts)-n— numeric output (do not resolve hostnames or service names)
Basic iptables rules
Allow incoming SSH:
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT-A INPUT— append to the INPUT chain-p tcp— match TCP protocol--dport 22— match destination port 22-j ACCEPT— jump to ACCEPT (allow the packet)
Allow established connections (important — without this, return traffic gets blocked):
sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPTAllow loopback traffic:
sudo iptables -A INPUT -i lo -j ACCEPTDrop everything else:
sudo iptables -P INPUT DROP-P sets the default policy. This is the last step — set it to DROP only after you have allowed the traffic you actually need.
Saving iptables rules
iptables rules do not persist across reboots by default.
On Debian/Ubuntu:
sudo apt install iptables-persistent
sudo netfilter-persistent saveRules are saved to /etc/iptables/rules.v4 and loaded on boot.
ufw
iptables is powerful but verbose. ufw provides a simpler interface for the most common use cases.
Enabling ufw
sudo ufw enableCheck status:
sudo ufw status verboseBasic ufw rules
Allow SSH:
sudo ufw allow sshOr by port number:
sudo ufw allow 22/tcpAllow HTTP and HTTPS:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcpAllow a port range:
sudo ufw allow 8000:8100/tcpAllow from a specific IP:
sudo ufw allow from 192.168.1.50Allow from a specific IP to a specific port:
sudo ufw allow from 192.168.1.50 to any port 5432Deny a port:
sudo ufw deny 3306Delete a rule:
sudo ufw delete allow 80/tcpufw default policies
sudo ufw default deny incoming
sudo ufw default allow outgoingThis is the standard server setup — deny all incoming traffic by default and only allow what you explicitly open. Set the defaults before enabling ufw.
ufw application profiles
Some packages install ufw profiles that you can use by name:
sudo ufw app list
sudo ufw allow "Nginx Full"
sudo ufw allow "OpenSSH"nftables
nftables is the modern replacement for iptables. It uses a cleaner syntax, performs better, and is now the default on newer distributions.
Check if nftables is active:
sudo nft list rulesetA basic nftables configuration that allows SSH, HTTP, HTTPS and drops everything else:
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
iif lo accept
ct state established,related accept
tcp dport { 22, 80, 443 } accept
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
Save this to /etc/nftables.conf and enable the service:
sudo systemctl enable --now nftablesA practical server setup
The standard hardened server firewall in order:
# Set defaults
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow SSH (do this before enabling or you lock yourself out)
sudo ufw allow ssh
# Allow web traffic if running a web server
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Enable
sudo ufw enable
# Verify
sudo ufw status verboseThe firewall is the boundary between your system and everything else. For any internet-facing server, getting it right is not optional. The ufw workflow above covers most cases. Learn iptables when you need finer control or are working with systems where ufw is not available.
Next up: environment variables and the shell — PATH, .bashrc, and how shell startup actually works.