how to setup simple firewall in linux

how to setup simple firewall in linux

A firewall is your Linux system’s first line of defense against unauthorized access, malicious traffic, and cyber attacks. Whether you’re running a personal desktop, a home server, or a cloud-based production environment, setting up a properly configured firewall is one of the most essential security practices you can implement.

This guide walks you through three different approaches to setting up a simple yet effective firewall on Linux:

  • UFW (Uncomplicated Firewall) – Perfect for beginners and Ubuntu/Debian users
  • firewalld – Ideal for RHEL/CentOS/Fedora users and those who prefer a zone-based approach
  • nftables – For advanced users who want direct control over Netfilter (the modern replacement for iptables)

By the end of this guide, you’ll have a working firewall that protects your system while allowing legitimate traffic like SSH, web browsing, and application-specific ports. All commands are tested on Ubuntu 24.04, Debian 12, Rocky Linux 9, and Fedora 40.

What You’ll Learn:

  • The difference between stateful and stateless firewalls
  • How to allow and block specific ports and IP addresses
  • How to make your firewall rules persistent across reboots
  • Common troubleshooting techniques

Let’s dive in and secure your Linux system in under 10 minutes.


Table of Contents

  1. Understanding Linux Firewall Basics
  2. Prerequisites
  3. Method 1: Setting Up UFW (Ubuntu/Debian)
  4. Method 2: Setting Up firewalld (RHEL/CentOS/Fedora)
  5. Method 3: Setting Up nftables (Advanced)
  6. Making Your Firewall Persistent
  7. Testing and Verifying Your Firewall
  8. Common Firewall Rules Examples
  9. Troubleshooting
  10. Conclusion

1. Understanding Linux Firewall Basics

Before we start configuring, let’s understand what a firewall does and how Linux handles it.

What is a Firewall?

A firewall is a network security system that monitors and controls incoming and outgoing network traffic based on predefined security rules. Think of it as a security guard at the entrance of your server:

  • Incoming traffic – Packets trying to reach your system from the internet or local network
  • Outgoing traffic – Packets leaving your system to other computers
  • Forwarded traffic – Packets passing through your system (if acting as a router)

Stateful vs. Stateless Firewalls

TypeDescriptionExample
StatefulTracks active connections and automatically allows reply trafficUFW, firewalld, nftables (default)
StatelessTreats each packet independently without connection trackingLegacy iptables (without conntrack)

Modern Linux firewalls use stateful packet inspection, meaning once you allow an outgoing connection (e.g., your server requests a webpage), the firewall automatically allows the returning response.

The Netfilter Framework

All Linux firewall solutions ultimately communicate with Netfilter – the packet filtering subsystem built directly into the Linux kernel. The tools we’ll use (UFW, firewalld, nftables) are just user-friendly interfaces to Netfilter.


2. Prerequisites

Before setting up your firewall, ensure you have:

System Requirements

  • A Linux distribution (Ubuntu 20.04+, Debian 11+, RHEL 8+, Rocky Linux 8+, AlmaLinux 8+, Fedora 36+)
  • Root access or sudo privileges
  • Basic familiarity with the command line

⚠️ Critical Warning for Remote Servers

If you are configuring a firewall on a remote server (VPS, cloud instance, etc.), always ensure you have out-of-band access (console via hosting provider) or keep your SSH session active while testing. Locking yourself out of a remote server requires manual intervention from your hosting provider.

Check Your Current Firewall Status

Bash
# Check if any firewall is already running
sudo ufw status
sudo firewall-cmd --state
sudo nft list ruleset

# Check open ports (before firewall)
sudo ss -tlnp
sudo netstat -tlnp

3. Method 1: Setting Up UFW (Ubuntu/Debian)

UFW (Uncomplicated Firewall) is the default firewall management tool on Ubuntu and Debian. It’s designed to be user-friendly while still powerful enough for most use cases.

Step 1: Install UFW

