A properly configured firewall is your Linux server’s first line of defense against unauthorized access and malicious attacks. This comprehensive guide will walk you through installing and configuring the three most popular Linux firewalls: UFW, firewalld, and iptables.

Understanding Linux Firewalls

Linux firewalls work by filtering network traffic based on predefined rules. They control incoming and outgoing connections, allowing legitimate traffic while blocking potentially harmful requests. There are three main firewall solutions for Linux:

  • UFW (Uncomplicated Firewall) – Simple, user-friendly, perfect for Ubuntu/Debian systems
  • firewalld – Dynamic firewall with zones, ideal for RHEL/CentOS/Fedora systems
  • iptables – Powerful, low-level firewall for advanced users

Prerequisites

Before you begin, ensure you have:

  • Root or sudo access to your Linux server
  • SSH access to your server (or physical/console access)
  • Basic knowledge of which services you need to allow
  • List of ports your applications use
⚠️ Critical Warning: Incorrect firewall configuration can lock you out of your server, especially if you’re connected via SSH. Always keep a backup connection open and test rules before disconnecting.

Part 1: UFW (Uncomplicated Firewall)

UFW is the easiest firewall to configure and is the default on Ubuntu and Debian-based systems.

Installing UFW

On Ubuntu/Debian:

sudo apt update
sudo apt install ufw

Verify installation:

sudo ufw version

Basic UFW Configuration

Step 1: Check UFW Status

sudo ufw status verbose

Step 2: Set Default Policies

Block all incoming traffic and allow all outgoing traffic by default:

sudo ufw default deny incoming
sudo ufw default allow outgoing
💡 Important: Before enabling UFW, make sure to allow SSH access or you’ll be locked out!

Step 3: Allow SSH Access

sudo ufw allow ssh

Or specify the port number if you use a custom SSH port:

sudo ufw allow 2222/tcp

Step 4: Enable UFW

sudo ufw enable

Confirm when prompted. UFW will now start on boot automatically.

Common UFW Rules

Allow HTTP and HTTPS (Web Server):

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

Or use service names:

sudo ufw allow http
sudo ufw allow https

Allow MySQL/MariaDB:

sudo ufw allow 3306/tcp

Allow PostgreSQL:

sudo ufw allow 5432/tcp

Allow FTP:

sudo ufw allow 21/tcp

Allow DNS:

sudo ufw allow 53

Allow Port Range:

sudo ufw allow 6000:6007/tcp

Allow from Specific IP Address:

sudo ufw allow from 192.168.1.100

Allow from IP to Specific Port:

sudo ufw allow from 192.168.1.100 to any port 22

Allow Subnet:

sudo ufw allow from 192.168.1.0/24

Managing UFW Rules

View All Rules with Numbers:

sudo ufw status numbered

Delete a Rule by Number:

sudo ufw delete 3

Delete a Rule by Specification:

sudo ufw delete allow 80/tcp

Deny a Connection:

sudo ufw deny from 203.0.113.100

Reset UFW to Default:

sudo ufw reset

Advanced UFW Configuration

Enable Logging:

sudo ufw logging on

Set logging level (low, medium, high, full):

sudo ufw logging medium

View Logs:

sudo tail -f /var/log/ufw.log

Allow Application Profiles:

View available application profiles:

sudo ufw app list

Allow an application:

sudo ufw allow 'Nginx Full'
sudo ufw allow 'Apache Full'
sudo ufw allow 'OpenSSH'

Part 2: firewalld

firewalld is a dynamic firewall manager used primarily on RHEL, CentOS, Fedora, and Rocky Linux systems. It uses zones to define trust levels for network connections.

Installing firewalld

On RHEL/CentOS/Fedora/Rocky Linux:

sudo dnf install firewalld

Or on older systems:

sudo yum install firewalld

Start and enable firewalld:

sudo systemctl start firewalld
sudo systemctl enable firewalld

Verify status:

sudo systemctl status firewalld
sudo firewall-cmd --state

Understanding firewalld Zones

