Tools: How To Set Up a Firewall Using firewalld on CentOS

Tools: How To Set Up a Firewall Using firewalld on CentOS

Source: DigitalOcean

By Justin Ellingwood and Manikandan Kurup 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. 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: 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. 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: 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. 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). 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: 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: 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: 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: To allow secure HTTPS traffic, run: After adding these services, you can verify that they were successfully added by running: 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: 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: You can verify that the rule has been applied by running: 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: Permanent configuration changes require a firewall reload before they take effect in the runtime environment. Reload the firewall using the following command: After reloading, verify that the rule is still present: 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: 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: 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: 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: You can see the specific configuration associated with a zone by including the --zone= parameter in your --list-all command: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: You can verify that this was successful using the --list-ports operation: 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: After testing, you will likely want to add these to the permanent firewall. You can do that by typing: 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: Now, you can adjust the definition found in the file you copied: To start, the file will contain the SSH definition that you copied: 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: Press ESC, then enter :x to save and close the file. Reload your firewall to get access to your new service: You can see that it is now among the list of available services: 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: You can verify that these are present in the permanent configuration by typing: As stated before, these won’t be available in the current instance of the firewall yet: Reload the firewall to bring these new zones into the active configuration: 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: Likewise, you can add the DNS service to your “privateDNS” zone: You can then change your interfaces over to these new zones to test them out: 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: After permanently applying these rules, you can restart the network and reload the firewall service: Validate that the correct zones were assigned: And validate that the appropriate services are available for both of the zones: 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: 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: Although this command successfully updates the permanent configuration, the rule will not affect the active firewall until you reload the configuration: 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: 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: 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: If the output returns no, allow SSH access before continuing: Once you confirm that the rule works correctly, make it permanent: 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: If the firewall service is not running, start it using: To ensure the firewall starts automatically when the system boots, enable the service: 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: 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. If the application actually uses TCP, the correct rule should be: 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: 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: To make the rule persistent across system reboots, add the --permanent flag and then reload the firewall: 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: To make this rule permanent: 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. You can also view all active services and ports for the current zone by running: 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: To disable firewalld so it does not start automatically at boot: 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: 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. Learn more about our products 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. 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 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 ?? 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. 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 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. Very helpful article! Please complete your information! 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.