Most Ubuntu/Debian installations include UFW by default. If not, install it:

Bash
sudo apt update
sudo apt install ufw -y

Step 2: Set Default Policies

Default policies determine what happens to traffic that doesn’t match any specific rule.

Bash
# Deny all incoming traffic by default
sudo ufw default deny incoming

# Allow all outgoing traffic by default (system can initiate connections)
sudo ufw default allow outgoing

# Deny all forwarded traffic (unless your system is a router)
sudo ufw default deny routed

Step 3: Allow Essential Services (Before Enabling!)

This is critical for remote servers – always allow SSH before enabling the firewall:

Bash
# Allow SSH (port 22) – CHANGE if you use a custom SSH port
sudo ufw allow ssh
# Or explicitly: sudo ufw allow 22/tcp

# For custom SSH port (e.g., 2222):
sudo ufw allow 2222/tcp

Step 4: Allow Additional Services

Bash
# Web server traffic
sudo ufw allow 80/tcp    # HTTP
sudo ufw allow 443/tcp   # HTTPS

# Database access (if needed)
sudo ufw allow 3306/tcp  # MySQL
sudo ufw allow 5432/tcp  # PostgreSQL

# Allow specific IP to access MySQL (more secure)
sudo ufw allow from 192.168.1.100 to any port 3306

# Allow a range of ports
sudo ufw allow 3000:3005/tcp

# Allow based on application profile (if available)
sudo ufw allow 'Apache Full'
sudo ufw allow 'OpenSSH'

To see available application profiles:

Bash
sudo ufw app list

Step 5: Enable UFW

Bash
# Enable the firewall (this activates all rules)
sudo ufw enable

# You'll see: "Command may disrupt existing ssh connections. Proceed with operation (y|n)?" 
# Type 'y' and press Enter

Step 6: Check Firewall Status

Bash
# Verbose status with rule numbers
sudo ufw status verbose numbered

# Example output:
# Status: active
# Logging: on (low)
# Default: deny (incoming), allow (outgoing), deny (routed)
# New profiles: skip
#
# To                         Action      From
# --                         ------      ----
# [ 1] 22/tcp                 ALLOW IN    Anywhere
# [ 2] 80/tcp                 ALLOW IN    Anywhere
# [ 3] 443/tcp                ALLOW IN    Anywhere

Step 7: Managing UFW Rules

Bash
# Delete a rule by number (find numbers from status command)
sudo ufw delete 2

# Delete by rule specification
sudo ufw delete allow 80/tcp

# Insert rule at specific position
sudo ufw insert 1 deny from 203.0.113.0/24

# Block a specific IP address
sudo ufw deny from 192.168.1.100

# Block a subnet
sudo ufw deny from 192.168.1.0/24

# Reset UFW to default (careful - this removes all rules)
sudo ufw reset

Complete UFW Setup Script (Copy-Paste Ready)

Bash
#!/bin/bash
# Simple UFW Firewall Setup Script

# Reset to defaults
sudo ufw --force reset

# Set default policies
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw default deny routed

# Allow essential services
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# Optional: Allow ping (ICMP)
sudo ufw allow proto icmp from any to any

# Enable firewall
sudo ufw --force enable

# Show status
sudo ufw status verbose

4. Method 2: Setting Up firewalld (RHEL/CentOS/Fedora)

firewalld is the default firewall management tool on RHEL, CentOS, Rocky Linux, AlmaLinux, and Fedora. It uses a zone-based approach, making it ideal for systems that connect to multiple networks (e.g., laptop with home, office, and public Wi-Fi).

Understanding firewalld Zones

Zones define the level of trust for network connections:

ZoneTrust LevelTypical Use
dropLowestAll incoming packets dropped
blockVery LowReject with ICMP messages
publicLowUntrusted public networks (default)
externalLowNAT/masquerading for outgoing
internalMediumTrusted internal network
dmzMediumDemilitarized zone for public services
workHighTrusted work network
homeHighTrusted home network
trustedHighestAccept all traffic