firewalld uses zones to manage trust levels. Common zones include:

  • drop – All incoming connections dropped without reply
  • block – All incoming connections rejected with icmp-host-prohibited message
  • public – For use in public areas, only selected incoming connections accepted
  • external – For external networks with masquerading enabled
  • dmz – For computers in DMZ with limited access
  • work – For work networks, more services trusted
  • home – For home networks, more services trusted
  • internal – For internal networks
  • trusted – All network connections accepted

Basic firewalld Configuration

Check Default Zone:

sudo firewall-cmd --get-default-zone

Set Default Zone:

sudo firewall-cmd --set-default-zone=public

List Active Zones:

sudo firewall-cmd --get-active-zones

View All Rules in a Zone:

sudo firewall-cmd --zone=public --list-all

Managing Services in firewalld

List Available Services:

sudo firewall-cmd --get-services

Allow SSH:

sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload
💡 Note: The --permanent flag makes rules persistent across reboots. Always run --reload after adding permanent rules to apply them immediately.

Allow HTTP and HTTPS:

sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

Remove a Service:

sudo firewall-cmd --permanent --remove-service=http
sudo firewall-cmd --reload

Managing Ports in firewalld

Open a Port:

sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --reload

Open Multiple Ports:

sudo firewall-cmd --permanent --add-port=3000-3005/tcp
sudo firewall-cmd --reload

List Open Ports:

sudo firewall-cmd --list-ports

Remove a Port:

sudo firewall-cmd --permanent --remove-port=8080/tcp
sudo firewall-cmd --reload

Advanced firewalld Configuration

Allow from Specific IP:

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.100" accept'
sudo firewall-cmd --reload

Allow IP to Specific Port:

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.100" port port="22" protocol="tcp" accept'
sudo firewall-cmd --reload

Block an IP Address:

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.100" reject'
sudo firewall-cmd --reload

View Rich Rules:

sudo firewall-cmd --list-rich-rules

Enable Logging:

sudo firewall-cmd --set-log-denied=all
sudo firewall-cmd --reload

Managing firewalld Zones

Add Interface to Zone:

sudo firewall-cmd --permanent --zone=public --add-interface=eth0
sudo firewall-cmd --reload

Change Zone for Interface:

sudo firewall-cmd --permanent --zone=home --change-interface=eth0
sudo firewall-cmd --reload

Part 3: iptables

iptables is the most powerful and flexible firewall for Linux, but also the most complex. It works at a lower level than UFW or firewalld.

Installing iptables

iptables is usually pre-installed on most Linux distributions. If not:

On Ubuntu/Debian:

sudo apt install iptables iptables-persistent

On RHEL/CentOS/Fedora:

sudo dnf install iptables-services
⚠️ Important: If using firewalld or UFW, disable them before using iptables to avoid conflicts.

Disable firewalld:

sudo systemctl stop firewalld
sudo systemctl disable firewalld

Disable UFW:

sudo ufw disable

Understanding iptables Chains

iptables uses three main chains:

  • INPUT – Controls incoming connections
  • OUTPUT – Controls outgoing connections
  • FORWARD – Controls routed/forwarded connections

Basic iptables Commands

View Current Rules:

sudo iptables -L -v -n

View Rules with Line Numbers:

sudo iptables -L --line-numbers

Flush All Rules (Clear Everything):

sudo iptables -F

Setting Default Policies

Set default policies to drop all traffic:

sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT

Allow Loopback Traffic

Always allow localhost connections:

sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A OUTPUT -o lo -j ACCEPT

Allow Established Connections

Allow established and related incoming connections:

sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

Common iptables Rules

Allow SSH:

sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT

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 from Specific IP:

sudo iptables -A INPUT -s 192.168.1.100 -j ACCEPT

Allow from Subnet:

sudo iptables -A INPUT -s 192.168.1.0/24 -j ACCEPT

Block an IP Address:

sudo iptables -A INPUT -s 203.0.113.100 -j DROP

Allow Port Range:

sudo iptables -A INPUT -p tcp --dport 6000:6007 -j ACCEPT

Allow Ping (ICMP):

sudo iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT

Deleting iptables Rules

Delete by Line Number:

sudo iptables -D INPUT 3

Delete by Specification:

sudo iptables -D INPUT -p tcp --dport 80 -j ACCEPT

Saving iptables Rules

Rules are lost on reboot unless saved.

