Table of Contents
Understanding Linux Host Firewalls
Linux distributions commonly use two high-level firewall tools:
ufw– Uncomplicated Firewall (Ubuntu/Debian focused)firewalld– Dynamic firewall manager (Fedora/RHEL/openSUSE, etc.)
Both manage underlying packet filters (iptables/nftables) but present simpler interfaces. This chapter focuses on how to use them, not on deep packet filtering theory.
You typically use one of these tools on a system, not both.
UFW (Uncomplicated Firewall)
UFW basics
UFW is designed to be easy for beginners:
- Default policy: deny incoming, allow outgoing
- Rules are expressed in terms of:
- Port numbers (
80,22) - Service names (
ssh,http) - Protocols (
tcp,udp) - Optional source IPs or subnets
On Ubuntu, UFW is usually installed by default but disabled until you turn it on.
Checking UFW status
Use:
sudo ufw status
sudo ufw status verbose
verbose shows default policies and logging status.
If UFW is not installed:
sudo apt install ufw(For Debian-family systems; other distributions may package it differently.)
Enabling and disabling UFW
Before enabling UFW, ensure you won’t lock yourself out, especially on remote servers.
Allow SSH *before* enabling
If you connect via SSH on the default port (22):
sudo ufw allow sshor explicitly:
sudo ufw allow 22/tcpThen enable:
sudo ufw enableUFW will apply its default policy (usually: deny incoming, allow outgoing) plus your rules.
To disable temporarily:
sudo ufw disableDisabling UFW flushes its active rules but does not remove them from its configuration; re-enabling brings them back.
Default policies
Default policies decide what happens if no rule matches.
Typical secure baseline for a server:
sudo ufw default deny incoming
sudo ufw default allow outgoingFor a workstation you might choose the same. You can see them with:
sudo ufw status verboseAllowing and denying traffic
Basic allow rules
Syntax:
sudo ufw allow <port>sudo ufw allow <port>/<proto>sudo ufw allow from <source>- Combinations of above.
Examples:
- Allow HTTP and HTTPS:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp- Allow OpenSSH using service name:
sudo ufw allow ssh
Run sudo ufw app list to see additional predefined services (on some systems).
Allowing by source
You can restrict access to certain IPs or networks:
- Allow SSH only from your office IP:
sudo ufw allow from 203.0.113.10 to any port 22 proto tcp- Allow HTTP only from a local subnet:
sudo ufw allow from 192.168.1.0/24 to any port 80 proto tcpDeny and reject
deny– silently drop packets (common default)reject– actively respond with an error
Examples:
sudo ufw deny 23/tcp # block Telnet
sudo ufw reject 25/tcp # reject SMTP connections
If your default incoming policy is deny, you rarely need explicit deny rules unless you want to override an earlier allow.
Managing and ordering rules
Listing rules with numbers
Use numbered output:
sudo ufw status numbered
You’ll see rules with indices like [ 1], [ 2], etc. The order matters: earlier rules take precedence.
Deleting rules
You can delete by number or rule text.
- By number:
sudo ufw status numbered
sudo ufw delete 3- By rule:
sudo ufw delete allow 80/tcpInserting rules at a specific position
You can insert rules at a specific rule number:
sudo ufw insert 1 allow from 10.0.0.0/8 to any port 22 proto tcpThis places the rule at position 1 and shifts others down.
Application profiles
On some systems, services provide UFW application profiles, simplifying rule creation.
See available apps:
sudo ufw app listView details of an app:
sudo ufw app info "OpenSSH"Allow a profile:
sudo ufw allow "Apache Full"Profiles bundle multiple ports (e.g., HTTP and HTTPS) under one name.
Logging and troubleshooting with UFW
Enabling logging
UFW can log blocked (and allowed) connections:
sudo ufw logging on
# or levels: off, low, medium, high, full
sudo ufw logging mediumLogs typically appear in:
/var/log/ufw.log(on Ubuntu), and/or/var/log/syslogor the system journal.
Reading logs
Entries include:
- Action:
BLOCK,ALLOW - Interface:
IN=... OUT=... - Source:
SRC=... - Destination:
DST=... - Destination port:
DPT=...
Example (simplified):
Jun 12 12:34:56 host kernel: [UFW BLOCK] IN=eth0 SRC=203.0.113.5 DST=198.51.100.10 LEN=60 ...If a service is unreachable:
- Confirm it’s listening on the expected port.
- Check
sudo ufw status verbose. - Examine logs for blocked packets.
firewalld
firewalld concepts
firewalld introduces a different model than UFW:
- Zones – sets of rules for a given trust level.
- Services – named collections of ports and protocols (e.g.,
ssh,http). - Permanent vs runtime configuration:
- Runtime changes – applied immediately, lost on reboot/reload unless made permanent.
- Permanent changes – stored in config, applied on restart/reload.
Common default zones include:
public– untrusted network (default for most interfaces)home,work,internal– more trusted networksdrop,block– very restrictivetrusted– allows all traffic
firewalld manages either iptables or nftables under the hood but uses firewalld commands or firewall-cmd for configuration.
Checking firewalld status
Basic commands:
sudo systemctl status firewalld
sudo firewall-cmd --state
If it shows running, the firewall is active.
If firewalld is not installed:
- On Fedora/RHEL:
sudo dnf install firewalldThen enable at boot and start:
sudo systemctl enable --now firewalldZones and interfaces
Viewing zones
List available zones:
sudo firewall-cmd --get-zonesSee your default zone:
sudo firewall-cmd --get-default-zoneDisplay detailed info for a zone (runtime):
sudo firewall-cmd --zone=public --list-allAssigning interfaces to zones
firewalld applies a zone to each network interface.
See active zones and interfaces:
sudo firewall-cmd --get-active-zonesSet an interface to use a specific zone (runtime):
sudo firewall-cmd --zone=public --change-interface=eth0To make that assignment permanent:
sudo firewall-cmd --permanent --zone=public --change-interface=eth0
sudo firewall-cmd --reload
If you’re on a server with a single network interface, that interface is typically in public by default.
Services and ports
Using services
Services are predefined collections of ports/protocols, e.g.:
ssh→22/tcphttp→80/tcphttps→443/tcpdhcp,dns, etc.
List known services:
sudo firewall-cmd --get-servicesAllow a service in the default zone (runtime):
sudo firewall-cmd --add-service=sshMake it permanent:
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reloadYou can also specify a zone:
sudo firewall-cmd --zone=public --add-service=http
sudo firewall-cmd --zone=public --permanent --add-service=http
sudo firewall-cmd --reloadUsing ports directly
To open a specific port:
sudo firewall-cmd --add-port=8080/tcp
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --reloadTo close a port:
sudo firewall-cmd --remove-port=8080/tcp
sudo firewall-cmd --permanent --remove-port=8080/tcp
sudo firewall-cmd --reloadChecking zone rules
For the public zone, for example:
sudo firewall-cmd --zone=public --list-allOutput includes:
- Interfaces in the zone
- Allowed services and ports
- Source addresses (if any)
Runtime vs permanent configuration
This is a key point with firewalld:
--permanentmodifies the persistent configuration but does not affect the running state immediately.- Without
--permanent, changes apply to runtime only and will be lost on restart.
To synchronize permanent configuration into runtime:
sudo firewall-cmd --reloadCommon workflow:
- Test rules at runtime (no
--permanent). - Once satisfied, reapply the same commands with
--permanent. - Run
sudo firewall-cmd --reload.
Source-based rules
You can define rules that apply only to specific source networks.
Example: allow SSH from a trusted subnet in the public zone:
sudo firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" \
source address="192.168.1.0/24" service name="ssh" accept'To make permanent:
sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" \
source address="192.168.1.0/24" service name="ssh" accept'
sudo firewall-cmd --reloadRich rules allow more complex conditions and actions than basic service/port entries.
Locking down and testing
Example: basic server policy
For a typical web + SSH server using public zone:
- Ensure
eth0is inpubliczone. - Allow SSH and HTTP(S):
sudo firewall-cmd --zone=public --add-service=ssh
sudo firewall-cmd --zone=public --add-service=http
sudo firewall-cmd --zone=public --add-service=https
sudo firewall-cmd --zone=public --permanent --add-service=ssh
sudo firewall-cmd --zone=public --permanent --add-service=http
sudo firewall-cmd --zone=public --permanent --add-service=https
sudo firewall-cmd --reloadBy default, unsolicited incoming connections to other ports are blocked.
Checking connectivity
From another system, test:
ssh user@servercurl http://servercurl https://server(if HTTPS configured)
If something fails:
- Verify the service is running and listening.
- Run:
sudo firewall-cmd --get-active-zones
sudo firewall-cmd --zone=public --list-all- Confirm the appropriate service/port is allowed in the correct zone.
firewalld logging and debugging
firewalld itself uses system logging (journald or /var/log/messages depending on the distribution).
To inspect:
sudo journalctl -u firewalldPacket-level logging is controlled by backend rules (iptables/nftables). For basic troubleshooting, you normally rely on:
firewall-cmd --list-allfor zone infofirewall-cmd --list-all-zonesfor a full overview- System logs (via
journalctlor/var/log/*) for dropped packets if logging is configured there
Choosing Between UFW and firewalld
- UFW:
- Simpler syntax
- Popular on Debian/Ubuntu
- Good for single-user systems and straightforward servers
- firewalld:
- Zone-based, more flexible
- Standard on Fedora/RHEL/openSUSE
- Better suited for multi-interface, multi-network setups and dynamic changes
Use the tool that your distribution integrates by default, unless you have a specific reason to switch. Avoid running both simultaneously to prevent conflicts.
Practical Safety Tips
- Always ensure remote access (SSH) is allowed before enabling or tightening firewall rules.
- Test changes from a separate session or machine, so you don’t lose access.
- Start with a restrictive default incoming policy and explicitly open only what you need.
- Document your rules (e.g., comments in scripts you use to apply them) so you can easily reproduce and audit your configuration.