Step 1: Install firewalld

Bash
# RHEL/CentOS/Rocky/AlmaLinux
sudo dnf install firewalld -y

# Ubuntu/Debian (less common but available)
sudo apt install firewalld -y

Step 2: Start and Enable firewalld

Bash
# Start the service
sudo systemctl start firewalld

# Enable to start on boot
sudo systemctl enable firewalld

# Check status
sudo systemctl status firewalld

Step 3: Check Default Zone

Bash
# Check default zone (usually "public")
sudo firewall-cmd --get-default-zone

# List all available zones
sudo firewall-cmd --get-zones

# See active zones and their rules
sudo firewall-cmd --get-active-zones

Step 4: Configure Basic Rules

Bash
# Allow SSH (essential for remote servers)
sudo firewall-cmd --add-service=ssh --permanent

# Allow web traffic
sudo firewall-cmd --add-service=http --permanent
sudo firewall-cmd --add-service=https --permanent

# Or allow by port number
sudo firewall-cmd --add-port=8080/tcp --permanent
sudo firewall-cmd --add-port=3000-3010/tcp --permanent

Step 5: Reload and Verify

Bash
# Reload to apply permanent rules
sudo firewall-cmd --reload

# Check all rules in default zone
sudo firewall-cmd --list-all

# Example output:
# public (active)
#   target: default
#   icmp-block-inversion: no
#   interfaces: eth0
#   sources: 
#   services: ssh http https
#   ports: 8080/tcp
#   protocols: 
#   forward: no
#   masquerade: no
#   rich-rules:

Step 6: Advanced firewalld Management

Bash
# Block a specific IP address
sudo firewall-cmd --add-rich-rule='rule family="ipv4" source address="203.0.113.50" drop' --permanent

# Allow a specific IP to access SSH only
sudo firewall-cmd --add-rich-rule='rule family="ipv4" source address="192.168.1.100" service name="ssh" accept' --permanent

# Allow a subnet
sudo firewall-cmd --add-source=192.168.1.0/24 --zone=internal --permanent

# Change default zone for an interface
sudo firewall-cmd --change-interface=eth0 --zone=internal --permanent

# Allow ICMP (ping) – enabled by default, disable if needed
sudo firewall-cmd --remove-icmp-block=echo-request --permanent

# Block ICMP
sudo firewall-cmd --add-icmp-block=echo-request --permanent

# Reload after changes
sudo firewall-cmd --reload

Complete firewalld Setup Script (RHEL/CentOS/Fedora)

Bash
#!/bin/bash
# Simple firewalld Setup Script

# Reset to default
sudo systemctl start firewalld
sudo firewall-cmd --runtime-to-permanent
sudo firewall-cmd --reload

# Set default zone to public
sudo firewall-cmd --set-default-zone=public

# Remove all existing services from public zone
sudo firewall-cmd --zone=public --remove-service=dhcpv6-client --permanent

# Add essential services
sudo firewall-cmd --add-service=ssh --permanent
sudo firewall-cmd --add-service=http --permanent
sudo firewall-cmd --add-service=https --permanent

# Reload and verify
sudo firewall-cmd --reload
sudo firewall-cmd --list-all

5. Method 3: Setting Up nftables (Advanced)

nftables is the modern replacement for iptables and is now the default firewall framework in most Linux distributions. It provides a unified syntax for both IPv4 and IPv6 with better performance.

Note: This method is for advanced users. Beginners should use UFW or firewalld.

Step 1: Install nftables

Bash
# Ubuntu/Debian
sudo apt install nftables -y

# RHEL/CentOS/Fedora
sudo dnf install nftables -y

Step 2: Create a Basic Configuration

Create /etc/nftables.conf:

#!/usr/sbin/nft -f

# Flush existing rules
flush ruleset

