Arch Linux does not enable a firewall service by default, so installing Firewalld on Arch Linux is a practical way to add zone-based filtering without writing raw nftables rules by hand. The zone model works well on laptops, servers, and virtualization hosts because each interface or source network can carry a different trust level.
Firewalld is available from Arch’s Extra repository and uses nftables as the default backend. Runtime changes let you test access rules immediately, while permanent changes keep the rules after reloads and reboots.
Install Firewalld on Arch Linux
The official Arch firewalld package provides the daemon and command-line tools. Use Firewalld when you want zones, runtime testing, rich rules, and integration with tools such as NetworkManager. Use UFW on Arch Linux instead when you prefer a simpler flat rule model for a single-interface host.
Update Arch Linux Before Installing Firewalld
Refresh package databases and apply pending system updates before installing a firewall service:
sudo pacman -Syu
These commands use
sudofor tasks that need root privileges. If your user is not in the sudoers file yet, run the commands as root or follow the guide on how to add and manage sudo users on Arch Linux.
Install Firewalld with Pacman
Install Firewalld from the official repository:
sudo pacman -S firewalld
Verify the Firewalld Package and Command
Confirm the package is installed and that firewall-cmd is the command provided by the Arch package:
pacman -Q firewalld
command -v firewall-cmd
pacman -Qo /usr/bin/firewall-cmd
Relevant output includes the installed package, command path, and owning package. The exact package release changes as Arch rolls forward:
firewalld 2.4.1-1 /usr/bin/firewall-cmd /usr/bin/firewall-cmd is owned by firewalld 2.4.1-1
The package installs firewall-cmd for live management and firewall-offline-cmd for offline configuration. The graphical tool is packaged separately as firewall-config and has its own install step.
The management commands use sudo firewall-cmd for both rule changes and daemon queries. Minimal Arch installs may not run a polkit agent, and unprivileged D-Bus queries can return authorization errors even when the daemon is healthy.
Enable and Start Firewalld on Arch Linux
Enable the Firewalld service to start automatically at boot and start it immediately:
sudo systemctl enable --now firewalld.service
Verify the service is enabled for boot and active now:
systemctl is-enabled firewalld.service
systemctl is-active firewalld.service
sudo firewall-cmd --state
A working service returns:
enabled active running
Do not run Firewalld at the same time as UFW or a separate hand-managed
iptables.serviceornftables.service. Pick one firewall manager so rule ownership stays predictable.
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. The Arch Wiki Firewalld page is the best upstream reference for Arch-specific notes beyond this workflow.
List all available zones:
sudo 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:
sudo 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:
sudo firewall-cmd --list-all
Example output for a host using the default public zone looks similar to this:
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 interface name depends on your system, but the default public zone includes the ssh and dhcpv6-client services. This means inbound SSH is already permitted in the default zone, which helps prevent lockouts when enabling the firewall on remote servers.
To view active zones and their assigned interfaces:
sudo firewall-cmd --get-active-zones
To view settings for a specific zone:
sudo firewall-cmd --info-zone=home
To list all zones with their complete configuration:
sudo 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:
sudo 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:
sudo 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. This example removes the http service added earlier:
sudo firewall-cmd --permanent --remove-service=http
sudo firewall-cmd --reload
Verify the service was removed:
sudo firewall-cmd --list-services
If http no longer appears in the service list, the rule has been removed from the active zone.
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:
sudo firewall-cmd --list-ports
After opening 8080/tcp and 51820/udp, the list should include both entries:
8080/tcp 51820/udp
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. Check your real interface names before copying interface examples:
ip -brief link
Use the interface names from your own output in the following commands.
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:
sudo 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:
sudo 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:
sudo 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:
sudo 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 sudo firewall-cmd --list-forward-ports and copy the complete rule.
Manage Runtime and Permanent Configuration
Firewalld maintains two configuration states: runtime, which is active immediately but temporary, and permanent, which is saved for reloads and reboots. The official firewall-cmd documentation uses this split throughout the command interface, so treat runtime changes as your test area.
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 its default configuration and remove custom zones, services, and rules:
sudo firewall-cmd --reset-to-defaults
Using
--reset-to-defaultsremoves customizations, including any SSH rule you changed manually. If connected remotely, keep a console or provider recovery session available 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 --check-config
sudo firewall-cmd --reload
The config check should return:
success
Verify the service is available:
sudo 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:
sudo 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:
sudo journalctl -k | grep -Ei 'reject|drop'
Monitor denied packets in real-time:
sudo journalctl -kf | grep -Ei 'reject|drop'
Enable denied packet logging only temporarily for troubleshooting. Heavy traffic to blocked ports can generate excessive log entries and fill disk space.
Install the Firewalld Graphical Interface
Desktop users can install firewall-config, the separate Arch package that provides the graphical Firewalld interface:
sudo pacman -S firewall-config
Launch the graphical configuration tool from a desktop session:
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 service errors:
sudo journalctl -xeu firewalld.service
Check whether another firewall service is active before disabling anything:
systemctl is-active iptables.service nftables.service ufw.service
If one of those services returns active, disable that specific firewall manager before starting Firewalld. For example, if nftables.service is active:
sudo systemctl disable --now nftables.service
sudo systemctl restart firewalld.service
If the journal points to a bad Firewalld XML file, check the saved configuration before resetting it:
sudo firewall-cmd --check-config
A clean configuration returns:
success
Rules Not Taking Effect
If rules are not working, verify the firewall is running:
sudo 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:
sudo firewall-cmd --get-active-zones
Then verify the rule exists in that zone:
sudo firewall-cmd --zone=public --list-all
SSH Access Was Blocked
If an SSH rule change blocks remote access, use a local console, hypervisor console, or provider rescue session first. Once you have console access, restore SSH in the active zone and save the working runtime rule:
sudo firewall-cmd --add-service=ssh
sudo firewall-cmd --runtime-to-permanent
sudo firewall-cmd --list-services
The service list should include ssh again:
dhcpv6-client ssh
If OpenSSH itself is missing or stopped, use the separate guide to install OpenSSH on Arch Linux before depending on remote access.
Firewalld and Docker
Docker manages its own packet-filtering rules when it publishes container ports. On a host that also runs Firewalld, a container published with -p 8080:80 can be reachable through Docker’s rules even when the equivalent Firewalld zone does not allow that port.
Use one of these safer patterns when Docker and Firewalld share the same Arch host:
- Bind published ports to localhost only (
-p 127.0.0.1:8080:80) and expose the service through a reverse proxy controlled by Firewalld rules. - Keep container-to-container traffic on Docker networks and expose only the host ports that should be public.
- Review Firewalld’s upstream Docker filtering guidance before changing Docker’s iptables behavior, because disabling Docker-managed rules without replacement policies can break container networking.
If you are still setting up the container runtime, the separate guide to install Docker on Arch Linux covers the package and service side.
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 the IPv6_rpfilter line and set it to loose mode:
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 enough 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
If you installed the graphical interface too, remove both packages together so Pacman can resolve the dependency relationship cleanly:
sudo pacman -Rns firewalld firewall-config
Verify removal with Pacman’s installed-package database:
pacman -Q firewalld || echo "firewalld is not installed"
A removed package returns:
error: package 'firewalld' was not found firewalld is not installed
Pacman removes package-owned files, but custom zones, services, and policies that you created under /etc/firewalld/ can remain. Remove them only if you no longer need that saved firewall policy:
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 may have no active firewall manager. Configure an alternative solution such as UFW on Arch Linux or a direct nftables ruleset before exposing the system to untrusted networks.
Conclusion
Firewalld is running on Arch Linux with zone-based rules you can test at runtime, save permanently, and inspect with sudo firewall-cmd --list-all. For exposed servers, pair the firewall with Fail2ban on Arch Linux, or use Nmap on Arch Linux from another host to verify which ports are reachable.


Formatting tips for your comment
You can use basic HTML to format your comment. Useful tags currently allowed in published comments:
<code>command</code>command<strong>bold</strong><em>italic</em><a href="https://example.com">link</a><blockquote>quote</blockquote>