How to set up a firewall using FirewallD on CentOS 8


 A Linux firewall used to protect your workstation or server from unwanted traffic. You can set up rules to either block traffic or allow through. CentOS 8 comes with a dynamic, customizable host-based firewall with a D-Bus interface. You can add or delete or update firewall rules without restarting the firewall daemon or service. The firewall-cmd act as a frontend for the nftables. In CentOS 8 nftables replaces iptables as the default Linux network packet filtering framework.

In this guide, we will show you how to set up a firewall for your CentOS 8 and manage with the help of firewall-cmd administrative tool.


  • an active KVM VPS or Linux Server
  • root or user with sudo privileges 

Basic concepts of FirewallD

Firewalld simplifies the concepts of network traffic management. You have two main ideas as follows when it comes to firewalld on CentOS 8.

Firewalld Zones

The firewalld daemon manages groups of rules using entities called zones. Zones are sets of rules that dictate what traffic should be allowed depending on the level of trust you have in the network. Network interfaces are assigned to a zone to dictate the behavior that the firewall should allow.

Below are the zones provided by FirewallD ordered according to the trust level of the zone from untrusted to trusted:

  • drop: All incoming connections are dropped without any notification. Only outgoing connections are allowed.
  • block: All incoming connections are rejected with an icmp-host-prohibited message for IPv4 and icmp6-adm-prohibited for IPv6n. Only outgoing connections are allowed.
  • public: For use in untrusted public areas. You do not trust other computers on the network, but you can allow selected incoming connections.
  • external: For use on external networks with NAT masquerading enabled when your system acts as a gateway or router. Only selected incoming connections are allowed.
  • internal: For use on internal networks when your system acts as a gateway or router. Other systems on the network are generally trusted. Only selected incoming connections are allowed.
  • dmz: Used for computers located in your demilitarized zone that have limited access to the rest of your network. Only selected incoming connections are allowed.
  • work: Used for work machines. Other computers on the network are generally trusted. Only selected incoming connections are allowed.
  • home: Used for home machines. Other computers on the network are generally trusted. Only selected incoming connections are allowed.
  • trusted: All network connections are accepted. Trust all of the computers in the network.

To use the firewall, we can create rules and alter the properties of our zones and then assign our network interfaces to whichever zones are most appropriate.

Firewalld Runtime and Permanent Settings

Firewalld uses two separated configuration sets, runtime, and permanent configuration.

When a rule is added or modified, by default, only the currently running firewall is modified. After the next reboot – or reload of the firewalld service – only the permanent rules will remain.

Most firewall-cmd operations can take a --permanent flag to indicate that the changes should be applied to the permenent configuration. Additionally, the currently running firewall can be saved to the permanent configuration with the firewall-cmd --runtime-to-permanent command.

This separation of runtime vs permanent configuration means that you can safely test rules in your active firewall, then reload to start over if there are problems.

Installing and Enabling firewalld

On CentOS 8, firewalld is installed and enabled by default. If for some reason it is not installed on your system, you can install and start the daemon by typing:

sudo yum install firewalld

After you install firewalld, you can enable the service and reboot your server. Keep in mind that enabling firewalld will cause the service to start up at boot. It is best practice to create your firewall rules and take the opportunity to test them before configuring this behavior in order to avoid potential issues.

sudo systemctl enable firewalld
sudo systemctl start firewalld

You can check the status of the firewall service with:

sudo firewall-cmd --state

If the firewall is enabled, the command should print running. Otherwise, you will see not running

Firewalld Zones

If you haven’t changed it, the default zone is set to public, and all network interfaces are assigned to this zone.

The default zone is the one that is used for everything that is not explicitly assigned to another zone.

We can see which zone is currently selected as the default by typing:

firewall-cmd --get-default-zone

To get a list of all available zones, type:

sudo firewall-cmd --get-zones
block dmz drop external home internal public trusted work

To see the active zones and the network interfaces assigned to them:

firewall-cmd --get-active-zones
   interfaces: eth0 eth1

Here, we can see that our 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 we know what rules are associated with the public zone though? We can print out the default zone’s configuration by typing:

