How to add a firewalld direct rule

A firewalld direct rule bypasses the normal service, port, rich rule, and policy abstractions and writes a lower-level rule into the backend firewall. Use it only when a zone rule cannot express the packet match, because direct rules are harder to audit and current upstream documentation marks the direct interface as deprecated.

Direct rules require an address family, table, chain, priority, and backend-style rule arguments. The example adds an IPv4 rule to accept TCP port 8443 from one trusted host in the INPUT path, then checks the saved direct-rule inventory before relying on it.

Runtime and permanent direct rules are separate. Add a temporary runtime rule only for testing, add the permanent rule when it must survive a reload, and keep a replacement plan with a rich rule or policy whenever the same match can be represented through supported firewalld objects.

Steps to add a firewalld direct rule:

  1. Confirm that firewalld is running before changing backend rules.
    $ sudo firewall-cmd --state
    running
  2. Check whether a supported zone rule can express the same exception.
    $ sudo firewall-cmd --zone=public --list-rich-rules
    rule family="ipv4" source address="10.77.0.10/32" port port="8443" protocol="tcp" accept

    Prefer services, ports, rich rules, or policies when they can express the match. The direct interface is deprecated upstream and should be kept for cases that need backend-specific behavior.

  3. Inspect existing permanent direct rules before adding a new priority.
    $ sudo firewall-cmd --permanent --direct --get-all-rules

    An empty result means no permanent direct rules are saved. Existing rules with the same family, table, chain, and low priority can run before the new rule.

  4. Add the direct rule to the permanent configuration.
    $ sudo firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -p tcp --dport 8443 -s 10.77.0.10 -j ACCEPT
    success

    The priority value sorts rules inside the selected chain. Lower numbers run earlier, so use a narrow source and destination match when adding a rule near the front of INPUT.

  5. Validate the saved firewalld configuration.
    $ sudo firewall-cmd --check-config
    success
  6. Reload firewalld so the permanent direct rule becomes active.
    $ sudo firewall-cmd --reload
    success

    A reload normally replaces runtime rules with permanent configuration. Direct runtime changes may be affected by FlushAllOnReload settings, so verify the final runtime inventory after reload.

  7. List the active direct rules after the reload.
    $ sudo firewall-cmd --direct --get-all-rules
    ipv4 filter INPUT 0 -p tcp --dport 8443 -s 10.77.0.10 -j ACCEPT
  8. Query the exact direct rule when a change ticket needs a yes-or-no proof.
    $ sudo firewall-cmd --direct --query-rule ipv4 filter INPUT 0 -p tcp --dport 8443 -s 10.77.0.10 -j ACCEPT
    yes
  9. Test the application port from the source address matched by the rule.
    $ nc -vz app01.example.net 8443
    Connection to app01.example.net 8443 port [tcp/*] succeeded!
  10. Test the same port from an unmatched source path.
    $ nc -vz -w 2 app01.example.net 8443
    nc: connect to app01.example.net port 8443 (tcp) failed: Connection timed out

    If the unmatched source still connects, look for a broader service, port, rich rule, source-zone assignment, policy, or earlier direct rule that allows the same traffic.