Put a Linux Interface in the Right firewalld Zone

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.

1. Check the current assignment

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:

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.

2. Inspect what the zone permits

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.

3. Move the interface at runtime

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.

4. Add only the required service

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.

5. Persist the tested result

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.

6. Fix assignments managed by the connection

The zone can also be stored in a connection's configuration using ZONE=.

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.

Done means