A zone file that does nothing is harmless, but one that does the wrong thing on a remote box means a trip to the data centre. This guide builds a small persistent firewalld zone that binds a source network and permits one named service, then checks and reloads it without guessing what the XML means. The examples match firewalld 2.1.1, the installed version used for this guide, and take about 20 minutes.
Start with read-only checks. These do not need elevated privileges, although the daemon may refuse some information when it is stopped:
$ firewall-cmd --version
2.1.1
$ firewall-cmd --state
running
$ firewall-cmd --get-active-zones
public
interfaces: enp1s0
The exact active zone and interface are host-specific. On a stopped daemon, this installation reports FirewallD is not running. Do not treat that as a reason to edit files blindly. First decide whether firewalld is meant to be the firewall on this host.
Write down the active zone, interfaces and any current services before changing anything:
$ firewall-cmd --get-active-zones
$ firewall-cmd --zone=public --list-all
Checkpoint: you have the current zone, interfaces and services noted. Replace public with the zone that is actually active on your machine. A zone file that no interface or source selects may be perfectly valid and still have no effect on traffic.
/etc/firewalld/zones/. That is the intended override location for administrator-created zones./usr/lib/firewalld/zones/. Do not edit them, because an update can replace them..xml. The manpage limits the zone name to 17 characters.This example creates office.xml for IPv4 addresses in 192.0.2.0/24, a documentation network. Replace that network with one you control:
# install -d -m 0755 /etc/firewalld/zones
# install -m 0644 /dev/null /etc/firewalld/zones/office.xml
# cp --preserve=mode,ownership,timestamps /etc/firewalld/zones/office.xml /etc/firewalld/zones/office.xml.bak
The last command is a recovery copy. If office.xml already contains useful policy, inspect it before replacing it.
Warning: the install commands need root, and the empty-file step destroys the contents of an existing file. It is only safe for a newly named zone, so do not use it on an existing one.
A zone has one zone root element. A source binds traffic to an address or network, and a service enables a predefined service. Service names come from firewalld's service definitions, so check the spelling rather than inventing a port label:
$ firewall-cmd --get-services | tr ' ' '\n' | grep -x ssh
ssh
Now write the policy as root. The example allows the predefined SSH service from the documentation network:
<?xml version="1.0" encoding="utf-8"?>
<zone>
<short>Office</short>
<description>Controlled administration network</description>
<source address="192.0.2.0/24"/>
<service name="ssh"/>
</zone>
Tip: the original text of this guide described a forward element for intra-zone forwarding, but the example XML above does not contain one. Add it only if you specifically need forwarding between interfaces or sources in this zone, and leave it out otherwise.
Use an editor with root privileges, such as sudoedit /etc/firewalld/zones/office.xml. Do not paste a source network you have not verified.
source takes an IP address or a network with a mask.address, mac or ipset, not several at once.Use services for named application protocols. Use port when no suitable service exists, and specify tcp, udp, sctp or dccp. For example, this permits TCP port 8443:
<port port="8443" protocol="tcp"/>
Do not add both a service and its individual ports for reassurance. That makes later reviews harder without changing the result. A protocol element is different: it permits a system protocol from /etc/protocols, not a TCP or UDP port.
Security warning: masquerading and forwarding are separate, security-sensitive choices. <masquerade/> enables address masquerading for the zone. A forward-port maps a local port to another port or address: use to-port for local forwarding, and to-addr with an optional to-port for remote forwarding. Do not add either element until you can name the destination and the return path.
For rules that depend on source, destination, logging, rate limits, or accept, reject and drop actions, use a rich rule. The zone manpage points to firewalld.richlanguage(5) for the full grammar. Keep this first zone simple and add rich rules one at a time.
Check the permanent configuration while the current runtime policy stays in place:
# firewall-cmd --check-config
success
A parse or schema error is a stop sign. Check XML spelling, closing tags, the zone filename, the source mask, service names and protocol values. Do not reload until this command succeeds. It validates configuration only: it does not prove that the intended interface or source will select the zone.
Confirm that firewalld can see the zone and its permanent contents:
$ firewall-cmd --get-zones
block dmz drop external home internal office public trusted work
$ firewall-cmd --permanent --zone=office --list-all
office
target: default
sources: 192.0.2.0/24
services: ssh
Checkpoint: office is listed, the source is correct and the expected service appears. Output varies by version and existing configuration. According to the installed zone manpage, the default target rejects packets that match no rule.
Warning: reloading is service-disrupting. Existing connections can be affected, and a bad policy can remove your access. Keep your second session or console ready.
When validation and the backup are done, reload as root:
# firewall-cmd --reload
success
$ firewall-cmd --zone=office --list-all
office
target: default
sources: 192.0.2.0/24
services: ssh
Test from a client in the declared source network, not only from the firewall host. Confirm the intended service works, and confirm that an unrelated source is not accidentally matching the new zone.
Tip: if NetworkManager manages an interface, it normally binds that interface to a zone automatically. An interface element in XML is mainly a fallback for interfaces it cannot manage.
A zone source and an interface are alternative ways to classify traffic. If both are present in overlapping zones, selection can surprise you. Use --get-active-zones and --zone=ZONE --list-all to inspect the actual arrangement.
If the reload fails validation, the old runtime policy should remain in place, but still read the error before retrying. If the new policy blocks your administration path, use the console or your second session. Restore the backup, validate and reload:
# cp --preserve=mode,ownership,timestamps /etc/firewalld/zones/office.xml.bak /etc/firewalld/zones/office.xml
# firewall-cmd --check-config
# firewall-cmd --reload
Recovery: do not delete a zone file as a first response. If the zone is no longer required, first remove its interface or source association and confirm the replacement policy. Keep the backup until a connection test has succeeded. Removing a backup is irreversible, so make it a deliberate housekeeping action rather than part of the recovery command.
/etc/firewalld/zones/, with a tested backup.firewall-cmd --check-config reports success before every reload.