sudo firewall-cmd --list-all
public (active)
   target: default
   icmp-block-inversion: no
   interfaces: eth0 eth1 sources: services: cockpit dhcpv6-client ssh ports: protocols: masquerade: no forward-ports: source-ports: icmp-blocks: rich rules:

We can see the specific configuration associated with a zone by including the --zone= parameter in our --list-all command:

sudo firewall-cmd --zone=home --list-all
   target: default
   icmp-block-inversion: no
   services: cockpit dhcpv6-client mdns samba-client ssh
   masquerade: no
   rich rules:

If you want to check the configurations of all available zones type:

sudo firewall-cmd --list-all-zones | less
Selecting Zones for your Interfaces

Unless you have configured your network interfaces otherwise, each interface will be put in the default zone when the firewall is started.

Changing the Zone of an Interface

You can create specific sets of rules for different zones and assign different interfaces to them. This is especially useful when you multiple interfaces on your machine.

To assign an interface to a different zone, specify the zone with the --zone option and the interface with the --change-interface option.

For instance, we can move our eth0 interface to the home zone by typing this:

sudo firewall-cmd --zone=home --change-interface=eth0

Verify the changes by typing:

firewall-cmd --get-active-zones
home    interfaces: eth0  public    interfaces: eth1
Changing the Default Zone

If all of your interfaces can be handled well by a single zone, it’s probably easiest to just designate the best zone as default 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 using the default zone:

sudo firewall-cmd --set-default-zone=home
Creating new Zones

Firewalld also allows you to create your own zones. This is handy when you want to create per-application rules.

In the following example we’ll create a new zone named memcached, open the port 18787 and allow access only from the IP address:

sudo firewall-cmd --new-zone=memcached --permanent

Add the rules to the zone:

sudo firewall-cmd --zone=memcached --add-port=18787/udp --permanent sudo firewall-cmd --zone=memcached --add-port=18787/tcp --permanent sudo firewall-cmd --zone=memcached --add-source= --permanent

Reload the firewalld daemon to activate the changes:

sudo firewall-cmd --reload
Firewalld Services

With firewalld you can allow traffic for specific ports and/or sources based on predefined rules called services.

To get a list of all default available services type:

sudo firewall-cmd --get-services
RH-Satellite-6 amanda-client amanda-k5-client amqp amqps apcupsd audit bacula bacula-client bb bgp bitcoin bitcoin-rpc bitcoin-testnet bitcoin-testnet-rpc bittorrent-lsd ceph ceph-mon cfengine cockpit condor-collector ctdb dhcp dhcpv6 dhcpv6-client distcc dns dns-over-tls docker-registry docker-swarm dropbox-lansync elasticsearch etcd-client etcd-server finger freeipa-4 freeipa-ldap freeipa-ldaps freeipa-replication freeipa-trust ftp ganglia-client ganglia-master git grafana gre high-availability http https imap imaps ipp ipp-client ipsec irc ircs iscsi-target isns jenkins kadmin kdeconnect kerberos kibana klogin kpasswd kprop kshell kube-apiserver ldap ldaps libvirt libvirt-tls lightning-network llmnr managesieve matrix mdns memcache minidlna mongodb mosh mountd mqtt mqtt-tls ms-wbt mssql murmur mysql nfs nfs3 nmea-0183 nrpe ntp nut openvpn ovirt-imageio ovirt-storageconsole ovirt-vmconsole plex pmcd pmproxy pmwebapi pmwebapis pop3 pop3s postgresql privoxy prometheus proxy-dhcp ptp pulseaudio puppetmaster quassel radius rdp redis redis-sentinel rpc-bind rsh rsyncd rtsp salt-master samba samba-client samba-dc sane sip sips slp smtp smtp-submission smtps snmp snmptrap spideroak-lansync spotify-sync squid ssdp ssh steam-streaming svdrp svn syncthing syncthing-gui synergy syslog syslog-tls telnet tentacle tftp tftp-client tile38 tinc tor-socks transmission-client upnp-client vdsm vnc-server wbem-http wbem-https wsman wsmans xdmcp xmpp-bosh xmpp-client xmpp-local xmpp-server zabbix-agent zabbix-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 HTTP service is defined like this:

WWW (HTTP) HTTP is the protocol used to serve Web pages. If you plan to make your Web server publicly available, enable this option. This option is not required for viewing pages locally or developing Web pages.

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. To allow incoming HTTP traffic (port 80) for interfaces in the public zone, only for the current session (runtime configuration) type:

