How to manage network services with firewall-cmd

In a previous article, you explored how to control the firewall at the command line in Fedora.

Now you are going to see how to see how add, remove, and list services, protocols and ports in order to block or allow them.

A short recap

First, it’s a good idea to check the status of your firewall, see if it’s running or not. You do this, as we previously learned, by using the state option (firewall-cmd ‐‐state).

The next step is to get the zone for the desired network interface. For example, I use a desktop that has two network interfaces: a physical interface (enp0s3), representing my actual network card and a virtual interface (virbr0) used by virtualization software like KVM. To see what zones are active, run firewall-cmd ‐‐get-active-zones.

Now that you know what zone you’re interested in, you can list the rules for the zone with firewall-cmd ‐‐info-zone=FedoraWorkstation.

Reading zone information

To display information for a particular zone, run firewall-cmd ‐‐zone=ZoneName ‐‐list-all, or simply display information for the default zone with:

[dan@localhost ~]$ firewall-cmd --list-all
FedoraWorkstation (active)
target: default
icmp-block-inversion: no
interfaces: enp0s3
services: dhcpv6-client mdns samba-client ssh
ports: 1025-65535/udp 1025-65535/tcp
masquerade: no
rich rules:

Now, let’s explore the output. The first line is showing which zone the following information applies to and if that zone is currently in use.

The target : default simply tells us this is the default zone. This can be set or retrieved via the ‐‐set-default-zone=ZoneName and ‐‐get-default-zone.

icmp-block-inversion, indicates if ICMP requests are blocked. For example if the machine responds to ping requests from other machines on the network. The interfaces field shows all interfaces that adopt this zone.

Handling services, ports, and protocols

Now focus on the services, ports, and protocols rows. By default, the firewall will block all ports, services and protocols. Only the listed ones will be allowed.

You can see the allowed services are very basic client services in this case. For example, accessing a shared folder on the network (samba-client), to talk to a DNS server or connect to a machine via SSH (the ssh service). You can think of a service as a protocol in combination to a port, for instance the ssh service is using the SSH protocol and, by convention, port 22. By allowing the ssh service, what you’re really doing is allowing incoming connections that use the ssh protocol at default port 22.

Notice, services that have the client word in their name, as a rule of thumb, refer to outgoing connections, i.e. connections that you make with your IP as source going to the outside, as opposed to the SSH service, for example, that will accept incoming connections (listening to connection coming from outside at you).

You can look up services in the file /etc/services. For example if you wish to know what port and protocol these service uses:

[dan@localhost ~]$ cat /etc/services | grep ssh
ssh 22/tcp # The Secure Shell (SSH) Protocol
ssh 22/udp # The Secure Shell (SSH) Protocol

You can see SSH uses both TCP and UDP port 22. Also, if you wish to see all available services, just use firewall-cmd ‐‐get-services.

Opening a port

If you want to block a port, service, or protocol, all you have to do if make sure it’s not listed here. By extension, if you want to allow a service, you need add it to your list.

Let’s say you want to open the port 5000 for TCP connection. To do this, run:

sudo firewall-cmd --zone=FedorwaWorkstation --permanent --add-port=5000/tcp

Notice that you need to specify the zone for which the rule applies. When you add the rule, you also need to specify if it is a TCP or UDP port via as indicated above. The permanent parameter sets the rule to persist even after a system reboot.

Look at the information for your zone again:

[dan@localhost ~]$ firewall-cmd --list-all
FedoraWorkstation (active)
target: default
icmp-block-inversion: no
interfaces: enp0s3
services: dhcpv6-client mdns samba-client ssh
ports: 1025-65535/udp 1025-65535/tcp 5000/tcp
masquerade: no
rich rules:

Similarly, if you wish to remove this port from the list, run:

sudo firewall-cmd --zone=FedorwaWorkstation --permanent --remove-port=5000/tcp

The very same remove (‐‐remove-protocol, ‐‐remove-service) and add (‐‐add-protocol, ‐‐add-service) options are also available for services and protocols.

Photo by T. Kaiser on Unsplash.

