Create and safely use a firewalld conntrack helper
You will create a local firewalld helper definition, make it available to a service, validate the XML, and apply the service change without confusing runtime state with the saved configuration. The example uses the FTP conntrack module on TCP port 2121. Allow about 15 minutes, plus a maintenance window if the service is handling live traffic.
The route
Jump straight to the step you need, or tick off Done means at the end.
This guide describes firewalld 2.1.1, installed here as package version 2.1.1-1. The helper file format is supplied by that version's firewalld.helper(5) manual page. A helper is a narrowly scoped conntrack definition, not a replacement for opening a firewall port: the service still needs a port or other matching rule that permits the traffic.
1. Check the package and service state
Run these checks as your ordinary user:
$ firewall-cmd --version
FirewallD is running: version: 2.1.1
$ firewall-cmd --state
running
The exact version line can include distribution details. If firewall-cmd --state does not report running, do not continue with commands that require the daemon. Start firewalld through your system's normal service manager or use the offline configuration tool if you are deliberately preparing an offline image.
Checkpoint: record the active service name you intend to change. The examples below use ftp-custom as a placeholder. Substitute the name of a service file that already exists, or create one through your normal service-management process.
2. Write the helper XML
Custom helper files belong in /etc/firewalld/helpers. Distribution-supplied definitions live in /usr/lib/firewalld/helpers; do not edit those files because package updates can replace them. The filename, without .xml, becomes the helper name.
The following definition associates the kernel's FTP conntrack module with TCP port 2121:
<?xml version="1.0" encoding="utf-8"?>
<helper module="nf_conntrack_ftp">
<short>Custom FTP helper</short>
<description>FTP control traffic on the custom port</description>
<port protocol="tcp" port="2121"/>
</helper>
Create the directory and file with elevated privileges. This command changes persistent firewall configuration, so review the path and contents before running it:
$ sudo install -d -m 0755 /etc/firewalld/helpers
$ sudoedit /etc/firewalld/helpers/ftp-custom.xml
Keep exactly one helper element in the file. Its module attribute is mandatory and names a netfilter conntrack helper beginning with nf_conntrack_. The optional family attribute accepts only ipv4 or ipv6; if omitted, the definition applies to both families. Add family="ipv4" when the helper must be restricted to IPv4.
Each port element must be empty and must contain both port and protocol. The port can be a number, a range such as 2121-2123, or an empty value when the helper should match the protocol without a port restriction. The accepted protocols are tcp, udp, sctp and dccp. Add another port element for another port and protocol pair.
3. Validate the file before loading it
First validate XML syntax without touching firewalld:
$ xmllint --noout /etc/firewalld/helpers/ftp-custom.xml
No output and exit status 0 means the XML parser accepted the file. If xmllint is not installed, inspect the file carefully and use firewalld's own configuration check in the next command.
Ask firewalld to check its permanent configuration:
$ sudo firewall-cmd --check-config
success
This checks XML validity and semantics. A failure usually points to an invalid attribute, an unsupported protocol, a missing module name, or a malformed element. Fix the file and run both checks again. Do not reload a configuration that has not passed the check.
Checkpoint: the file exists under /etc/firewalld/helpers, xmllint accepts it when available, and firewall-cmd --check-config returns success.
4. Attach the helper to a permanent service
A helper definition is not used merely because its XML file exists. Attach its name to the service that needs it. The operation is permanent and requires elevated privileges:
$ sudo firewall-cmd --permanent --service=ftp-custom --add-helper=ftp-custom
success
$ sudo firewall-cmd --permanent --service=ftp-custom --query-helper=ftp-custom
yes
For a service that does not already exist, stop here and create its service definition first. Do not guess a service name. You can inspect the saved service definitions with:
$ firewall-cmd --permanent --get-services
The --permanent change is saved to disk but is not effective in the current runtime configuration. That separation is deliberate: you can validate a saved change before selecting when it becomes active.
5. Apply and verify the change
Reloading makes the current permanent configuration the new runtime configuration. It can discard other runtime-only changes, so check with the firewall owner before doing this on a busy host:
$ sudo firewall-cmd --reload
success
$ firewall-cmd --service=ftp-custom --get-service-helpers
ftp-custom
If the service has a different name, substitute it in both commands. The helper listing confirms that firewalld read the service configuration. It does not prove that the kernel module is available or that an application is using the expected FTP behaviour. Test the actual service from an approved client and review your normal firewall and conntrack monitoring.
When a reload is not appropriate yet, leave the change permanent and schedule the reload. If you need to discard the saved attachment before applying it, remove only that association:
$ sudo firewall-cmd --permanent --service=ftp-custom --remove-helper=ftp-custom
success
$ sudo firewall-cmd --check-config
success
Removing the helper association does not delete /etc/firewalld/helpers/ftp-custom.xml. Delete that file only when you have confirmed that no service or automation refers to it, and keep a copy if you may need to restore it.
6. Avoid the common traps
- A helper is not a port opening. Permit the control port through the relevant zone or service rules as a separate, reviewed change.
- Do not put a custom definition in
/usr/lib/firewalld/helpers. Use/etc/firewalld/helpersfor local configuration. - Do not assume that omitting
familymeans IPv4 only. The documented default is both IPv4 and IPv6. - Do not use
--complete-reloadas a routine verification step. The firewall-cmd manual warns that it can terminate active connections by losing state information. - Do not use
--runtime-to-permanentcasually. It overwrites the complete permanent configuration with the current runtime configuration, not just this helper change.
Done means
- The helper XML is under
/etc/firewalld/helpersand names an installed, appropriate conntrack module. - The XML and permanent firewalld configuration checks pass.
- The helper is attached to the intended service with
--permanent --add-helper. - A planned reload has made the permanent change runtime, or the reload is intentionally deferred.
- The service port rules and helper behaviour have been tested separately.