A Linux firewall controls which network traffic is allowed in and out of your server. Without one, every open port is exposed to the internet. This guide covers two approaches: ufw (Uncomplicated Firewall — the easier choice for most use cases) and iptables (the underlying engine — essential for advanced scenarios).
ufw — Uncomplicated Firewall (Ubuntu/Debian)
ufw wraps iptables with a simpler command interface. It is included by default on Ubuntu and is the right choice for standard server setups.
Enabling and Checking Status
sudo ufw status # Show status and rules
sudo ufw status verbose # Detailed view
sudo ufw enable # Enable firewall
sudo ufw disable # Disable firewall (not recommended on production)
Warning: enable ufw only after you have allowed SSH, or you will lock yourself out.
Basic Rules
# Allow SSH before enabling (critical!)
sudo ufw allow ssh # Allow port 22
sudo ufw allow 2222/tcp # Allow custom SSH port
# Allow common services
sudo ufw allow http # Allow port 80
sudo ufw allow https # Allow port 443
sudo ufw allow 3306/tcp # MySQL (be careful — prefer restricting)
# Allow from specific IP only
sudo ufw allow from 192.168.1.100 to any port 22
sudo ufw allow from 192.168.1.0/24 to any port 3306
# Deny a port
sudo ufw deny 23/tcp # Deny Telnet
Deleting Rules
sudo ufw status numbered # Show rules with numbers
sudo ufw delete 3 # Delete rule #3
sudo ufw delete allow http # Delete by rule definition
Default Policies
sudo ufw default deny incoming # Block all incoming by default
sudo ufw default allow outgoing # Allow all outgoing by default
Logging
sudo ufw logging on # Enable logging
sudo tail -f /var/log/ufw.log # Watch firewall log
firewalld — For RHEL/Rocky/Fedora
sudo systemctl status firewalld
sudo firewall-cmd --state
# Allow services
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --permanent --add-port=8080/tcp
# Reload to apply permanent rules
sudo firewall-cmd --reload
# List all rules
sudo firewall-cmd --list-all
iptables — The Low-Level Engine
iptables is the actual Linux kernel firewall. ufw and firewalld are front-ends for it. Understanding iptables basics helps you debug issues and write precise rules.
Viewing Rules
sudo iptables -L -n -v # List rules with stats
sudo iptables -L -n --line-numbers # Show line numbers
sudo iptables -t nat -L -n # NAT table rules
Basic Rule Structure
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT # Allow SSH
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT # Allow HTTP
sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # Allow established
sudo iptables -A INPUT -i lo -j ACCEPT # Allow loopback
sudo iptables -P INPUT DROP # Default deny incoming
Deleting Rules
sudo iptables -D INPUT -p tcp --dport 23 -j ACCEPT # Delete specific rule
sudo iptables -D INPUT 3 # Delete by line number
sudo iptables -F # Flush ALL rules (careful)
Saving iptables Rules
# Ubuntu/Debian
sudo apt install iptables-persistent
sudo netfilter-persistent save
# RHEL/Rocky
sudo service iptables save
cat /etc/sysconfig/iptables
A Minimal Secure iptables Ruleset
#!/bin/bash
# Flush existing rules
iptables -F
iptables -X
# 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/related connections
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allow SSH
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# Allow HTTP and HTTPS
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
# Log and drop everything else
iptables -A INPUT -j LOG --log-prefix "IPTables-Dropped: "
iptables -A INPUT -j DROP
Summary
For most servers, ufw on Ubuntu/Debian and firewalld on RHEL/Rocky provide everything you need with a clean interface. Understanding iptables gives you the power to handle complex scenarios — NAT, port forwarding, traffic shaping. Always allow SSH before enabling any firewall, and test rules carefully before applying them to production.