This guide explains how to install Firewalld on Arch Linux and configure zone-based firewall rules for securing your system. Firewalld provides dynamic firewall management through zones that define trust levels for network connections and interfaces. A laptop connecting to home WiFi, a coffee shop network, and a corporate VPN can automatically apply different security rules to each connection without manual reconfiguration. Developed by Red Hat and used as the default firewall on Fedora and RHEL-based distributions, Firewalld offers a more intuitive approach than raw nftables rules while supporting runtime changes without restarting services.
This guide covers understanding zone-based security concepts, configuring default zones and services, creating custom port rules, implementing rich rules for advanced filtering, managing permanent versus runtime configurations, and completely removing Firewalld when switching to alternative solutions. By the end, you will have a fully configured zone-based firewall protecting your Arch Linux system.
Firewalld uses nftables as its backend on Arch Linux and operates within its own namespace, allowing other applications like Docker or libvirt to maintain separate firewall rules. For configuration details beyond this guide, see the Arch Wiki Firewalld page.
Install Firewalld via Pacman
Arch Linux ships without a firewall by default, leaving incoming connections unfiltered. Firewalld is available in the official extra repository. Before installation, update your system to ensure package compatibility:
sudo pacman -Syu
Install Firewalld:
sudo pacman -S firewalld
Verify the installation by checking the Firewalld version:
firewall-cmd --version
Expected output:
2.4.0
Firewalld is now installed. The package includes firewall-cmd for command-line management, firewall-offline-cmd for configuration when the daemon is not running, and firewall-config for graphical management (requires the gtk3 optional dependency).
Enable and Start Firewalld
Enable the Firewalld service to start automatically at boot and start it immediately:
sudo systemctl enable --now firewalld.service
Verify the service is running:
systemctl status firewalld.service
Expected output showing Firewalld is active:
● firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; preset: disabled)
Active: active (running) since Fri 2026-01-31 12:00:00 UTC; 5s ago
Docs: man:firewalld(1)
Main PID: 1234 (firewalld)
Tasks: 2 (limit: 4915)
Memory: 32.1M
CPU: 412ms
CGroup: /system.slice/firewalld.service
└─1234 /usr/bin/python /usr/bin/firewalld --nofork --nopid
Confirm the firewall is active:
firewall-cmd --state
Expected output:
running
Do not run Firewalld simultaneously with other firewall managers like UFW or direct iptables/nftables services. Multiple firewall managers create conflicting rules and unpredictable behavior.
Understand Firewalld Zones
Firewalld organizes network traffic management through zones, which are named sets of rules that define the trust level for network connections. When a connection is established, Firewalld assigns it to a zone based on the source address or network interface, then applies that zone’s rules.
List all available zones:
firewall-cmd --get-zones
Expected output:
block dmz drop external home internal public trusted work
Each zone serves a specific security purpose:
| Zone | Default Behavior | Use Case |
|---|---|---|
| public | Rejects incoming except allowed services | Untrusted networks (default zone) |
| home | Trusts other computers on the network | Home networks with trusted devices |
| work | Trusts coworkers and network devices | Corporate networks |
| internal | Similar to home, for internal networks | Internal segments behind NAT |
| dmz | Limited access for DMZ servers | Publicly accessible servers |
| external | Masquerading enabled for routers | External-facing router interfaces |
| trusted | Accepts all network connections | Fully trusted networks only |
| drop | Drops all incoming without reply | Maximum stealth, no protocol responses |
| block | Rejects all incoming with ICMP message | Blocking with host unreachable notification |
The difference between drop and block affects how blocked clients perceive your server. With drop, connection attempts time out silently, making it harder for attackers to confirm the host exists. With block, clients immediately receive an ICMP host unreachable message, providing faster feedback for legitimate users who may have misconfigured their connection.
Check the default zone:
firewall-cmd --get-default-zone
Expected output:
public
The public zone is the default and appropriate for most server deployments. New interfaces without explicit zone assignments automatically use the default zone.
View Current Firewall Configuration
Before making changes, review the current firewall state. View all settings for the default zone:
firewall-cmd --list-all
Expected output showing the default public zone configuration:
public (active) target: default ingress-priority: 0 egress-priority: 0 icmp-block-inversion: no interfaces: eth0 sources: services: dhcpv6-client ssh ports: protocols: forward: yes masquerade: no forward-ports: source-ports: icmp-blocks: rich rules:
The output shows that the public zone is active with ssh and dhcpv6-client services enabled by default. This means SSH connections are already permitted, preventing lockouts when enabling the firewall on remote servers.
To view active zones and their assigned interfaces:
firewall-cmd --get-active-zones
To view settings for a specific zone:
firewall-cmd --info-zone=home
To list all zones with their complete configuration:
firewall-cmd --list-all-zones
Configure Services
Services in Firewalld are predefined port and protocol combinations that correspond to common applications. Using services instead of raw port numbers makes rules more readable and maintainable.
List Available Services
View all predefined services:
firewall-cmd --get-services
This displays hundreds of predefined services including http, https, ssh, mysql, postgresql, dns, and many others.
View details about a specific service:
firewall-cmd --info-service=http
Expected output:
http ports: 80/tcp protocols: source-ports: modules: destination: includes: helpers:
Add Services to a Zone
Add a service to the default zone (runtime only):
sudo firewall-cmd --add-service=http
Expected output:
success
This change is temporary and will not persist after a firewall reload or system reboot. To make the change permanent, add the --permanent flag:
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
When using --permanent, changes apply to the saved configuration but not the running firewall. Reload to apply permanent changes to the runtime:
sudo firewall-cmd --reload
To add a service to a specific zone:
sudo firewall-cmd --permanent --zone=internal --add-service=samba
Remove Services from a Zone
Remove a service using the --remove-service option:
sudo firewall-cmd --permanent --remove-service=dhcpv6-client
sudo firewall-cmd --reload
Verify the service was removed:
firewall-cmd --list-services
Configure Ports
When no predefined service matches your application, open ports directly.
Open Individual Ports
Open a TCP port permanently:
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --reload
Open a UDP port:
sudo firewall-cmd --permanent --add-port=51820/udp
sudo firewall-cmd --reload
List currently open ports:
firewall-cmd --list-ports
Open Port Ranges
Open a range of ports for applications that require multiple consecutive ports:
sudo firewall-cmd --permanent --add-port=6000-6010/tcp
sudo firewall-cmd --reload
Close Ports
Remove an open port:
sudo firewall-cmd --permanent --remove-port=8080/tcp
sudo firewall-cmd --reload
Manage Zone Assignments
Different network interfaces can be assigned to different zones, applying separate security policies to each.
Change the Default Zone
Change the default zone for new connections:
sudo firewall-cmd --set-default-zone=home
Expected output:
success
Changing the default zone is always permanent. No
--permanentflag or reload is required.
Assign an Interface to a Zone
Move an interface to a different zone:
sudo firewall-cmd --permanent --zone=internal --change-interface=eth1
sudo firewall-cmd --reload
Check which zone an interface belongs to:
firewall-cmd --get-zone-of-interface=eth1
Assign Zones with NetworkManager
If your system uses NetworkManager, assign zones to connection profiles for automatic zone switching when connecting to different networks. List connection profiles:
nmcli connection show
Assign a connection to a zone:
nmcli connection modify "Home WiFi" connection.zone home
Replace Home WiFi with your actual connection profile name. When you connect to this network, Firewalld automatically applies the home zone’s rules.
Create Rich Rules
Rich rules provide fine-grained control over traffic filtering when basic service and port rules are insufficient. They support filtering by source address, destination port, protocol, logging, and rate limiting within a single rule. Use rich rules to restrict services to specific IP ranges, implement connection logging for security monitoring, or create temporary access rules.
Allow Access from Specific IP Addresses
Allow a specific IP to access a service:
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.100" service name="ssh" accept'
sudo firewall-cmd --reload
Allow a subnet to access a specific port:
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.0.0/8" port port="3306" protocol="tcp" accept'
sudo firewall-cmd --reload
Block Specific IP Addresses
Drop all traffic from a specific IP address:
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.50" drop'
sudo firewall-cmd --reload
To reject (send ICMP unreachable) instead of silently dropping:
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.50" reject'
sudo firewall-cmd --reload
Log and Rate Limit Connections
Create a rule that logs and limits SSH connections from any source:
sudo firewall-cmd --permanent --add-rich-rule='rule service name="ssh" log prefix="SSH_CONN: " level="info" limit value="5/m" accept'
sudo firewall-cmd --reload
This logs SSH connections with a prefix, limited to 5 log entries per minute to prevent log flooding.
View and Remove Rich Rules
List all rich rules in the current zone:
firewall-cmd --list-rich-rules
Remove a rich rule by specifying the complete rule:
sudo firewall-cmd --permanent --remove-rich-rule='rule family="ipv4" source address="203.0.113.50" drop'
sudo firewall-cmd --reload
Configure Port Forwarding
Firewalld supports port forwarding for NAT scenarios where external traffic needs routing to internal servers.
Enable Masquerading
Port forwarding requires masquerading (source NAT) to be enabled on the zone. Masquerading rewrites the source IP address of forwarded packets to the firewall’s external IP, making it appear as though traffic originates from the firewall rather than the internal server. This allows internal hosts without public IPs to communicate with external networks.
sudo firewall-cmd --permanent --zone=public --add-masquerade
sudo firewall-cmd --reload
Verify masquerading is enabled:
firewall-cmd --query-masquerade
Forward Ports to Internal Hosts
Forward external port 8080 to an internal server’s port 80:
sudo firewall-cmd --permanent --zone=public --add-forward-port=port=8080:proto=tcp:toport=80:toaddr=192.168.1.10
sudo firewall-cmd --reload
Forward to a different port on the same host:
sudo firewall-cmd --permanent --add-forward-port=port=2222:proto=tcp:toport=22
sudo firewall-cmd --reload
List port forwarding rules:
firewall-cmd --list-forward-ports
Remove Port Forwarding
Removing a port forwarding rule requires specifying the complete original rule. Unlike services or ports, you cannot remove a forward by specifying only the port and protocol:
sudo firewall-cmd --permanent --remove-forward-port=port=8080:proto=tcp:toport=80:toaddr=192.168.1.10
sudo firewall-cmd --reload
If you forget the exact forwarding specification, list current forwards first with firewall-cmd --list-forward-ports and copy the complete rule.
Manage Runtime and Permanent Configuration
Firewalld maintains two configuration states: runtime (active but temporary) and permanent (saved but inactive until reload). Understanding this separation helps you test changes safely before committing them.
Test Changes Before Making Permanent
Add a rule without --permanent to test it:
sudo firewall-cmd --add-service=http
This change is active immediately but will not survive a reload or reboot. If the rule works correctly, make it permanent:
sudo firewall-cmd --runtime-to-permanent
This saves the entire current runtime configuration as permanent.
Use Temporary Rules with Timeouts
Add a rule that automatically expires after a specified duration:
sudo firewall-cmd --add-service=vnc-server --timeout=1h
This opens VNC access for one hour, then automatically removes the rule. Timeout values support seconds (default), minutes (m), or hours (h):
sudo firewall-cmd --add-port=5900/tcp --timeout=30m
Timeouts only work with runtime rules. You cannot combine
--timeoutwith--permanent.
Reload and Reset
Reload the firewall to apply permanent changes:
sudo firewall-cmd --reload
To completely reload the firewall and lose all runtime state information:
sudo firewall-cmd --complete-reload
To reset Firewalld to default configuration, removing all custom zones, services, and rules:
sudo firewall-cmd --reset-to-defaults
Using
--reset-to-defaultsremoves all customizations including SSH rules. If connected remotely, ensure you have console access before running this command.
Create Custom Services
Custom services simplify firewall management for applications that use multiple ports or non-standard configurations. Instead of opening individual ports and remembering which ports belong to which application, you create a named service definition that groups all required ports together. This makes rules more readable and easier to manage across multiple zones.
Service definitions are stored in /usr/lib/firewalld/services/ (system defaults, do not edit) and /etc/firewalld/services/ (custom services). Create a custom service file:
sudo nano /etc/firewalld/services/myapp.xml
Add the service definition:
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>MyApp</short>
<description>My custom application service</description>
<port protocol="tcp" port="9000"/>
<port protocol="tcp" port="9001"/>
</service>
Reload Firewalld to recognize the new service:
sudo firewall-cmd --reload
Verify the service is available:
firewall-cmd --info-service=myapp
Use the custom service like any predefined service:
sudo firewall-cmd --permanent --add-service=myapp
sudo firewall-cmd --reload
Configure Log Denied Packets
Firewalld can log packets that are dropped or rejected, useful for troubleshooting connection issues and monitoring potential attacks.
Check current log denied setting:
firewall-cmd --get-log-denied
Expected output:
off
Enable logging of denied packets:
sudo firewall-cmd --set-log-denied=all
Available log levels: all (logs all denied packets), unicast (only direct traffic to this host), broadcast (only broadcast traffic), multicast (only multicast traffic), or off. For most troubleshooting, unicast filters out noisy broadcast traffic while capturing relevant denied connections.
View denied packets in the system journal:
journalctl -k | grep -i reject
Monitor denied packets in real-time:
journalctl -kf | grep -i reject
Enable denied packet logging only temporarily for troubleshooting. Heavy traffic to blocked ports can generate excessive log entries and fill disk space.
Use the Graphical Interface
For desktop users, firewall-config provides a graphical interface for managing Firewalld. The utility is included with the Firewalld package but requires GTK3.
Install the optional GTK3 dependency:
sudo pacman -S gtk3
Launch the graphical configuration tool:
firewall-config
The interface allows you to configure zones, services, ports, and rich rules visually. Changes made in firewall-config can be applied to runtime only or saved permanently using the Configuration dropdown at the top of the window.
Troubleshoot Common Issues
Firewalld Service Will Not Start
If Firewalld fails to start, check the journal for errors:
journalctl -xeu firewalld.service
Common causes include conflicting firewall services or corrupted configuration files. Check for and disable conflicting services:
sudo systemctl disable --now iptables.service nftables.service ufw.service 2>/dev/null
If configuration files are corrupted, reset to defaults:
sudo rm -rf /etc/firewalld/*
sudo firewall-cmd --reload
Rules Not Taking Effect
If rules are not working, verify the firewall is running:
firewall-cmd --state
If you added rules with --permanent, ensure you reloaded:
sudo firewall-cmd --reload
Verify the rule is in the correct zone. Check which zone your interface uses:
firewall-cmd --get-active-zones
Then verify the rule exists in that zone:
firewall-cmd --zone=public --list-all
Firewalld and Docker
Docker manages its own iptables/nftables rules independently of Firewalld. With Firewalld’s nftables backend, both systems operate in separate namespaces and can coexist. However, Docker container ports published with -p flags bypass Firewalld zone rules because Docker inserts its NAT rules at a higher netfilter priority.
This means a container with -p 8080:80 is accessible from external networks regardless of your Firewalld configuration. To control Docker container access, either:
- Bind published ports to localhost only (
-p 127.0.0.1:8080:80) and use a reverse proxy with Firewalld rules - Use Docker networks and manage inter-container communication through Docker’s own networking
- Configure Docker to integrate with Firewalld by adding
{ "iptables": false }to/etc/docker/daemon.jsonand manually managing container network rules
IPv6 Connectivity Issues
Firewalld implements an IPv6 reverse path filter that verifies incoming packets have a valid return route. On systems with multiple interfaces connected to the same network (such as laptops with both wired and wireless active), this strict filtering can cause intermittent IPv6 connectivity. Symptoms include random connection timeouts, one interface working while another fails, or IPv6 connections succeeding inconsistently.
If you experience these issues, change the reverse path filter to loose mode, which only checks that a return path exists without validating the specific interface:
sudo nano /etc/firewalld/firewalld.conf
Find and change:
IPv6_rpfilter=loose
Restart Firewalld to apply the change:
sudo systemctl restart firewalld.service
Remove Firewalld from Arch Linux
Remove Firewalld only when switching to a different firewall solution. Disabling the service with sudo systemctl disable --now firewalld.service is sufficient for temporary deactivation.
Stop and disable the service:
sudo systemctl disable --now firewalld.service
Remove the Firewalld package and orphaned dependencies:
sudo pacman -Rns firewalld
Verify removal:
firewall-cmd --version
Expected output:
-bash: firewall-cmd: command not found
Custom configuration files in /etc/firewalld/ may remain as .pacsave backups. Remove them if no longer needed:
The following command permanently deletes all Firewalld configuration files. Only run this if you are certain you no longer need any custom zones, services, or rules.
sudo rm -rf /etc/firewalld/
After removing Firewalld, your system has no active firewall. Configure an alternative solution like UFW or direct nftables rules before exposing the system to untrusted networks.
Frequently Asked Questions
Firewalld uses zones to group rules by trust level, making it ideal for systems with multiple network interfaces that need different security policies. UFW uses a simpler flat rule model better suited for single-interface servers. Firewalld also supports runtime changes without reload and has built-in service definitions for hundreds of applications.
When you add rules with --permanent, Firewalld saves them to configuration files but does not apply them to the running firewall. Run firewall-cmd --reload after making permanent changes to apply them. Alternatively, add rules without --permanent to test, then use firewall-cmd --runtime-to-permanent to save working rules.
Firewalld uses nftables as its backend on Arch Linux. It creates rules in a dedicated firewalld table within nftables, allowing other applications like Docker or libvirt to maintain their own firewall rules in separate namespaces without conflicts.
If you still have console access, run sudo firewall-cmd --add-service=ssh and sudo firewall-cmd --runtime-to-permanent to restore SSH access. The default public zone includes SSH by default, so resetting to defaults with sudo firewall-cmd --reset-to-defaults also restores SSH access.
No. Running multiple firewall managers creates conflicting rules and unpredictable behavior. Disable and stop one firewall service completely before enabling another. Use either Firewalld or UFW, not both.
Conclusion
Firewalld now protects your Arch Linux system with zone-based security policies, service rules, and logging for security monitoring. The zone model allows different security policies for different network interfaces, while the separation of runtime and permanent configuration enables safe testing before committing changes. As a next step, verify your configuration by running firewall-cmd --list-all after each change session to confirm the expected rules are active. For servers handling sensitive data or exposed to the internet, pair Firewalld with intrusion detection tools like fail2ban to automatically block IP addresses after repeated failed authentication attempts.