On Ubuntu/Debian (with iptables-persistent):

sudo netfilter-persistent save

Or manually:

sudo iptables-save | sudo tee /etc/iptables/rules.v4

On RHEL/CentOS:

sudo service iptables save

Or:

sudo iptables-save | sudo tee /etc/sysconfig/iptables

Restoring iptables Rules

On Ubuntu/Debian:

sudo iptables-restore < /etc/iptables/rules.v4

On RHEL/CentOS:

sudo iptables-restore < /etc/sysconfig/iptables

Complete iptables Configuration Example

Here's a complete basic firewall setup:

#!/bin/bash

# Flush existing rules
sudo iptables -F
sudo iptables -X

# Set default policies
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT

# Allow loopback
sudo iptables -A INPUT -i lo -j ACCEPT

# Allow established connections
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# Allow SSH
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# 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 ping
sudo iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT

# Save rules
sudo netfilter-persistent save

Firewall Security Best Practices

1. Principle of Least Privilege

Only open ports that are absolutely necessary. If a service isn't being used, don't allow its port through the firewall.

2. Use Specific Rules

Instead of allowing all traffic from an IP, allow specific ports:

# Better
sudo ufw allow from 192.168.1.100 to any port 22

# Avoid
sudo ufw allow from 192.168.1.100

3. Implement Rate Limiting

UFW Rate Limiting:

sudo ufw limit ssh

iptables Rate Limiting:

sudo iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set
sudo iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 -j DROP

4. Regular Audits

Regularly review your firewall rules and remove unnecessary ones:

sudo ufw status numbered
sudo firewall-cmd --list-all
sudo iptables -L -v -n

5. Enable Logging

Enable firewall logging to monitor suspicious activity and troubleshoot issues.

6. Keep Firewall Updated

Regularly update your firewall software:

sudo apt update && sudo apt upgrade  # Debian/Ubuntu
sudo dnf update  # RHEL/Fedora

7. Test Before Deploying

Always test firewall rules in a safe environment before applying to production servers.

Common Firewall Scenarios

Web Server (Apache/Nginx)

UFW:

sudo ufw allow 'Nginx Full'
sudo ufw allow ssh
sudo ufw enable

firewalld:

sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload

Database Server (MySQL/PostgreSQL)

Only allow from application server IP:

UFW:

sudo ufw allow from 192.168.1.50 to any port 3306
sudo ufw allow ssh
sudo ufw enable

firewalld:

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.50" port port="3306" protocol="tcp" accept'
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload

Mail Server

UFW:

sudo ufw allow 25/tcp   # SMTP
sudo ufw allow 587/tcp  # Submission
sudo ufw allow 993/tcp  # IMAPS
sudo ufw allow 995/tcp  # POP3S
sudo ufw allow ssh
sudo ufw enable

Docker Host

Docker manipulates iptables directly. If using UFW:

# Edit /etc/ufw/after.rules and add Docker rules
# Or edit /etc/default/ufw
DEFAULT_FORWARD_POLICY="ACCEPT"

Troubleshooting Firewall Issues

Issue: Locked Out After Enabling Firewall

Solution: If you have console access (physical or cloud console), log in and disable the firewall:

sudo ufw disable
sudo systemctl stop firewalld

Then reconfigure with proper SSH access rules.

Issue: Service Not Accessible After Opening Port

Check if service is listening:

sudo netstat -tulpn | grep :80
sudo ss -tulpn | grep :80

Check if firewall rule is active:

sudo ufw status | grep 80
sudo firewall-cmd --list-ports
sudo iptables -L -n | grep 80

Check service logs:

sudo journalctl -u nginx -n 50
sudo tail -f /var/log/apache2/error.log

Issue: Rules Not Persisting After Reboot

UFW: UFW should persist automatically. Check if enabled:

sudo ufw status

firewalld: Ensure you used --permanent flag:

sudo firewall-cmd --permanent --list-all

iptables: Ensure rules are saved:

sudo netfilter-persistent save  # Debian/Ubuntu
sudo service iptables save      # RHEL/CentOS

Testing Your Firewall

Test Open Ports

From another machine, test if ports are open:

telnet your_server_ip 80
nc -zv your_server_ip 443

