FirewallD is a dynamic firewall manager for Linux that lets you control network traffic with zones, services, and rich rules without disconnecting current sessions.
To use FirewallD on a Linux server, install it, enable the service, choose a default zone, allow required services or ports, then reload to persist rules across reboots. Learning how to use FirewallD on a Linux server is one of the fastest ways to improve your security posture.
In this beginner friendly guide, I’ll show you how to install, configure, and manage FirewallD using practical commands and real world examples, plus production ready best practices we use on managed servers at YouStable.
What is FirewallD (and why use it)?
FirewallD is a daemon that manages firewall rules dynamically via zones and services. Under the hood it uses nftables on modern distros (or iptables on older ones).
Unlike static firewall tools, FirewallD updates rules without dropping connections, integrates with system services via D-Bus, and offers granular “rich rules” for advanced control.
Prerequisites and Supported Linux Distributions
FirewallD is available on RHEL 8/9, CentOS Stream, AlmaLinux, Rocky Linux, Fedora, openSUSE, and Ubuntu/Debian.
You’ll need sudo or root access and SSH to your server. If you’re in a cloud (AWS, Azure, GCP), ensure your provider’s security groups or network ACLs also allow the same ports you open locally.
Install and Enable FirewallD
RHEL, CentOS Stream, AlmaLinux, Rocky, Fedora
sudo dnf install -y firewalld
# For CentOS 7 or very old systems: sudo yum install -y firewalld
sudo systemctl enable --now firewalld
sudo firewall-cmd --state # should print: running
Ubuntu and Debian
sudo apt update
sudo apt install -y firewalld
sudo systemctl enable --now firewalld
sudo firewall-cmd --state
Tip: If you used UFW before, disable it to avoid conflicts:
sudo ufw disable
sudo systemctl stop ufw
Understanding Zones and Services
Zones in FirewallD
Zones represent trust levels for network connections. You assign interfaces (eth0, ens3) or source IP ranges to zones, then allow services/ports in those zones. Common zones include: drop, block, public, external, internal, dmz, home, work, trusted. The default is usually “public” on servers.
sudo firewall-cmd --get-default-zone
sudo firewall-cmd --get-active-zones
sudo firewall-cmd --list-all --zone=public
FirewallD Services
Services are predefined rules (like http, https, ssh, dns) that include the required ports and protocols. They live in /usr/lib/firewalld/services/ (system-level) and /etc/firewalld/services/ (custom). Use them where possible instead of remembering port numbers.
sudo firewall-cmd --get-services
sudo firewall-cmd --info-service=http
FirewallD Commands You’ll Use Daily
FirewallD has two configurations: runtime (temporary) and permanent (persist after reboot). Add –permanent to save, then reload.
# Set the default zone
sudo firewall-cmd --set-default-zone=public
# Allow a service
sudo firewall-cmd --add-service=http --permanent
sudo firewall-cmd --reload
# Allow a port (single or range)
sudo firewall-cmd --add-port=8080/tcp --permanent
sudo firewall-cmd --add-port=30000-30100/tcp --permanent
sudo firewall-cmd --reload
# Remove access
sudo firewall-cmd --remove-service=http --permanent
sudo firewall-cmd --remove-port=8080/tcp --permanent
sudo firewall-cmd --reload
# List current rules
sudo firewall-cmd --list-all
A Secure-By-Default Setup (Step-by-Step)
- Confirm your SSH access works on the correct port and from your IP.
- Set the default zone to public and bind your interface to it.
- Allow only the minimum services needed (ssh, http/https, database if required).
- Enable logging for denied packets while testing.
- Reload and verify connectivity.
# Bind interface and restrict to minimal services
sudo firewall-cmd --zone=public --change-interface=eth0 --permanent
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
# (Optional) Log denied packets during audits
sudo firewall-cmd --set-log-denied=all
sudo firewall-cmd --reload
sudo firewall-cmd --list-all --zone=public
If SSH runs on a non-standard port, allow it explicitly and ensure SELinux allows that port (RHEL-family):
# Allow custom SSH port 2222
sudo firewall-cmd --add-port=2222/tcp --permanent
sudo firewall-cmd --reload
# SELinux context for custom SSH port (RHEL/Alma/Rocky)
sudo semanage port -a -t ssh_port_t -p tcp 2222
Managing Ports and Services
Common Allow Rules
# Web
sudo firewall-cmd --add-service=http --permanent
sudo firewall-cmd --add-service=https --permanent
# SSH
sudo firewall-cmd --add-service=ssh --permanent
# DNS, SMTP, MariaDB (use only if needed and secure access)
sudo firewall-cmd --add-service=dns --permanent
sudo firewall-cmd --add-service=smtp --permanent
sudo firewall-cmd --add-service=mysql --permanent
sudo firewall-cmd --reload
Port Ranges and Protocols
# TCP/UDP toggle
sudo firewall-cmd --add-port=1194/udp --permanent
# Port range (e.g., passive FTP or game servers)
sudo firewall-cmd --add-port=50000-50100/tcp --permanent
sudo firewall-cmd --reload
Removing Unnecessary Access
sudo firewall-cmd --remove-service=mysql --permanent
sudo firewall-cmd --remove-port=50000-50100/tcp --permanent
sudo firewall-cmd --reload
Granular Control with Rich Rules
Rich rules offer advanced matching, source restrictions, logging, and rate limiting. Use them to lock management ports to trusted IPs or subnets.
# Allow SSH only from a single IP
sudo firewall-cmd --add-rich-rule='rule family="ipv4" \
source address="203.0.113.10" service name="ssh" accept' --permanent
# Allow SSH from a subnet with rate limiting
sudo firewall-cmd --add-rich-rule='rule family="ipv4" \
source address="203.0.113.0/24" service name="ssh" \
limit value="15/m" accept' --permanent
# Log & drop everything else hitting SSH (example)
sudo firewall-cmd --add-rich-rule='rule family="ipv4" \
service name="ssh" log prefix="FW-SSH " level="info" limit value="5/m"' --permanent
sudo firewall-cmd --add-rich-rule='rule family="ipv4" \
service name="ssh" drop' --permanent
sudo firewall-cmd --reload
Zones for Multi-NIC or Multi-Tenant Servers
Assign Interfaces to Zones
# Public-facing NIC
sudo firewall-cmd --zone=public --change-interface=eth0 --permanent
# Internal/private NIC
sudo firewall-cmd --zone=internal --change-interface=eth1 --permanent
sudo firewall-cmd --reload
Source-Based Zones
# Treat a trusted office subnet as "trusted"
sudo firewall-cmd --zone=trusted --add-source=10.0.10.0/24 --permanent
sudo firewall-cmd --reload
With this model, your public zone can expose only web ports, while internal or trusted zones can allow SSH or database access from specific private ranges.
Masquerading, NAT, and Port Forwarding
For edge servers or gateways, you can NAT outbound traffic and forward ports internally using FirewallD.
# Enable NAT (masquerading) on the external zone
sudo firewall-cmd --zone=public --add-masquerade --permanent
# Forward external port 80 to local 8080
sudo firewall-cmd --zone=public \
--add-forward-port=port=80:proto=tcp:toport=8080 --permanent
# Forward 443 to an internal host
sudo firewall-cmd --zone=public \
--add-forward-port=port=443:proto=tcp:toaddr=10.0.0.10 --permanent
sudo firewall-cmd --reload
Ensure kernel IP forwarding is enabled for routing scenarios and review cloud provider firewall rules to avoid conflicts or double-NAT surprises.
IPv6 Considerations
FirewallD applies most rules to both IPv4 and IPv6 by default. If your server has AAAA DNS records or global IPv6 addresses, confirm your policies with tests over IPv6 and consider rich rules that include family=”ipv6″ when restricting sources.
Testing and Troubleshooting
# Validate configuration syntax
sudo firewall-cmd --check-config
# See zones and rules
sudo firewall-cmd --get-active-zones
sudo firewall-cmd --list-all --zone=public
# Save runtime rules to permanent
sudo firewall-cmd --runtime-to-permanent
# Inspect logs and denied packets
journalctl -u firewalld --since "1 hour ago"
sudo firewall-cmd --set-log-denied=all # during troubleshooting
# Cross-check with sockets and nftables
sudo ss -tulpen
sudo nft list ruleset
If you lose SSH access during testing, use your cloud/VPS console to revert changes or temporarily allow the necessary port and IP from the provider panel.
FirewallD vs. iptables vs. UFW
- FirewallD: Dynamic updates, zone-based model, service awareness, rich rules, integrates with system tools. Best for RHEL/Fedora families and multi-zone servers.
- iptables (legacy): Powerful but lower-level and static. Easy to lock yourself out; superseded by nftables on many distros.
- UFW: Simple allow/deny syntax on Ubuntu; great for single-zone setups, fewer advanced features than FirewallD’s rich rules/zones.
Production Best Practices
- Principle of least privilege: open only what you must.
- Restrict SSH with rich rules to known IPs; consider key-only auth and rate limits.
- Separate zones: public for web, internal/trusted for admin and database access.
- Document every rule; use configuration management (Ansible) to version policies.
- Avoid mixing manual nft rules with FirewallD; let one tool own the firewall.
- Test changes in runtime first; then commit to –permanent and reload.
- Enable denial logging during audits, then revert to reduce noise.
- Review cloud security groups and load balancers alongside local rules.
FAQ’s
Is FirewallD better than iptables for servers?
For most modern servers, yes. FirewallD offers dynamic updates, zone-based policies, and service definitions, reducing mistakes and downtime. It uses nftables by default on newer distros and keeps rules consistent across reboots with –permanent and reload mechanics.
How do I open a port in FirewallD?
Use add-port with protocol and make it permanent, then reload:sudo firewall-cmd --add-port=8080/tcp --permanent
sudo firewall-cmd --reload
What is the difference between runtime and permanent in FirewallD?
Runtime rules apply immediately but vanish on restart. Permanent rules persist across reboots but require reload to take effect. You can test changes at runtime first, then save with –runtime-to-permanent or re-run with –permanent and reload.
How do I allow a service only from one IP?
Use a rich rule targeting the service and source IP:sudo firewall-cmd --add-rich-rule='rule family="ipv4" \
source address="203.0.113.10" service name="ssh" accept' --permanent
sudo firewall-cmd --reload
Does FirewallD work with IPv6?
Yes. Most service and port rules apply to both IPv4 and IPv6 automatically. For strict controls, use rich rules with family=”ipv6″ and test connectivity over IPv6 to verify your policy behaves as expected.
Conclusion
Mastering FirewallD on Linux is straightforward once you understand zones, services, and the runtime/permanent workflow. Start minimal, test carefully, and layer rich rules for precision. If you prefer expert, hands off security hardening, YouStable’s managed hosting team can design and maintain a robust FirewallD policy tailored to your workloads.