Skip to main content

Firewall Basics With UFW and firewalld

Media Firewall Basics With UFW and firewalld

A firewall is one of the most important security controls on a Linux computer or server. It decides which network connections are allowed, which are blocked and which services can be reached from other devices.

Linux includes powerful firewall capabilities through the kernel’s Netfilter system. However, configuring the underlying rules directly can be complicated. Tools such as UFW and firewalld provide simpler ways to manage those rules without having to build an entire firewall configuration manually. (firewalld⁠)

This guide explains the basics of both tools, including how to enable a firewall safely, open and close ports, restrict access and avoid accidentally locking yourself out of a remote server.

What Does a Linux Firewall Actually Do?

A host-based firewall controls network traffic entering, leaving or passing through a Linux machine.

For most desktops and servers, the main concern is incoming traffic. A firewall can prevent another device from connecting to a service unless you have explicitly allowed it.

For example, a server might be running:

  • SSH on TCP port 22
  • A website on TCP port 80
  • An encrypted website on TCP port 443
  • A database on TCP port 3306
  • A custom application on TCP port 8080

Without suitable firewall rules, some of these services may be reachable from networks that should not have access to them.

A common baseline policy is therefore:

  • Deny unsolicited incoming connections
  • Allow normal outgoing connections
  • Open only the services that are genuinely required
  • Restrict administrative services to trusted addresses where possible

A firewall does not replace software updates, strong passwords, multi-factor authentication or secure application configuration. It adds another protective layer.

UFW and firewalld: What Is the Difference?

UFW stands for Uncomplicated Firewall. It is designed to make straightforward firewall rules easier to create and manage. It is commonly associated with Ubuntu and other Debian-based distributions.

firewalld is a dynamically managed firewall service commonly used by distributions in the Red Hat family, including Fedora, Rocky Linux, AlmaLinux and Red Hat Enterprise Linux. It organises rules around zones, services and network interfaces.

Both tools ultimately manage Linux firewall rules, but their operating models are different.

UFW is usually easier when:

  • You are managing a desktop or straightforward server
  • The machine has a small number of network interfaces
  • You want simple allow-and-deny rules
  • You are using Ubuntu or a related distribution

firewalld is usually better when:

  • The machine connects to networks with different trust levels
  • You need different rules for different interfaces
  • You want to use predefined service definitions
  • You are managing Fedora, RHEL or a related distribution
  • Firewall rules need to be changed without restarting the firewall service

firewalld uses zones to represent different levels of network trust. A public Wi-Fi connection, for example, should normally be assigned a less-trusted zone than an internal office network. (firewalld⁠)

You would not normally run UFW and firewalld as competing firewall managers on the same machine. Choose the tool supported by your distribution and manage the rules consistently through it.

Part One: UFW Basics

Check Whether UFW Is Installed

On Ubuntu, UFW is often installed by default. Check its status with:

sudo ufw status

You may see:

Status: inactive

This means UFW is installed but is not currently enforcing its rules.

Install it on a Debian-based distribution with:

sudo apt update

sudo apt install ufw

Set Sensible Default Policies

Before enabling UFW, define the default behaviour:

sudo ufw default deny incoming

sudo ufw default allow outgoing

This blocks unsolicited incoming connections while allowing the machine to initiate normal outbound connections.

For many desktops and conventional servers, this is a sensible starting position.

Protect Remote SSH Access Before Enabling UFW

This is one of the most important steps in the entire guide.

When configuring a remote server, allow SSH before enabling the firewall:

sudo ufw allow OpenSSH

Alternatively, allow the port directly:

sudo ufw allow 22/tcp

If SSH is using a custom port, allow that port instead:

sudo ufw allow 2222/tcp

Failing to allow the correct SSH port before enabling the firewall could disconnect your current session and prevent you from reconnecting. Ubuntu’s guidance similarly recommends permitting OpenSSH before enabling UFW on a remote system. (Ubuntu Documentation⁠)

Ideally, keep a provider console, hypervisor console or other recovery route available when changing remote firewall rules.

Enable UFW

After confirming that required management access is allowed, enable the firewall:

sudo ufw enable

Check the result:

sudo ufw status verbose

A typical result might show:

Status: active

Logging: on