sudo firewall-cmd --zone=public --add-service=http

If you are modifying the default zone you can leave out the --zone option.

To verify that the service was added successfully use the --list-services option:

sudo firewall-cmd --zone=public --list-services
cockpit dhcpv6-client http ssh

Alternately, you could use the --runtime-to-permanent flag to save the currently running firewall configuration to the permanant config:

sudo firewall-cmd --runtime-to-permanent

Be careful with this, as all changes made to the running firewall will be commited permenantly.

Use the --list-services along with the --permanent option to verify your changes:

sudo firewall-cmd --zone=public --list-services --permanent
cockpit 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. We 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 --add-service=https --permanent
Creating a new FirewallD Service

As we have already mentioned, the default services are stored in the /usr/lib/firewalld/services directory. The easiest way to create a new service is to copy an existing service file to the /etc/firewalld/services directory, which is the location for user-created services and modify the file settings.

For instance, we could copy the SSH service definition to use for our 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. First open it in your favorite text editor. We’ll use vi here:

sudo vi /etc/firewalld/services/example.xml

To start, the file will contain the SSH definition that you copied:


  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.

Save the file and reload the FirewallD service:

sudo firewall-cmd --reload

The majority of this definition is actually metadata. You will want to change the short name and description for the service within the  and  tags

For our example service, imagine that we need to open up port 5000 for TCP and 7000 for UDP.

We can modify the existing definition with something like this:


  example service
  This is just an example service. It probably shouldn't be used on a real system.

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:

firewall-cmd --get-services

You can now use this service in your zones same as any other service

What If No Appropriate Service Is Available?

The services that are included with the firewalld installation represent many of the most common 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.

Opening a Port for your Zones

The easiest 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 (TCP or UDP) for the ports.

For instance, if our application runs on port 3600 and uses TCP, we could temporarily add this to the public zone using the --add-port= parameter. Protocols can be designated as either tcp or udp:

sudo firewall-cmd --zone=public --add-port=3600/t

We can verify that this was successful using the --list-ports operation:

sudo firewall-cmd --zone=public --list-ports

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 our application uses UDP ports 2000 to 3000, we could open these up on public by typing:

sudo firewall-cmd --zone=public --add-port=2000-3000/udp

To keep the port open after a reboot, add the rule to the permanent settings by running the same command using the --permanent flag or by executing:

sudo firewall-cmd --zone=public --permanent --add-port=3600/tcp
sudo firewall-cmd --zone=public --permanent --add-port=2000-3000/udp
sudo firewall-cmd --zone=public --permanent --list-ports
3600/tcp 2000-3000/udp

The syntax for removing a port is the same as when adding a port. Just use --remove-port instead of the --add-port option.

sudo firewall-cmd --zone=public --remove-port=3600/tcp
How to write port forwarding firewalld rule

To forward traffic from one port to another port, first enable masquerading for the desired zone using the --add-masquerade option.

For example, to enable masquerading for the external zone, type:

sudo firewall-cmd --zone=external --add-masquerade

In the following example we are forwarding the traffic from port 443 to port 8080 on the same server:

sudo firewall-cmd --zone=external --add-forward-port=port=443:proto=tcp:toport=8080
  • To delete above port forwarding, run
sudo firewall-cmd --zone=external --remove-forward-port=port=443:proto=tcp:toport=8080
Forward traffic to another IP address 

In the following example we are forwarding the traffic to lxd server/container hosted at port 443:

sudo firewall-cmd --zone=external --add-forward-port=port=80:proto=tcp:toaddr=
Forward traffic to another server on a different port

In the following example we are forwarding the traffic from port 443 to port 8080 on a server with IP

sudo firewall-cmd --zone=external --add-forward-port=port=443:proto=tcp:toport=8080:toaddr=

To make the forward rule persistent, use:

sudo firewall-cmd --runtime-to-permanent


You learned the basic concept of firewalld and some common examples for CentOS 8 server.

Make sure to allow all incoming connections that are necessary for the proper functioning of your system, while limiting all unnecessary connections.

That’s all! Enjoy GreenCloudVPS services!

On this page