# Create table for IPv4 and IPv6 (inet family)
table inet filter {
    # Input chain – incoming traffic
    chain input {
        type filter hook input priority filter; policy drop;

        # Allow loopback
        iif lo accept

        # Allow established/related connections
        ct state established,related accept

        # Allow ICMP (ping)
        ip protocol icmp accept
        ip6 nexthdr icmpv6 accept

        # Allow SSH
        tcp dport 22 accept

        # Allow HTTP/HTTPS
        tcp dport { 80, 443 } accept

        # Log dropped packets
        log prefix "nftables INPUT drop: " counter drop
    }

    # Forward chain – routed traffic (drop by default)
    chain forward {
        type filter hook forward priority filter; policy drop;
    }

    # Output chain – outgoing traffic (allow by default)
    chain output {
        type filter hook output priority filter; policy accept;
    }
}

Step 3: Load and Enable nftables

Bash
# Load the configuration
sudo nft -f /etc/nftables.conf

# Verify rules
sudo nft list ruleset

# Enable and start service
sudo systemctl enable nftables
sudo systemctl start nftables

Step 4: Managing nftables Rules

Bash
# List rules with handles (for deletion)
sudo nft list ruleset -a

# Add rule to allow specific IP
sudo nft add rule inet filter input ip saddr 192.168.1.100 accept

# Insert rule at position 2
sudo nft insert rule inet filter input position 2 ip saddr 10.0.0.0/8 drop

# Delete rule by handle (find handle with -a flag)
sudo nft delete rule inet filter input handle 5

# Flush all rules (careful!)
sudo nft flush ruleset

# Save current rules to config
sudo nft list ruleset > /etc/nftables.conf

6. Making Your Firewall Persistent

Firewall rules are stored in memory and lost on reboot unless saved.

For UFW

Bash
# UFW rules are automatically persistent when enabled
# To ensure service starts at boot:
sudo systemctl enable ufw

For firewalld

Bash
# firewalld handles persistence automatically with --permanent
# Ensure service is enabled
sudo systemctl enable firewalld

For nftables

Bash
# Enable service to load rules on boot
sudo systemctl enable nftables

# Rules are loaded from /etc/nftables.conf at boot
# After making changes, save:
sudo nft list ruleset > /etc/nftables.conf

7. Testing and Verifying Your Firewall

Check Firewall Status

Bash
# UFW
sudo ufw status verbose

# firewalld
sudo firewall-cmd --list-all
sudo firewall-cmd --get-active-zones

# nftables
sudo nft list ruleset

Test from Another Machine

Bash
# Test if SSH is accessible
ssh user@your-server-ip

# Test HTTP with curl
curl -I http://your-server-ip

# Test if a blocked port is actually blocked (from remote)
telnet your-server-ip 25  # Should timeout or refuse

Check Firewall Logs

Bash
# UFW logs
sudo tail -f /var/log/ufw.log

# firewalld logs
sudo journalctl -u firewalld -f

# nftables logs (if configured)
sudo dmesg | grep -i "nftables"
sudo journalctl -k | grep -i "nftables"

8. Common Firewall Rules Examples

Web Server Configuration

Allow only HTTP, HTTPS, and SSH, block everything else.

UFW:

Bash
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

firewalld:

Bash
sudo firewall-cmd --set-default-zone=public
sudo firewall-cmd --remove-service=dhcpv6-client --permanent
sudo firewall-cmd --add-service=ssh --permanent
sudo firewall-cmd --add-service=http --permanent
sudo firewall-cmd --add-service=https --permanent
sudo firewall-cmd --reload

Database Server Configuration

Allow SSH and database port only from specific IPs.

UFW:

Bash
sudo ufw default deny incoming
sudo ufw allow from 10.0.0.0/8 to any port 22
sudo ufw allow from 192.168.1.0/24 to any port 5432
sudo ufw enable

firewalld:

Bash
sudo firewall-cmd --add-rich-rule='rule family="ipv4" source address="10.0.0.0/8" service name="ssh" accept' --permanent
sudo firewall-cmd --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port port="5432" protocol="tcp" accept' --permanent
sudo firewall-cmd --reload