Default: deny (incoming), allow (outgoing), disabled (routed)

Allow a Port

To allow HTTP traffic on TCP port 80:

sudo ufw allow 80/tcp

Allow HTTPS on TCP port 443:

sudo ufw allow 443/tcp

Allow a custom TCP application:

sudo ufw allow 8080/tcp

Allow a UDP service:

sudo ufw allow 51820/udp

Specifying TCP or UDP avoids creating a broader rule than necessary.

Allow a Named Application Profile

Some installed applications provide predefined UFW profiles.

List them with:

sudo ufw app list

You might see entries such as:

OpenSSH

Nginx Full

Nginx HTTP

Nginx HTTPS

Allow a profile with:

sudo ufw allow "Nginx Full"

Inspect what a profile permits before using it:

sudo ufw app info "Nginx Full"

Application profiles can make configurations easier to understand than lists of unexplained port numbers.

Allow Access From One IP Address

To allow all traffic from a trusted management address:

sudo ufw allow from 203.0.113.25

A safer approach is usually to limit the address to a particular service:

sudo ufw allow from 203.0.113.25 to any port 22 proto tcp

This permits SSH from that source without giving it unrestricted access to every listening service.

Allow Access From a Local Network

To allow SSH from a private subnet:

sudo ufw allow from 192.168.1.0/24 to any port 22 proto tcp

This can be useful for internal systems that should be administered only from the office network or a management VLAN.

Be careful with private address ranges on cloud servers. The source address seen by the server may not always be the one you expect because of VPNs, proxies, network address translation or load balancers.

Deny a Connection Explicitly

UFW’s default incoming policy may already block the connection, but explicit deny rules can make your intentions clearer:

sudo ufw deny 23/tcp

To block a particular address:

sudo ufw deny from 203.0.113.50

Rate-Limit SSH Connections

UFW includes a simple rate-limiting option:

sudo ufw limit OpenSSH

Or:

sudo ufw limit 22/tcp

This may reduce repeated rapid connection attempts. It should not be treated as a complete defence against brute-force attacks, however. SSH keys, disabled password login where appropriate, multi-factor authentication and proper monitoring remain important.

View Numbered Rules

To display active rules with numbers:

sudo ufw status numbered

Example:

[ 1] 22/tcp     ALLOW IN    Anywhere

[ 2] 80/tcp     ALLOW IN    Anywhere

[ 3] 443/tcp    ALLOW IN    Anywhere

Numbered output makes removing rules easier.

Delete a UFW Rule

Delete a rule by repeating it with the delete keyword:

sudo ufw delete allow 8080/tcp

Or delete it by number:

sudo ufw status numbered

sudo ufw delete 3

Check the numbered list again after a deletion because the remaining rule numbers may change.

Enable Logging

Enable standard logging with:

sudo ufw logging on

Select a logging level if needed:

sudo ufw logging low

sudo ufw logging medium

sudo ufw logging high

Higher logging levels can generate a significant amount of data, particularly on an internet-facing system.

Logs may be available through the system journal or files under /var/log, depending on the distribution’s logging configuration.

Temporarily Disable UFW

To stop enforcing UFW rules:

sudo ufw disable

This keeps the configuration but disables the firewall.

To remove the rules and restore UFW to its default state:

sudo ufw reset

A reset is destructive. Review the impact before using it on a remote or production machine.

Part Two: firewalld Basics

Check Whether firewalld Is Running

Check the service through systemd:

sudo systemctl status firewalld

You can also ask firewalld directly:

sudo firewall-cmd --state

A running service should return:

running

firewall-cmd is the main command-line client for checking and changing firewalld configurations. (firewalld⁠)

Install firewalld on a supported distribution through its package manager. For example:

sudo dnf install firewalld

Start it and enable it at boot:

sudo systemctl enable --now firewalld

Understanding firewalld Zones

Zones are central to firewalld.

A zone contains a set of rules defining which services and ports are allowed. A network interface or source address can then be assigned to that zone.

Common predefined zones include:

  • drop
  • block
  • public
  • external
  • internal
  • dmz
  • work
  • home
  • trusted

The names suggest their intended trust levels, but you should inspect the actual configuration rather than relying only on the label.

List available zones:

sudo firewall-cmd --get-zones

