
Firewalld is a dynamic firewall management tool available on many modern Linux distributions. On modern systems (including CentOS Stream 10), firewalld typically programs rules using the nftables packet filtering framework under the hood, while iptables is a different (lower-level) interface for managing Netfilter rules directly.
In this guide, you will install and enable firewalld, inspect the default zone configuration, and learn how to safely open access for common services and custom ports using firewall-cmd. You will also learn how zones work in practice, how runtime rules differ from permanent rules, and how to avoid accidentally locking yourself out of a remote server over SSH while making changes. Finally, you will create custom services and zones for more tailored policies, and walk through common troubleshooting steps and FAQs.
Note: There is a chance that you may be working with a newer version of firewalld than was available at the time of this writing, or that your server was set up slightly differently than the example server used throughout this guide. The behavior of some of the commands explained in this guide may vary depending on your specific configuration.
Key Takeaways:
--permanent flag only affect the runtime configuration, meaning they will be lost when the firewall service restarts unless they are explicitly saved as permanent rules.Firewalld is installed and enabled by default on most CentOS Stream 10 systems. If it is not installed, you can install it using the dnf package manager:
- sudo dnf install firewalld
After installing firewalld, you can enable the service and reboot the server. Keep in mind that enabling firewalld will cause the service to start up at boot. It is best practice to create firewall rules and take the opportunity to test them before configuring this behavior in order to avoid potential issues.
- sudo systemctl enable --now firewalld
When the server restarts, your firewall should be brought up, your network interfaces should be put into the zones you configured (or fall back to the configured default zone), and any rules associated with the zone(s) will be applied to the associated interfaces.
You can verify that the service is running and reachable by typing:
- sudo firewall-cmd --state
Outputrunning
This indicates that your firewall is up and running with the default configuration.
Firewalld is a firewall management solution available for many Linux distributions that provides a dynamic interface for managing firewall rules. It simplifies firewall configuration by allowing administrators to define rules using zones, services, and ports. Firewalld manages firewall rules dynamically and applies them using the nftables framework in modern Linux systems.
Before we begin talking about how to actually use the firewall-cmd utility to manage your firewall configuration, you should get familiar with a few basic concepts that the tool introduces.
firewalld and iptables are related, but they operate at different layers.
firewalld is a firewall management service/daemon. You express policy using zones, services (like ssh/http), ports, and rich rules, and it translates that policy into kernel firewall rules for you. This is typically easier to audit and maintain because you work in terms of intent (“allow SSH” rather than raw packet-matching rules.iptables is a low-level rule interface for the kernel’s Netfilter firewall. You manage tables and chains directly (for example, adding rules to INPUT/OUTPUT/FORWARD), and rule order matters for what gets accepted, rejected, or dropped.On CentOS Stream 10, firewalld typically programs nftables under the hood. The iptables command may still be present, but it is commonly a compatibility frontend (often iptables-nft) rather than the primary way the system expects you to manage firewall policy. For troubleshooting, you can inspect the effective policy with firewall-cmd --list-all (zone/policy view) and the generated nftables rules with nft list ruleset (low-level view).
| Topic | firewalld | iptables |
|---|---|---|
| What you manage | Policy objects (zones/services/ports/rich rules) | Explicit ordered rules (tables/chains) |
| Backend on CentOS Stream 10 | nftables (via firewalld) | Often compatibility tooling; not the preferred policy interface |
| Persistence | Separate runtime vs permanent configs + reload | Depends on distro tooling/workflow to save/restore rules |
| Auditing | firewall-cmd --list-all, zone-scoped views |
iptables -S / iptables-save style rule dumps |
Important: Avoid mixing managers. If firewalld is enabled, use firewall-cmd and firewalld config files as the source of truth; direct iptables changes can be overwritten on reload and make behavior harder to predict.
The firewalld daemon manages groups of rules using entities called “zones”. Zones are basically sets of rules dictating what traffic should be allowed depending on the level of trust you have in the networks your computer is connected to. Network interfaces are assigned a zone to dictate the behavior that the firewall should allow.
For computers that might move between networks frequently (like laptops), this kind of flexibility provides a good method of changing your rules depending on your environment. You may have strict rules in place prohibiting most traffic when operating on a public WiFi network, while allowing more relaxed restrictions when connected to your home network. For a server, these zones are not as immediately important because the network environment rarely, if ever, changes.
Regardless of how dynamic your network environment may be, it is still useful to be familiar with the general idea behind each of the predefined zones for firewalld. In order from least trusted to most trusted, the predefined zones within firewalld are:
icmp-host-prohibited or icmp6-adm-prohibited message.To use the firewall, you can create rules and alter the properties of your zones and then assign your network interfaces to whichever zones are most appropriate.
In firewalld, zones represent different levels of trust assigned to network connections. Each zone contains a predefined set of firewall rules that determine which network traffic is allowed or blocked. These rules define which services, ports, protocols, and forwarding behaviors are permitted for network interfaces associated with that zone.
When firewalld is running, every network interface is assigned to a zone. The firewall rules associated with that zone are then applied to all traffic entering or leaving that interface. This design allows administrators to apply different firewall policies depending on the trust level of the network environment.
For example, a server connected directly to the public internet should generally allow only a minimal number of services. In contrast, a server located inside a trusted internal network may safely expose additional services.
Firewalld provides several predefined zones, each designed for a specific level of trust or network environment.
The following table describes some commonly used zones and their typical use cases:
| Zone | Typical Use Case |
|---|---|
| public | Default zone for servers connected to untrusted networks such as the internet |
| home | Trusted home networks where more services may be permitted |
| work | Office or corporate networks where systems are moderately trusted |
| dmz | Servers that must be accessible from the internet but isolated from internal networks |
| trusted | Fully trusted networks where nearly all traffic is allowed |
Administrators can assign network interfaces to zones manually or allow firewalld to assign them automatically to the default zone.
Most cloud servers are directly connected to the internet and therefore typically use the public zone. In this configuration, the firewall should expose only essential services such as SSH, which is used for remote administration.
You can check which services are currently allowed in the public zone by running the following command:
- sudo firewall-cmd --zone=public --list-services
Outputcockpit dhcpv6-client ssh
This output indicates that the server allows SSH connections for remote management and basic networking services required for system operation.
If the server is running a web application or website, HTTP and HTTPS traffic must be permitted through the firewall.
You can allow HTTP traffic by running the following command:
- sudo firewall-cmd --zone=public --add-service=http
To allow secure HTTPS traffic, run:
- sudo firewall-cmd --zone=public --add-service=https
After adding these services, you can verify that they were successfully added by running:
- sudo firewall-cmd --zone=public --list-services
Outputcockpit dhcpv6-client http https ssh
This configuration allows incoming web traffic while still restricting access to other services.
Servers located within a trusted internal network environment often require additional services. For example, file sharing or service discovery may be enabled within a private network.
In these cases, the internal or work zones are often used. These zones typically allow additional services such as multicast DNS and file-sharing services.
You can inspect the services associated with the internal zone using the following command:
- sudo firewall-cmd --zone=internal --list-services
Outputdhcpv6-client mdns samba-client ssh
This output indicates that systems in this zone allow SSH access, network discovery services, and file-sharing services, which are commonly used in trusted internal environments.
By assigning appropriate zones to network interfaces and configuring the services allowed within each zone, administrators can create flexible and maintainable firewall policies that match the security requirements of different network environments.
Firewalld maintains two separate firewall configurations: a runtime configuration and a permanent configuration. Understanding the difference between these two configurations is essential for safely managing firewall rules.
The runtime configuration represents the active firewall rules currently enforced by the system. Any rule added without the --permanent flag immediately modifies the running firewall configuration.
However, runtime rules exist only in memory. If the firewalld service is restarted or the system reboots, these rules are discarded and the firewall returns to its permanent configuration.
The permanent configuration is stored on disk and defines the firewall rules that persist across system restarts. Changes made with the --permanent flag modify this stored configuration but do not immediately affect the running firewall.
Because of this separation, administrators typically follow a two-step workflow:
This approach reduces the risk of accidentally locking yourself out of a system.
The following command allows HTTP traffic in the currently running firewall configuration:
- sudo firewall-cmd --zone=public --add-service=http
You can verify that the rule has been applied by running:
- sudo firewall-cmd --zone=public --list-services
Outputcockpit dhcpv6-client http ssh
At this point, HTTP traffic is allowed. However, if the system is rebooted, this rule will be lost.
To make the rule persist across reboots, add it to the permanent configuration using the --permanent flag:
- sudo firewall-cmd --zone=public --permanent --add-service=http
Permanent configuration changes require a firewall reload before they take effect in the runtime environment.
Reload the firewall using the following command:
- sudo firewall-cmd --reload
After reloading, verify that the rule is still present:
- sudo firewall-cmd --zone=public --list-services
Outputcockpit dhcpv6-client http ssh
Before you begin to make modifications, you should familiarize yourself with the default environment and rules provided by the daemon.
You can see which zone is currently selected as the default by typing:
- sudo firewall-cmd --get-default-zone
Outputpublic
Since you haven’t given firewalld any commands to deviate from the default zone, and none of your interfaces are configured to bind to another zone, that zone will also be the only “active” zone (the zone that is controlling the traffic for your interfaces). You can verify that by typing:
- sudo firewall-cmd --get-active-zones
Outputpublic
interfaces: eth0 eth1
Here, you can see that the example server has two network interfaces being controlled by the firewall (eth0 and eth1). They are both currently being managed according to the rules defined for the public zone.
How do you know what rules are associated with the public zone? You can print out the default zone’s configuration by typing:
- sudo firewall-cmd --list-all
Outputpublic (default, active)
target: default
ingress-priority: 0
egress-priority: 0
icmp-block-inversion: no
interfaces: eth0 eth1
sources:
services: cockpit dhcpv6-client ssh
ports:
protocols:
forward: yes
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
You can tell from the output that this zone is both the default and active and that the eth0 and eth1 interfaces are associated with this zone (as you saw in the previous output). However, you can also see that this zone allows for the normal operations associated with a DHCP client (for IP address assignment) and SSH (for remote administration).
Now you have a good idea about the configuration for the default and active zone. You can find out information about other zones as well.
To get a list of the available zones, type:
- sudo firewall-cmd --get-zones
Outputblock dmz drop external home internal public trusted work
You can see the specific configuration associated with a zone by including the --zone= parameter in your --list-all command:
- sudo firewall-cmd --zone=home --list-all
Outputhome
target: default
ingress-priority: 0
egress-priority: 0
icmp-block-inversion: no
interfaces:
sources:
services: cockpit dhcpv6-client mdns samba-client ssh
ports:
protocols:
forward: yes
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
You can output all of the zone definitions by using the --list-all-zones option. You will probably want to pipe the output into a pager for easier viewing:
- sudo firewall-cmd --list-all-zones | less
Unless you have configured your network interfaces otherwise, each interface will be put in the default zone when the firewall is booted.
You can transition an interface between zones during a session by using the --zone= parameter in combination with the --change-interface= parameter. As with all commands that modify the firewall, you will need to use sudo.
For instance, you can transition your eth0 interface to the “home” zone by typing this:
- sudo firewall-cmd --zone=home --change-interface=eth0
Outputsuccess
Note: Whenever you are transitioning an interface to a new zone, be aware that you are probably modifying the services that will be operational. For instance, in this example you are moving to the “home” zone, which has SSH available. This means that your connection shouldn’t drop. Some other zones do not have SSH enabled by default and if your connection is dropped while using one of these zones, you could find yourself unable to log back in.
You can verify that this was successful by asking for the active zones again:
- sudo firewall-cmd --get-active-zones
Outputhome
interfaces: eth0
public
interfaces: eth1
If all of your interfaces can best be handled by a single zone, it’s probably easier to select the best default zone and then use that for your configuration.
You can change the default zone with the --set-default-zone= parameter. This will immediately change any interface that had fallen back on the default to the new zone:
- sudo firewall-cmd --set-default-zone=home
Outputsuccess
The basic way of defining firewall exceptions for the services you wish to make available is fairly straightforward. This section walks through the basic idea.
The simplest method is to add the services or ports you need to the zones you are using. Again, you can get a list of the available services with the --get-services option:
- sudo firewall-cmd --get-services
OutputRH-Satellite-6 amanda-client amanda-k5-client bacula bacula-client bitcoin bitcoin-rpc bitcoin-testnet bitcoin-testnet-rpc ceph ceph-mon cfengine condor-collector ctdb dhcp dhcpv6 dhcpv6-client dns docker-registry dropbox-lansync elasticsearch freeipa-ldap freeipa-ldaps freeipa-replication freeipa-trust ftp ganglia-client ganglia-master high-availability http https imap imaps ipp ipp-client ipsec iscsi-target kadmin kerberos kibana klogin kpasswd kshell ldap ldaps libvirt libvirt-tls managesieve mdns mosh mountd ms-wbt mssql mysql nfs nrpe ntp openvpn ovirt-imageio ovirt-storageconsole ovirt-vmconsole pmcd pmproxy pmwebapi pmwebapis pop3 pop3s postgresql privoxy proxy-dhcp ptp pulseaudio puppetmaster quassel radius rpc-bind rsh rsyncd samba samba-client sane sip sips smtp smtp-submission smtps snmp snmptrap spideroak-lansync squid ssh synergy syslog syslog-tls telnet tftp tftp-client tinc tor-socks transmission-client vdsm vnc-server wbem-https xmpp-bosh xmpp-client xmpp-local xmpp-server
Note: You can get more details about each of these services by looking at their associated .xml file within the /usr/lib/firewalld/services directory. For instance, the SSH service is defined like this:
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>SSH</short>
<description>Secure Shell (SSH) is a protocol for logging into and executing commands on remote machines. It provides secure encrypted communications. If you plan on accessing your machine remotely via SSH over a firewalled interface, enable this option. You need the openssh-server package installed for this option to be useful.</description>
<port protocol="tcp" port="22"/>
</service>
You can enable a service for a zone using the --add-service= parameter. The operation will target the default zone or whatever zone is specified by the --zone= parameter. By default, this will only adjust the current firewall session. You can adjust the permanent firewall configuration by including the --permanent flag.
For instance, if you are running a web server serving conventional HTTP traffic, you can allow this traffic for interfaces in your “public” zone for this session by typing:
- sudo firewall-cmd --zone=public --add-service=http
You can leave out the --zone= if you wish to modify the default zone. You can verify the operation was successful by using the --list-all or --list-services operations:
- sudo firewall-cmd --zone=public --list-services
Outputcockpit dhcpv6-client http ssh
Once you have tested that everything is working as it should, you will probably want to modify the permanent firewall rules so that your service will still be available after a reboot. You can make your “public” zone change permanent by typing:
- sudo firewall-cmd --zone=public --permanent --add-service=http
Outputsuccess
You can verify that this was successful by adding the --permanent flag to the --list-services operation. You need to use sudo for any --permanent operations:
- sudo firewall-cmd --zone=public --permanent --list-services
Outputcockpit dhcpv6-client http ssh
Your “public” zone will now allow HTTP web traffic on port 80. If your web server is configured to use SSL/TLS, you’ll also want to add the https service. You can add that to the current session and the permanent rule-set by typing:
- sudo firewall-cmd --zone=public --add-service=https
- sudo firewall-cmd --zone=public --permanent --add-service=https
The firewall services that are included with the firewalld installation represent many of the most common requirements for applications that you may wish to allow access to. However, there will likely be scenarios where these services do not fit your requirements.
In this situation, you have two options.
One way to add support for your specific application is to open up the ports that it uses in the appropriate zone(s). This is done by specifying the port or port range, and the associated protocol for the ports you need to open.
For instance, if your application runs on port 5000 and uses TCP, you can add this to the “public” zone for this session using the --add-port= parameter. Protocols can be either tcp or udp:
- sudo firewall-cmd --zone=public --add-port=5000/tcp
Outputsuccess
You can verify that this was successful using the --list-ports operation:
- sudo firewall-cmd --zone=public --list-ports
Output5000/tcp
It is also possible to specify a sequential range of ports by separating the beginning and ending port in the range with a dash. For instance, if your application uses UDP ports 4990 to 4999, you can open these up on “public” by typing:
- sudo firewall-cmd --zone=public --add-port=4990-4999/udp
After testing, you will likely want to add these to the permanent firewall. You can do that by typing:
- sudo firewall-cmd --zone=public --permanent --add-port=5000/tcp
- sudo firewall-cmd --zone=public --permanent --add-port=4990-4999/udp
- sudo firewall-cmd --zone=public --permanent --list-ports
Outputsuccess
success
5000/tcp 4990-4999/udp
Opening ports for your zones is easy, but it can be difficult to keep track of what each one is for. If you ever decommission a service on your server, you may have a hard time remembering which ports that have been opened are still required. To avoid this situation, it is possible to define a service.
Services are collections of ports with an associated name and description. Using services is easier to administer than ports, but requires a bit of upfront work. A good way to start is to copy an existing script (found in /usr/lib/firewalld/services) to the /etc/firewalld/services directory where the firewall looks for non-standard definitions.
For instance, you can copy the SSH service definition to use for your “example” service definition like this. The filename minus the .xml suffix will dictate the name of the service within the firewall services list:
- sudo cp /usr/lib/firewalld/services/ssh.xml /etc/firewalld/services/example.xml
Now, you can adjust the definition found in the file you copied:
- sudo vi /etc/firewalld/services/example.xml
To start, the file will contain the SSH definition that you copied:
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>SSH</short>
<description>Secure Shell (SSH) is a protocol for logging into and executing commands on remote machines. It provides secure encrypted communications. If you plan on accessing your machine remotely via SSH over a firewalled interface, enable this option. You need the openssh-server package installed for this option to be useful.</description>
<port protocol="tcp" port="22"/>
</service>
The majority of this definition is actually metadata. You will want to change the short name for the service within the <short> tags. This is a human-readable name for your service. You should also add a description so that you have more information if you ever need to audit the service. The only configuration you need to make that actually affects the functionality of the service will likely be the port definition where you identify the port number and protocol you wish to open. This can be specified multiple times.
For your “example” service, imagine that you need to open up port 7777 for TCP and 8888 for UDP. By entering INSERT mode by pressing i, you can modify the existing definition with something like this:
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>Example Service</short>
<description>This is just an example service. It probably shouldn't be used on a real system.</description>
<port protocol="tcp" port="7777"/>
<port protocol="udp" port="8888"/>
</service>
Press ESC, then enter :x to save and close the file.
Reload your firewall to get access to your new service:
- sudo firewall-cmd --reload
You can see that it is now among the list of available services:
- sudo firewall-cmd --get-services
OutputRH-Satellite-6 amanda-client amanda-k5-client bacula bacula-client bitcoin bitcoin-rpc bitcoin-testnet bitcoin-testnet-rpc ceph ceph-mon cfengine condor-collector ctdb dhcp dhcpv6 dhcpv6-client dns docker-registry dropbox-lansync elasticsearch example freeipa-ldap freeipa-ldaps freeipa-replication freeipa-trust ftp ganglia-client ganglia-master high-availability http https imap imaps ipp ipp-client ipsec iscsi-target kadmin kerberos kibana klogin kpasswd kshell ldap ldaps libvirt libvirt-tls managesieve mdns mosh mountd ms-wbt mssql mysql nfs nrpe ntp openvpn ovirt-imageio ovirt-storageconsole ovirt-vmconsole pmcd pmproxy pmwebapi pmwebapis pop3 pop3s postgresql privoxy proxy-dhcp ptp pulseaudio puppetmaster quassel radius rpc-bind rsh rsyncd samba samba-client sane sip sips smtp smtp-submission smtps snmp snmptrap spideroak-lansync squid ssh synergy syslog syslog-tls telnet tftp tftp-client tinc tor-socks transmission-client vdsm vnc-server wbem-https xmpp-bosh xmpp-client xmpp-local xmpp-server
You can now use this service in your zones as you normally would.
While the predefined zones will probably be more than enough for most users, it can be helpful to define your own zones that are more descriptive of their function.
For instance, you might want to create a zone for your web server, called “publicweb”. However, you might want to have another zone configured for the DNS service you provide on your private network. You might want a zone called “privateDNS” for that.
When adding a zone, you must add it to the permanent firewall configuration. You can then reload to bring the configuration into the running session. For instance, you can create the two zones described above by typing:
- sudo firewall-cmd --permanent --new-zone=publicweb
- sudo firewall-cmd --permanent --new-zone=privateDNS
You can verify that these are present in the permanent configuration by typing:
- sudo firewall-cmd --permanent --get-zones
Outputblock dmz drop external home internal privateDNS public publicweb trusted work
As stated before, these won’t be available in the current instance of the firewall yet:
- sudo firewall-cmd --get-zones
Outputblock dmz drop external home internal public trusted work
Reload the firewall to bring these new zones into the active configuration:
- sudo firewall-cmd --reload
- sudo firewall-cmd --get-zones
Outputblock dmz drop external home internal privateDNS public publicweb trusted work
Now, you can begin assigning the appropriate services and ports to your zones. It’s usually a good idea to adjust the active instance and then transfer those changes to the permanent configuration after testing. For instance, for the “publicweb” zone, you might want to add the SSH, HTTP, and HTTPS services:
- sudo firewall-cmd --zone=publicweb --add-service=ssh
- sudo firewall-cmd --zone=publicweb --add-service=http
- sudo firewall-cmd --zone=publicweb --add-service=https
- sudo firewall-cmd --zone=publicweb --list-all
Outputpublicweb
target: default
ingress-priority: 0
egress-priority: 0
icmp-block-inversion: no
interfaces:
sources:
services: http https ssh
ports:
protocols:
forward: no
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
Likewise, you can add the DNS service to your “privateDNS” zone:
- sudo firewall-cmd --zone=privateDNS --add-service=dns
- sudo firewall-cmd --zone=privateDNS --list-all
OutputprivateDNS
ingress-priority: 0
egress-priority: 0
icmp-block-inversion: no
interfaces:
sources:
services: dns
ports:
protocols:
forward: no
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
You can then change your interfaces over to these new zones to test them out:
- sudo firewall-cmd --zone=publicweb --change-interface=eth0
- sudo firewall-cmd --zone=privateDNS --change-interface=eth1
At this point, you have the opportunity to test the configuration. If these values work for you, you will want to add the same rules to the permanent configuration. You can do that by re-applying the rules with the --permanent flag:
- sudo firewall-cmd --zone=publicweb --permanent --add-service=ssh
- sudo firewall-cmd --zone=publicweb --permanent --add-service=http
- sudo firewall-cmd --zone=publicweb --permanent --add-service=https
- sudo firewall-cmd --zone=privateDNS --permanent --add-service=dns
After permanently applying these rules, you can restart the network and reload the firewall service:
- sudo systemctl restart NetworkManager
- sudo systemctl reload firewalld
Validate that the correct zones were assigned:
- sudo firewall-cmd --get-active-zones
OutputprivateDNS
interfaces: eth1
publicweb
interfaces: eth0
And validate that the appropriate services are available for both of the zones:
- sudo firewall-cmd --zone=publicweb --list-services
Outputhttp https ssh
- sudo firewall-cmd --zone=privateDNS --list-services
Outputdns
You have successfully set up your own zones! If you want to make one of these zones the default for other interfaces, remember to configure that behavior with the --set-default-zone= parameter:
- sudo firewall-cmd --set-default-zone=publicweb
When working with firewalld, you may occasionally encounter issues such as blocked connections, rules not applying correctly, or configuration changes not persisting after a reboot. Understanding the most common problems and how to diagnose them can help you quickly restore network connectivity and maintain a secure firewall configuration.
One common issue occurs when a firewall rule is added with the --permanent flag but does not immediately affect network traffic. This happens because permanent rules are stored in the configuration files but are not applied to the running firewall until the firewall configuration is reloaded.
For example, you might run the following command:
- sudo firewall-cmd --zone=public --permanent --add-service=http
Although this command successfully updates the permanent configuration, the rule will not affect the active firewall until you reload the configuration:
- sudo firewall-cmd --reload
If a newly added rule does not appear to work, verify that the firewall has been reloaded after modifying permanent rules.
Another common problem occurs when a service or port appears to be blocked even after it has been allowed through the firewall. This may happen if the rule was applied to the wrong firewall zone.
First, check which zone your network interface is currently using:
- sudo firewall-cmd --get-active-zones
Outputpublic
interfaces: eth0
If the rule was added to a different zone than the one assigned to your interface, it will not affect the traffic for that interface. In this situation, either add the rule to the correct zone or change the interface assignment.
You can inspect the rules for a specific zone using:
- sudo firewall-cmd --zone=public --list-all
This command shows all services, ports, and policies currently applied to the zone.
A common mistake when modifying firewall rules on a remote server is accidentally blocking SSH access. If SSH is not allowed in the firewall zone associated with your network interface, your remote connection may be terminated when the firewall is reloaded.
To avoid this situation, always confirm that SSH access is permitted before applying firewall changes:
- sudo firewall-cmd --zone=public --query-service=ssh
Outputyes
If the output returns no, allow SSH access before continuing:
- sudo firewall-cmd --zone=public --add-service=ssh
Once you confirm that the rule works correctly, make it permanent:
- sudo firewall-cmd --zone=public --permanent --add-service=ssh
- sudo firewall-cmd --reload
Keeping a second SSH session open while modifying firewall rules can also help prevent accidental lockouts.
If firewall commands return unexpected results or appear to have no effect, the firewalld service may not be running.
You can verify the firewall service status using the following command:
- sudo firewall-cmd --state
Outputrunning
If the firewall service is not running, start it using:
- sudo systemctl start firewalld
To ensure the firewall starts automatically when the system boots, enable the service:
- sudo systemctl enable firewalld
Firewalld should generally be the primary tool used to manage firewall rules on systems where it is installed and running. Using other firewall tools, such as direct iptables commands, may create conflicts because firewalld dynamically manages the underlying firewall configuration.
If manual iptables rules are added while firewalld is running, they may be overwritten when firewalld reloads its configuration.
To inspect the current low-level firewall rules generated by firewalld, you can run:
- sudo nft list ruleset
This command displays the nftables rules that firewalld has created based on the configured zones and policies.
Another troubleshooting scenario occurs when the wrong protocol is specified when opening a port. For example, if an application expects TCP traffic but the firewall rule allows UDP traffic, the connection will fail even though the port appears open.
For example:
- sudo firewall-cmd --zone=public --add-port=5000/udp
If the application actually uses TCP, the correct rule should be:
- sudo firewall-cmd --zone=public --add-port=5000/tcp
Always confirm which protocol the application requires when configuring firewall rules.
After making firewall changes, it is a good practice to review the final configuration to ensure that the expected services and ports are allowed.
You can display the complete firewall configuration using:
- sudo firewall-cmd --list-all
This command provides a summary of the active zone configuration, including allowed services, open ports, and forwarding rules.
Regularly reviewing the firewall configuration helps ensure that only the necessary services remain accessible while maintaining a secure system.
firewalld is a dynamic firewall management service used on many Linux distributions, including CentOS. It provides a simplified way to manage firewall rules by organizing them into zones, services, ports, and rich rules. Instead of manually defining low-level packet filtering rules, administrators can specify higher-level policies that describe which types of network traffic should be allowed.
On modern CentOS systems such as CentOS Stream 10, firewalld uses the nftables framework as its underlying backend. The firewall-cmd command-line utility communicates with the running firewalld daemon, which then translates the configured policies into nftables rules that the Linux kernel enforces.
firewalld maintains two separate firewall configurations: a runtime configuration and a permanent configuration.
Runtime rules are applied immediately to the currently running firewall configuration. These rules remain active only while the firewall service is running and will be lost if the system is restarted or the firewalld service is reloaded.
Permanent rules are stored on disk and persist across system reboots. When a rule is added with the --permanent flag, it modifies the saved configuration rather than the active firewall. After modifying permanent rules, you must reload the firewall using sudo firewall-cmd --reload to apply the changes to the running configuration.
You can open a port using the --add-port option with the firewall-cmd command.
For example, to open TCP port 5000 in the default zone, run:
- sudo firewall-cmd --zone=public --add-port=5000/tcp
To make the rule persistent across system reboots, add the --permanent flag and then reload the firewall:
- sudo firewall-cmd --zone=public --permanent --add-port=5000/tcp
- sudo firewall-cmd --reload
This allows incoming connections to port 5000 on the specified zone.
firewalld includes predefined service definitions that represent commonly used network services such as SSH, HTTP, and HTTPS. Each service maps to the ports and protocols required for that service.
To allow a service, use the --add-service option. For example, to allow HTTP traffic:
- sudo firewall-cmd --zone=public --add-service=http
To make this rule permanent:
- sudo firewall-cmd --zone=public --permanent --add-service=http
- sudo firewall-cmd --reload
This approach is often preferred over opening ports directly because service definitions are easier to understand and maintain.
You can view the open ports for a specific zone using the --list-ports command.
For example:
- sudo firewall-cmd --zone=public --list-ports
Output5000/tcp 4990-4999/udp
You can also view all active services and ports for the current zone by running:
- sudo firewall-cmd --list-all
This command displays the full configuration of the active firewall zone, including allowed services, ports, and other rule settings.
To temporarily stop the firewall service, run:
- sudo systemctl stop firewalld
To disable firewalld so it does not start automatically at boot:
- sudo systemctl disable firewalld
If you want to reset the firewall configuration to its default state, you can remove custom rules from the configuration directory and reload the firewall:
- sudo firewall-cmd --complete-reload
Alternatively, you can remove specific rules or zones manually and reload the firewall service to apply the changes.
You should now have a fairly good understanding of how to administer the firewalld service on your CentOS system for day-to-day use.
The firewalld service allows you to configure maintainable rules and rule-sets that take into consideration your network environment. It allows you to seamlessly transition between different firewall policies through the use of zones and gives administrators the ability to abstract the port management into more friendly service definitions. Acquiring a working knowledge of this system will allow you to take advantage of the flexibility and power that this tool provides.
For more Linux-related tutorials, check out our following articles:
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
Former Senior Technical Writer at DigitalOcean, specializing in DevOps topics across multiple Linux distributions, including Ubuntu 18.04, 20.04, 22.04, as well as Debian 10 and 11.
With over 6 years of experience in tech publishing, Mani has edited and published more than 75 books covering a wide range of data science topics. Known for his strong attention to detail and technical knowledge, Mani specializes in creating clear, concise, and easy-to-understand content tailored for developers.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
All of the above works fine until reboot and I am locked out… Even with zero mods. ONLY; systemctl enable firewalld && reboot (on a pure droplet) … After that ssh (and all ports) is locked forever. Prior to rebooting I can test and everything works as expected
What could be the problem?
I liked too much the Changing the Zone of your Interface Permanently tip on editing the network interface configuration file. Because the permanent parameter isn’t working as should to. Thank you.
Hi,
So far this and other Digital Ocean’s posting about linux servers have be great - wonderfully clear instructions.
Just one small typo here though - under Turning on the Firewall
sudo systemctl start firwalld.service
should be
sudo systemctl start firewalld.service
Any reason why with firewalld I can’t add permanent rules to the public zone but If added without --permanent it adds?
Dear , Thanks for the tutorial. I am having some problem. I am using centos 6 as a vsftpd server and proxyserver. there are users from 30 places put files on my server. and with iptables it is running smoothly. I want to update with centos7 but the problem is that I am unable to converts iptables rules to firewalld rules for example iptables commands are below: -A INPUT -s 172.28.60.42/32 -p tcp -m tcp --dport 21 -j ACCEPT -A INPUT -s 172.28.60.45/32 -p tcp -m tcp --dport 21 -j ACCEPT -A INPUT -s xx.xx.xx.xx/32 -p tcp -m tcp --dport 21 -j ACCEPT
how to convert those to firewalld ?? I am not getting any clue. Could you please help ??
Thanking you, Ehsan
Dear Sir,
Thank you for your quick response. I was totally stuck with the thing thank you once again for helping me out . another question after putting those rules do i need to add any thing bellow accept .if no very good.
if yes then i used the following rules for denying all other sources at the end of the line “-A INPUT -p tcp -m tcp --dport 21 -j DROP”
What would be the rich rule syntax for denying all ??
if you kindly guide me… it would be very helpful for me.
Thanking you, Ehsan
Another excellent tutorial - I am grateful for your existence Justin Ellingwood! DO should promote you to oversee all tutorial creation from now on.
Hello, lovely tut! I am having some issues, however, when I type in the command:
sudo systemctl start firewalld
I receive the error:
sudo: systemctl: command not found
any ideas of what may be going on? Thanks!
Really great tutorial, I learned all I needed to get up and running with firewalld in about 5 or 10 minutes.
One minor detail: In “Defining a Service,” after creating a new service file, you write “Reload your firewall to get access to your new service.” I guess it depends on what you mean by “get access,” but a client would not be able to connect to the new service yet. You’d need to issue a # firewall-cmd --add-service <new-service> before the service would be accessible.
I know you describe --add-service before and after this section, so maybe you thought it didn’t need to be included here as well, or that it was obvious…which it probably is, but it took me a second.
Thanks again.
Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.
Full documentation for every DigitalOcean product.
The Wave has everything you need to know about building a business, from raising funding to marketing your product.
Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.
New accounts only. By submitting your email you agree to our Privacy Policy
Scale up as you grow — whether you're running one virtual machine or ten thousand.
Sign up and get $200 in credit for your first 60 days with DigitalOcean.*
*This promotional offer applies to new accounts only.