For System Administrators


  1. Jack

    You seriously should delete this google+ button from top right corner 🙂

  2. Joao Rodrigues

    If you use the –permanent, your rules won’t be applied until you do a firewall-cmd –reload or until you reboot.

    Also, there’s a couple of typos.
    It’s written fedorwa instead of fedora

    • Good remark! And thanks for the observation, I’ll see what I can to correct that!

  3. Being able to create your own service definitions and applying those to specific zones and interfaces is also super useful.

  4. Jordan

    Nice job, I need to learn more about this.

    • Thank you! Means much to me! I know it’s a bit repetitive to what was written in part one, maybe should have covered also how to deal with custom services.

  5. Giovanni Fabbro

    So I noticed that Fedora 33 is going to be using systemd-resolved by default too.

    Great, but can we standardize on systemd-swap as well? Swap partitions seem to be wasteful and outdated at this point in time. Isn’t there security improvements having it as a file on an encrypted filesystem vs a standalone partition (does LUKS do this automatically?)? And shouldn’t it be more economical on resources with the EarlyOOM improvements?

  6. Nice job, I need to learn more about this.Thank alot i hope you update upto time

  7. MF

    One thing I have been missing in firewalld is the ability to add private services from e.g. rpm packages.
    Assume that I have a exampled.rpm which contains a server listening on the “example” port, upon installation of that I would like to be able to register the “example” service in firewalld, how would I go about doing that?

    • Good question! I think that by simply opening the correct port and protocol, it would become neutral or agnostic in regards to what you are running. In other words you could run http server X or server Y as long as they operate on same port/protocol and that’s set up in the firewall you can exchange them with no problem.
      Now you could also create your custom service myHttpServer and deal with that level of abstractin if so wish.
      Hope it helps

    • You can easily create your own custom services by adding them at the command line with firewall-cmd and leverage the –new-service (I’d just inject all of the ports/description/etc, and then do a –runtime-to-permanent call).

      Or you can write the file in your favorite text editor, and then call firewall-cmd –new-service-from-file.

      Or you can write the definition straight to: /etc/firewalld/services/${YOUR_SERVICE}.xml, and then firewall-cmd –add-service=${YOUR_SERVICE}

    • Joao Rodrigues

      Let’s say your example service listens on ports 666/tcp and 999/udp:
      Create a file called /etc/firewalld/services/example-service.xml with the contents:

      Example Service
      A longer description where you explain what the example service is and what it does

      Then you can register the example service like this:

      firewall-cmd –permanent –add-service=example-service

      firewall-cmd –reload

    • Joao Rodrigues

      (Edit: Let’s see if this displays correctly – can we have a preview comment?)

      Let’s say your example service listens on ports 666/tcp and 999/udp:
      Create a file called /etc/firewalld/services/example-service.xml with the contents:

      <?xml version="1.0" encoding="utf-8"?>
      <short>Example Service</short>
      <description>A longer description where you explain what the example service is and what it does</description>
      <port protocol="tcp" port="666"/>
      <port protocol="udp" port="999"/>

      Then you can register the example service like this:
      # firewall-cmd –permanent –add-service=example-service
      # firewall-cmd –reload

      • Ondrej

        No it did not 😀
        The default services are defined in:

        so you can always have a look and just copy paste them O:)

  8. itsmefma

    Thanks for the article!
    If there is another entry in this series I would like it to be about rich rules 😀

  9. Anonymous

    A few tips and tricks for firewall-cmd I’ve learned over the years that are valuable when using Fedora on a multi-NIC system as firewall:

    Get familiar with nmcli for managing the IP settings and configurations on your interfaces. Running nmcli without parameters will give you a quick overview of your current interfaces and their configuration. The nmcli commands aren’t difficult – nmcli connection edit ‘Connection Name’ drops you in, goto section lets you configure a section, print shows you the settings, back goes up a level, save, quit, etc. It’s all pretty self explanatory. Note it likes /CIDR notation (i.e. for addresses, and it assumes when you got to set the address that you’re adding to an existing one, so you need to clear the existing address if it has one before adding a new one. At this point, I disable all IPv6 because I don’t know enough to secure it properly.

    Next, you set up your zones using firewall-cmd independently of binding to them. I typically have an internal zone and two external zones – external_lockdown for when I don’t want any inbound connectivity, and external_normal that exposes my normal services to the Internet. For my external_lockdown zone, I even use –add-icmp-block for everything – I go completely icmp quiet.

    On both of my external zones I have –add-masquerade – that’s how you get IPv4 NATing to work.

    Finally, the tricky piece of the puzzle is that my experience is that firewall-cmd doesn’t bind zones to interfaces properly if the interface isn’t plugged in. Futher more, sometimes it seems like you can end up with multiple zones bound to a single interface, and that doesn’t seem helpful. So what I do now is do my zone binding from a console connection. Next, when I’m messing with zones on the external interface, I disconnect my external feed and just the cable from my internal network switch to whichever interface I’m binding. I unbind the current zone on that interface with –remove-interface, then add the interface to the new zone with –add-interface, then use –reload, then check everything with –get-active-zones.

    Finally, I use GRC’s Shields Up to probe my machine from the Internet after doing any work as confirmation that the ports I expect to see are open and everything else is locked down tight.

  10. Hello to every one, for the reason that I am really keen of reading this
    webpage’s post to be updated daily. It contains good data.

Comments are Closed

The opinions expressed on this website are those of each author, not of the author's employer or of Red Hat. Fedora Magazine aspires to publish all content under a Creative Commons license but may not be able to do so in all cases. You are responsible for ensuring that you have the necessary permission to reuse any work on this site. The Fedora logo is a trademark of Red Hat, Inc. Terms and Conditions