Show active zones and their interfaces:

sudo firewall-cmd --get-active-zones

Check the default zone:

sudo firewall-cmd --get-default-zone

Inspect the public zone:

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

firewalld stores vendor-supplied defaults separately from locally customised zone configurations. Custom zone files are normally kept under /etc/firewalld/zones. (firewalld⁠)

Runtime and Permanent Rules

firewalld separates its runtime configuration from its permanent configuration.

A runtime change takes effect immediately but normally disappears after a reload or restart.

A permanent change is stored but may not affect the current runtime configuration until firewalld is reloaded.

For example, this opens HTTP temporarily:

sudo firewall-cmd --zone=public --add-service=http

This adds the rule permanently:

sudo firewall-cmd --zone=public --add-service=http --permanent

Apply permanent changes to the running configuration:

sudo firewall-cmd --reload

The separation between runtime and permanent rules makes it possible to test some changes before committing them. (firewalld⁠)

Allow a Predefined Service

To allow HTTP in the public zone:

sudo firewall-cmd --zone=public --add-service=http --permanent

Allow HTTPS:

sudo firewall-cmd --zone=public --add-service=https --permanent

Allow SSH:

sudo firewall-cmd --zone=public --add-service=ssh --permanent

Reload the firewall:

sudo firewall-cmd --reload

Confirm the allowed services:

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

Where an appropriate predefined service exists, using it is usually clearer than opening individual ports. firewalld includes definitions for many common services and can display them with firewall-cmd --get-services. (firewalld⁠)

Open a Specific Port

To open TCP port 8080:

sudo firewall-cmd --zone=public --add-port=8080/tcp --permanent

sudo firewall-cmd --reload

Open a UDP port:

sudo firewall-cmd --zone=public --add-port=51820/udp --permanent

sudo firewall-cmd --reload

List open ports:

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

Remove a Service or Port

Remove HTTP access:

sudo firewall-cmd --zone=public --remove-service=http --permanent

Remove TCP port 8080:

sudo firewall-cmd --zone=public --remove-port=8080/tcp --permanent

Then reload:

sudo firewall-cmd --reload

Assign an Interface to a Zone

List network interfaces:

ip address

Move an interface into the internal zone:

sudo firewall-cmd --zone=internal --change-interface=ens192 --permanent

sudo firewall-cmd --reload

Check the result:

sudo firewall-cmd --get-active-zones

Before moving a remote server’s main interface, confirm that the destination zone allows SSH or whichever service you use for administration.

Create a Rule for One Trusted Address

Rich rules provide more detailed matching.

For example, allow SSH from one IP address:

sudo firewall-cmd --zone=public \

  --add-rich-rule='rule family="ipv4" source address="203.0.113.25" service name="ssh" accept' \

  --permanent

Reload:

sudo firewall-cmd --reload

List rich rules:

sudo firewall-cmd --zone=public --list-rich-rules

Remove the rule by repeating it with --remove-rich-rule:

sudo firewall-cmd --zone=public \

  --remove-rich-rule='rule family="ipv4" source address="203.0.113.25" service name="ssh" accept' \

  --permanent


 

sudo firewall-cmd --reload

Rich rules are powerful, but the syntax must be entered carefully. Always verify the active configuration after making changes.

Checking Which Services Are Actually Listening

Opening a firewall port does not start the application behind it.

Similarly, closing a firewall port does not stop the service. It only prevents matching network traffic from reaching it through that path.

Check listening TCP and UDP sockets with:

sudo ss -tulpn

Useful fields include:

  • The protocol
  • The local listening address
  • The port number
  • The process using the socket

A service bound to 127.0.0.1 is normally available only from the local machine.

A service bound to 0.0.0.0 may be listening on all IPv4 interfaces, although firewall rules can still restrict access.

For IPv6, look for addresses such as :: and confirm that your firewall rules cover both address families as intended.

Test From Another Device

Do not rely entirely on the firewall’s status output. Test connectivity from another system.

For a web service:

curl -I http://server-address

For a TCP port:

nc -vz server-address 443

You can also scan systems you own or are authorised to assess with a tool such as Nmap:

nmap -sT server-address

A local test from the server itself may not accurately represent what a remote machine can reach.