Or use nmap:

nmap -p 22,80,443 your_server_ip

Test from the Server

curl -I http://localhost
curl -I https://localhost

Online Port Scanners

Use online tools to scan your public IP:

  • https://www.yougetsignal.com/tools/open-ports/
  • https://pentest-tools.com/network-vulnerability-scanning/tcp-port-scanner-online-nmap

Firewall Comparison Chart

Feature UFW firewalld iptables
Ease of Use ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐
Flexibility ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
Default On Ubuntu/Debian RHEL/CentOS/Fedora None (manual)
Dynamic Rules No Yes No
Zone Support No Yes No
Best For Beginners, Simple setups Enterprise, Complex networks Advanced users, Custom configs

Quick Reference Commands

UFW Quick Reference

# Status and management
sudo ufw status verbose
sudo ufw enable
sudo ufw disable
sudo ufw reload

# Allow/deny rules
sudo ufw allow 80/tcp
sudo ufw deny 8080/tcp
sudo ufw allow from 192.168.1.100
sudo ufw delete allow 80/tcp

# Application profiles
sudo ufw app list
sudo ufw allow 'Nginx Full'

# Logging
sudo ufw logging on

firewalld Quick Reference

# Status and management
sudo systemctl status firewalld
sudo firewall-cmd --state
sudo firewall-cmd --reload

# Services
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --remove-service=http
sudo firewall-cmd --list-services

# Ports
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --permanent --remove-port=8080/tcp
sudo firewall-cmd --list-ports

# Zones
sudo firewall-cmd --get-default-zone
sudo firewall-cmd --set-default-zone=public
sudo firewall-cmd --zone=public --list-all

# Rich rules
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.100" accept'
sudo firewall-cmd --list-rich-rules

iptables Quick Reference

# View rules
sudo iptables -L -v -n
sudo iptables -L --line-numbers

# Add rules
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -s 192.168.1.100 -j ACCEPT

# Delete rules
sudo iptables -D INPUT 3
sudo iptables -F  # Flush all rules

# Default policies
sudo iptables -P INPUT DROP
sudo iptables -P OUTPUT ACCEPT

# Save rules
sudo netfilter-persistent save  # Debian/Ubuntu
sudo service iptables save      # RHEL/CentOS

Conclusion

Configuring a firewall is essential for securing your Linux server. Whether you choose UFW for its simplicity, firewalld for its dynamic zone-based approach, or iptables for maximum control, the key is to implement the principle of least privilege: only allow what's necessary and block everything else.

✅ Key Takeaways:
  • Always allow SSH before enabling your firewall
  • Test rules before disconnecting from your server
  • Use specific rules rather than blanket allows
  • Enable logging to monitor suspicious activity
  • Regularly audit and update your firewall rules
  • Combine firewall protection with other security measures

Remember that a firewall is just one layer of your security strategy. Combine it with regular updates, strong passwords or SSH keys, fail2ban, intrusion detection systems, and security monitoring for comprehensive server protection.

Additional Security Recommendations

To further enhance your server security beyond the firewall:

  • Install Fail2Ban: Automatically ban IPs that show malicious signs
  • Use SSH Keys: Disable password authentication entirely
  • Enable Two-Factor Authentication: Add an extra layer of security
  • Regular Updates: Keep your system and packages up to date
  • Security Auditing: Use tools like Lynis or OpenSCAP for security audits
  • Intrusion Detection: Install AIDE or Tripwire to monitor file integrity
  • Log Monitoring: Regularly review system logs for suspicious activity

Common Ports Reference

Service Port Protocol
SSH 22 TCP
FTP 21 TCP
SFTP 22 TCP
HTTP 80 TCP
HTTPS 443 TCP
SMTP 25 TCP
SMTP Submission 587 TCP
SMTPS 465 TCP
IMAP 143 TCP
IMAPS 993 TCP
POP3 110 TCP
POP3S 995 TCP
MySQL/MariaDB 3306 TCP
PostgreSQL 5432 TCP
MongoDB 27017 TCP
Redis 6379 TCP
DNS 53 TCP/UDP
NTP 123 UDP
RDP 3389 TCP
Docker 2375-2376 TCP