Plug a machine into a coffee-shop network with the same firewall rules you use at your desk and you have made a small mistake with a long tail. This guide inspects firewalld's zones, binds one network interface to the zone that matches its trust level, allows one named service and makes the result survive a reload. The examples use firewalld 2.1.1 and firewall-cmd, and take about 15 minutes, including a check that you have not locked yourself out.
root or sudo.enp1s0. Replace it with the name on your host.Ask firewalld which zone is active and which is the default:
$ firewall-cmd --get-active-zones
public
interfaces: enp1s0
$ firewall-cmd --get-default-zone
public
Your output can differ. The active-zone listing is the useful answer for an interface that is currently up. A connection belongs to one zone, while a zone can serve several connections.
Do not change a zone just because its name sounds familiar:
public suits an untrusted network.home, work and internal imply more trust.trusted accepts all network connections and deserves particular care.Checkpoint: confirm the interface really is the one connected to the network you are about to classify. Use ip link or your NetworkManager tools if the name is unclear.
Query the zone before editing it:
$ firewall-cmd --zone=public --list-all
public (active)
target: default
interfaces: enp1s0
sources:
services: cockpit dhcpv6-client ssh
ports:
protocols:
forward: yes
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
The exact services and other lines depend on the host. A service is a predefined combination of ports and protocols. Ports, ICMP blocks, masquerading, forward ports, intra-zone forwarding and rich rules are also properties of a zone. Read the complete output rather than assuming that moving an interface only changes one port.
Tip: do not expose a service just to make a client work. Identify the application, its listening address and its required protocol first. If the application is not meant to be reachable from this network, changing the firewall is the wrong fix.
When you have confirmed the target zone, bind the interface to it. This changes the running firewall, so keep an existing administrative session open:
$ sudo firewall-cmd --zone=internal --change-interface=enp1s0
success
$ firewall-cmd --get-active-zones
internal
interfaces: enp1s0
--change-interface changes the zone binding for an interface. It does not change the default zone. It also does not mean every interface on the host should use the same zone. A laptop on public Wi-Fi and a server interface on a private management network may need different treatment.
Checkpoint: run firewall-cmd --zone=internal --list-all and confirm the interface appears there. If the result is wrong, undo the runtime binding immediately:
$ sudo firewall-cmd --zone=public --change-interface=enp1s0
success
Recovery: that undo command assumes public was the previous binding. Use the zone you recorded in step 1 if yours was different.
For a service already supplied by firewalld, add its name to the selected zone. This example permits SSH in the runtime configuration:
$ sudo firewall-cmd --zone=internal --add-service=ssh
success
$ firewall-cmd --zone=internal --list-services
ssh
This opens the service in the running configuration. It does not prove that an SSH daemon is listening, and it does not create one. Verify the application separately, for example with ss -ltn and a controlled connection from the intended network.
Removing the runtime permission is the direct recovery:
$ sudo firewall-cmd --zone=internal --remove-service=ssh
success
Warning: use a named service when one exists. Adding a broad port range, or selecting trusted to bypass a confusing result, makes the policy harder to review and can expose more than you intended.
Runtime changes disappear when firewalld reloads or restarts. After testing the intended access, repeat the approved changes with --permanent:
$ sudo firewall-cmd --permanent --zone=internal --change-interface=enp1s0
success
$ sudo firewall-cmd --permanent --zone=internal --add-service=ssh
success
$ sudo firewall-cmd --reload
success
$ firewall-cmd --get-active-zones
internal
interfaces: enp1s0
The permanent database is separate from the runtime state. A permanent command alone does not apply the change straight away. --reload makes the saved configuration active while retaining runtime state where firewalld supports it. Check the zone again after the reload.
Tip: if you tested runtime changes on purpose and want to save the whole current runtime configuration instead, sudo firewall-cmd --runtime-to-permanent is available. Treat it as a deliberate write: it can persist unrelated runtime changes made by another administrator or service.
The zone can also be stored in a connection's configuration using ZONE=.
nm-connection-editor.Here is the trap: a manual firewalld binding can look correct until the connection is brought down and up again. If the zone returns after reconnection, inspect the connection profile and set the intended zone there. Then reload or reactivate the connection during a maintenance window.
Warning: keep a console or out-of-band session available, because network changes can interrupt remote access.