Common Firewall Mistakes

Enabling the Firewall Before Allowing SSH

This is the classic remote-server mistake.

Always permit the correct management service first and keep a recovery console available.

Opening More Than the Application Needs

Avoid rules such as large port ranges unless the application genuinely requires them.

Instead of opening every database connection to the internet, restrict the database port to the application server, VPN subnet or management network that needs it.

Forgetting the Protocol

TCP and UDP are different protocols.

Opening:

sudo ufw allow 53/tcp

does not automatically allow:

53/udp

Some services require one protocol, while others may require both.

Forgetting firewalld’s Permanent Configuration

A runtime rule can appear to work perfectly and then disappear after a reload or reboot.

Check both the runtime and permanent configuration:

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

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

Reloading Before Confirming Remote Access

When using firewalld, a temporary runtime rule may be keeping your session alive. Reloading can replace that runtime configuration with the permanent configuration.

Confirm that the permanent rules include your remote management access before running:

sudo firewall-cmd --reload

Assuming the Firewall Is the Only Filter

Traffic may be filtered by several layers, including:

  • A cloud security group
  • A hosting provider firewall
  • A broadband router
  • A corporate perimeter firewall
  • A VPN
  • A container platform
  • The host firewall itself
  • The application’s own access controls

Container platforms, virtualisation systems and VPN software may also create their own firewall rules, which can lead to unexpected interactions. (Ubuntu Documentation⁠)

Allowing a Port Without Securing the Service

A firewall can reduce exposure, but it cannot fix an insecure application.

If you open SSH to the internet, the SSH service still needs secure authentication.

If you open HTTPS, the web server still needs updates, appropriate TLS settings and secure application code.

If you expose a database, it still needs strong credentials and carefully configured user permissions.

A Simple UFW Server Baseline

For a basic Ubuntu web server managed through SSH:

sudo ufw default deny incoming

sudo ufw default allow outgoing


 

sudo ufw allow OpenSSH

sudo ufw allow 80/tcp

sudo ufw allow 443/tcp


 

sudo ufw enable

sudo ufw status verbose

A more restrictive configuration could permit SSH only from a trusted office address:

sudo ufw delete allow OpenSSH

sudo ufw allow from 203.0.113.25 to any port 22 proto tcp

Only make this change after confirming that the trusted public IP address is correct and stable.

A Simple firewalld Server Baseline

For a basic web server using the public zone:

sudo systemctl enable --now firewalld


 

sudo firewall-cmd --zone=public --add-service=ssh --permanent

sudo firewall-cmd --zone=public --add-service=http --permanent

sudo firewall-cmd --zone=public --add-service=https --permanent


 

sudo firewall-cmd --reload

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

Before assuming the rules are correct, also verify which interface is assigned to the public zone:

sudo firewall-cmd --get-active-zones

Which Firewall Tool Should You Learn?

For a single Ubuntu desktop, small server or simple virtual machine, UFW is often the more approachable choice.

For systems that use network zones, multiple interfaces or more dynamic network configurations, firewalld may provide a cleaner structure.

The most important lessons are the same whichever tool you choose:

  1. Start with a restrictive incoming policy.
  2. Allow only the services that are required.
  3. Limit sensitive services to trusted source addresses.
  4. Confirm both IPv4 and IPv6 behaviour.
  5. Test from another device.
  6. Document why every exception exists.
  7. Remove rules when services are retired.
  8. Keep a recovery method available when changing a remote firewall.

Final Thoughts

A firewall does not need to be complicated to be valuable. Even a small ruleset that blocks unsolicited incoming connections and exposes only necessary services can significantly reduce a system’s attack surface.

The real danger is not usually having too few complicated rules. It is having old, undocumented or overly broad rules that nobody remembers creating.

Whether you choose UFW or firewalld, keep the configuration deliberate, review it regularly and verify that the exposed services still match the machine’s purpose.

Need Help Securing Your Linux Systems?

Hamilton Group can help your organisation review Linux servers, firewall rules, remote-access controls and wider network security.

We can identify unnecessary exposed services, tighten administrative access and help build a practical security configuration that protects your systems without disrupting legitimate users.

Call 0330 043 0069 or visit hgmssp.com to speak with one of our IT and cybersecurity specialists.