Rate Limiting (Prevent Brute Force)

Limit SSH connection attempts to 3 per minute.

UFW:

Bash
sudo ufw limit ssh

firewalld:

Bash
sudo firewall-cmd --add-rich-rule='rule family="ipv4" service name="ssh" limit value="3/m" accept' --permanent
sudo firewall-cmd --reload

Allow Only Outbound DNS

UFW:

Bash
sudo ufw default deny outgoing
sudo ufw allow out 53/tcp
sudo ufw allow out 53/udp
sudo ufw allow out 22/tcp  # If you need SSH out

9. Troubleshooting

Problem 1: Locked Out of Remote Server

Prevention: Always add SSH allow rule before enabling firewall.

Recovery (if you have console access):

Bash
# Via hosting provider's console or IPMI
sudo ufw disable
# or
sudo systemctl stop firewalld
# or
sudo nft flush ruleset

Problem 2: Application Not Accessible

Bash
# Check if firewall is blocking
sudo ufw status verbose
sudo firewall-cmd --list-all
sudo nft list ruleset

# Temporarily disable to test (DANGER - only for testing)
sudo ufw disable
sudo systemctl stop firewalld

# Check if application is listening on correct interface
sudo ss -tlnp | grep <port>

Problem 3: Rules Disappeared After Reboot

Bash
# UFW – ensure enabled
sudo ufw status  # Should show "active"

# firewalld – check service
sudo systemctl is-enabled firewalld

# nftables – check service and config
sudo systemctl status nftables
sudo nft list ruleset

Problem 4: Docker Conflicts with Firewall

Docker manipulates iptables directly. Solutions:

Bash
# Option 1: Restart firewall after Docker
sudo systemctl restart docker
sudo ufw reload  # or sudo systemctl restart firewalld

# Option 2: Configure Docker to respect firewall rules
# Edit /etc/docker/daemon.json
{
  "iptables": false
}

10. Conclusion

Setting up a simple firewall on Linux is one of the most important security steps you can take. Whether you choose UFW (Ubuntu/Debian), firewalld (RHEL/Fedora), or nftables (advanced), the principles remain the same:

  1. Deny all incoming traffic by default
  2. Allow only necessary services (SSH, HTTP, HTTPS)
  3. Allow outgoing traffic (or restrict if needed)
  4. Make rules persistent across reboots
  5. Test thoroughly before relying on the firewall

Quick Reference: Which Tool Should You Use?

Your SituationRecommended Tool
Ubuntu/Debian desktop or serverUFW (simplest)
RHEL/CentOS/Rocky/AlmaLinuxfirewalld (default)
Fedora Workstationfirewalld
Advanced user needing precise controlnftables
Cloud server (AWS, DO, Vultr)UFW or firewalld
Container/Kubernetes environmentnftables or Cilium

Final Checklist

  • [ ] Firewall is active and enabled at boot
  • [ ] SSH port is allowed (critical for remote servers)
  • [ ] Default incoming policy is DENY/REJECT/DROP
  • [ ] Required application ports are explicitly allowed
  • [ ] Tested from external connection
  • [ ] Rules are persistent (survive reboot)

Your Next Steps: Once your basic firewall is working, consider exploring more advanced features:

  • IP whitelisting/blacklisting
  • Rate limiting for brute force protection
  • Port knocking for SSH
  • Integration with fail2ban

Found this guide helpful? Bookmark it for future reference or share it with your team. For more Linux security guides, check out our other tutorials on SSH hardening, intrusion detection, and system monitoring.

Total
4
Shares

Leave a Reply

Previous Post
rlogin, rsh and rcp commands in Linux and it perimeters

rlogin, rsh and rcp commands in Linux and it perimeters

Next Post
What are the important rules to setup firewall

Important Firewall Rules to Configure

Related Posts