Advanced Policy Firewall (APF)
Advanced Policy Firewall, usually called APF, is an iptables and netfilter firewall manager for internet-facing Linux servers. It turns a long ruleset into one annotated configuration, a trust system, and a practical command-line workflow. The useful part is not how quickly it can start. It is whether an operator can change policy without losing access or allowing traffic that was never intended.
APF is actively maintained. Version 2.0.2 was current when this guide was reviewed. The workflow below uses its current command interface, configuration, IPv6 behavior, container support, trust sources, validation, and recovery controls.
What APF does
APF builds Linux packet-filter rules from a central file, normally /etc/apf/conf.apf. Its policy has three broad layers:
- Static policy: ports, protocols, interfaces, and host allow or deny rules.
- Stateful policy: connection tracking that recognizes established and related traffic.
- Sanity policy: checks for malformed packets, forged source ranges, fragments, and suspicious connection patterns.
Current APF releases add dual-stack IPv6 filtering, temporary trust entries with expiry, ipset block lists, GeoIP country rules, structured audit events, connection limits, SYN-flood controls, systemd integration, and a compatibility mode for container-managed rules. APF can use either the traditional iptables backend or iptables running on the nftables backend.
That last sentence is easy to misread. APF supporting iptables-nft does not mean it becomes a native nftables policy manager. It still manages policy through the iptables interface.
Choose one firewall owner
Do not layer APF casually on top of firewalld, a hand-maintained nftables ruleset, or another firewall package. Several tools writing the same packet path create an order-of-evaluation problem, not defense in depth. A restart by either tool can remove, duplicate, or bypass rules owned by the other.
| Choose | It is a good fit when | Main caution |
|---|---|---|
| APF | You operate an existing APF estate or want its host trust, reactive blocking, remote lists, and per-address policy model | It owns iptables policy and must be tested with distro and container networking |
| firewalld | You want distro-integrated zones, runtime and permanent policy, and common NetworkManager integration | Direct rules can behave differently with its nftables backend |
| Native nftables | You need a custom ruleset and your team can own its syntax, testing, persistence, and automation | You also own every operating guardrail that a higher-level manager would provide |
Pick the manager that matches the server fleet and support model. If you are replacing an existing manager, document that migration as a separate change. Our Linux Server Support service can help review the host, access path, and rollback plan before a firewall change.
Prepare without locking yourself out
A firewall change on a remote server is also an access-control change. Before installing APF, arrange an out-of-band console or hypervisor console that does not depend on the interface being filtered. Keep the current administrative session open and plan to test with a second session.
Build an inventory from the server rather than assuming SSH is on port 22 or that the public interface is named eth0:
ip -brief address
ip route
ss -lntup
systemctl is-active firewalld
systemctl is-active nftables
iptables --version
iptables-save
ip6tables-save
Record every required inbound service, its address family, interface, source restriction, and owning application. Include monitoring, backup, DNS, VPN, control-panel, cluster, and application health traffic. Then map outbound dependencies such as DNS resolution, package repositories, time synchronization, APIs, databases, webhooks, and mail relays.
Save the current IPv4 and IPv6 rules in your approved change record. Confirm how the server will restore them. An APF rollback that merely flushes rules may recover access, but it does not reconstruct another manager's earlier policy.
Install a reviewed release
Use the official R-fx Networks repository and review the release before executing its installer. At the time of this review, the project identified v2.0.2 as the latest release. If the Releases page shows a newer version, review its changelog and substitute the approved tag.
git clone https://github.com/rfxn/advanced-policy-firewall.git
cd advanced-policy-firewall
git tag --sort=-v:refname | head
git checkout --detach v2.0.2
git status --short
less README.md
less CHANGELOG
sudo bash install.sh
The default installation path is /etc/apf, and the command is installed as /usr/local/sbin/apf. The installer also provides a systemd unit on modern systems. Do not enable persistent boot loading merely because installation completed. Configure and test the policy first.
Configure the policy you actually need
Open /etc/apf/conf.apf and read the comments above each setting. New installations start with DEVEL_MODE="1". In development mode, APF schedules an automatic flush every five minutes to reduce the chance of a permanent lockout. This is a safety net, not a replacement for console access and a tested rollback.
Review these settings first:
| Setting | Decision | Common mistake |
|---|---|---|
IFACE_UNTRUSTED | The internet-facing interface or interfaces APF should filter | Copying an old interface name after a network or distro migration |
IFACE_TRUSTED | Interfaces that are intentionally exempt | Trusting a broad interface when only a narrow source rule was required |
IG_TCP_CPORTS | Required inbound TCP destination ports | Leaving only the default port 22 when administration uses another port |
IG_UDP_CPORTS | Required inbound UDP destination ports | Forgetting DNS, VPN, application, or monitoring traffic |
USE_IPV6 | Whether APF must build the IPv6 policy too | Protecting IPv4 while leaving an active IPv6 path unreviewed |
EGF | Whether outbound filtering is enabled | Enabling it before mapping DNS, updates, APIs, mail, and other dependencies |
DOCKER_COMPAT | How APF preserves container-runtime rules during a reload | Assuming auto-detection replaces a real container connectivity test |
DEVEL_MODE | Automatic test-mode flush until validation is complete | Disabling it before a second access session and application checks pass |
IPv6 should be an explicit decision. If the host has routable IPv6, either build and test an IPv6 policy or disable IPv6 through an approved host and network design. Silently ignoring it leaves a second packet path outside the expected rule set. Keep essential ICMPv6 behavior intact because IPv6 neighbor discovery and path operation depend on it.
Validate in development mode
Validate the configuration before loading it, then keep the console and current administrative session available:
sudo apf config validate
sudo apf -o
sudo apf -s
sudo apf status
sudo systemctl status apf --no-pager
sudo iptables -S
sudo ip6tables -S
From a second session, repeat the real administration path. Test each exposed application from an appropriate external source, not only from localhost. Confirm monitoring and backups still connect. For a stateful firewall, also test a new connection after the rules are loaded; an already established session can hide a missing allow rule.
If the policy fails, use the out-of-band console to inspect the APF log and rules. apf -f stops APF and flushes its firewall policy, so use it only as part of the prepared recovery procedure. Do not fire that command through a failing remote session and hope the connection survives.
Only after the second login, application tests, IPv4 and IPv6 checks, logging, and rollback test pass should you set DEVEL_MODE="0", restart APF, and verify persistence through the supported systemd unit. Do not combine systemd, a SysV script, and rc.local startup methods.
Use the APF command line
APF 2.0.x supports both the familiar single-letter commands and structured subcommands. Commands such as apf -r, apf -a, and apf -d remain current. Run them with root privileges. Use sudo apf ... when /usr/local/sbin is already in the root command path, or use the complete installed path sudo /usr/local/sbin/apf ....
HOST can be an IPv4 address, IPv6 address, CIDR network, fully qualified domain name, or supported country code. CMT is an optional quoted comment. Use documentation ranges such as 198.51.100.0/24 and 203.0.113.0/24 only in examples. Replace them with an address you verified and own before making a real rule.
| Command | What it does | Example | Result and safety check |
|---|---|---|---|
apf -sapf --start | Loads the complete configured firewall policy. | sudo apf -s | Use it for the first development-mode load. Keep console recovery and the existing SSH session open, then test a new SSH session and every required service. |
apf -rapf --restart | Flushes and reloads all APF firewall rules. | sudo apf --validatesudo apf -r | Validate first. A wrong interface, port, or source rule can end remote access during reload. Verify with apf --info, a second login, and external service tests. |
apf -fapf --stopapf --flush | Stops APF and flushes all firewall rules. | sudo apf -f | This removes firewall protection. Use it only from the prepared recovery console or an approved rollback procedure, then restore the intended policy. |
apf --infoapf status | Shows an APF status summary, rule counts, trust counts, enabled filtering, subsystems, and recent logging. | sudo apf --info | Use this after start or restart. It is a summary, so still test the real allowed and denied network paths. |
apf -tapf --statusapf status log | Pages through the full APF status log at /var/log/apf_log. | sudo apf -t | Use it to investigate loading and runtime events. Press q to leave the pager. |
apf --rulesapf status rules | Writes active rules to standard output in iptables -S form. | sudo apf --rules | Use it for review or controlled filtering. It reports loaded rules, not whether the application behind an allowed port is healthy. |
apf -lapf --list | Opens the complete firewall rules in an editor for browsing. | sudo apf -l | This is not the allow-list command. Use apf --la to display allow entries and apf --ld for deny entries. |
apf -oapf --dump-configapf config dump | Outputs all effective APF configuration variables. | sudo apf -o | Save it with a change record or support case after reviewing whether the output contains internal operational details. |
apf --validateapf --checkapf config validate | Checks the configuration without starting or restarting the firewall. | sudo apf config validate | Run this after every configuration edit. Success proves the file parsed, not that the policy permits the correct production traffic. |
apf -a HOST [CMT]apf --allow HOST [CMT] | Adds a persistent allow entry and loads it immediately. No restart is required. | sudo apf -a 198.51.100.25 "office VPN example" | A bare address broadly trusts that host. Confirm the entry with apf --lookup and apf -g. Use advanced syntax when only one service should be allowed. |
apf -d HOST [CMT]apf --deny HOST [CMT] | Adds a persistent deny entry and loads it immediately. No restart is required. | sudo apf -d 203.0.113.50 "confirmed abusive host example" | Verify the source address and current sessions first. Confirm the stored and loaded rule with apf --lookup and apf -g. |
apf -u HOSTapf --remove HOSTapf --unban HOST | Removes a matching host or country code from all local and global trust files, including allow, deny, and temporary entries. | sudo apf -u 203.0.113.50 | This is broader than only undoing -d. Check where the host exists before removal, then confirm apf --lookup returns not found. |
apf --laapf --list-allow | Displays allow trust entries without comments and blank lines. | sudo apf --la | Use it before and after -a or -u. Also search global and loaded rules when investigating effective policy. |
apf --ldapf --list-deny | Displays deny trust entries without comments and blank lines. | sudo apf --ld | Use it before and after -d or -u. A host can also be affected by global, country, ipset, or reactive rules. |
apf --lookup HOSTapf trust lookup HOST | Checks whether the exact host exists in an allow, deny, global, country, or temporary trust file. | sudo apf --lookup 203.0.113.50 | Exit status is 0 when found and 1 when not found. It searches trust files, not every generated firewall rule. |
apf -g PATTERNapf --search PATTERN | Searches IPv4 and IPv6 rules, ipsets, and trust files for an address, port, chain, or other pattern. | sudo apf -g 203.0.113.50sudo apf -g :443 | Use this when --lookup is too narrow. Read the matched chain and action instead of treating any match as a block. |
apf -eapf --refreshapf trust refresh | Refreshes trust chains and re-resolves FQDN entries. | sudo apf -e | Use it after a dynamic DNS change. It is not a complete policy restart and does not refresh classic DLIST_* feeds. |
apf -ta HOST TTL [CMT]apf trust temp add | Adds a temporary allow entry with an expiry such as 5m, 1h, or 7d. | sudo apf -ta 198.51.100.25 1h "approved maintenance example" | Confirm the expiry with apf --temp-list. Temporary access still needs an owner, purpose, and approval. |
apf -td HOST TTL [CMT]apf trust temp deny | Adds a temporary deny entry with automatic expiry. | sudo apf -td 203.0.113.50 30m "incident containment example" | Confirm the correct source, expiry, evidence, and permanent follow-up before relying on a temporary block. |
apf --temp-listapf trust temp list | Lists temporary allow and deny entries with their remaining time. | sudo apf --temp-list | Use it during maintenance and incident handoff so temporary access or blocking is not forgotten. |
apf --temp-flushapf trust temp flush | Removes every temporary trust entry. | sudo apf --temp-listsudo apf --temp-flush | Review the list first. This removes temporary allows and temporary denies together, which can restore abusive traffic or remove emergency access. |
apf -vapf --version | Prints the installed APF version. | sudo apf -v | Record it before comparing behavior with documentation or opening a support issue. |
apf -hapf --helpman apf | Shows command help and the installed manual. | man apf | The installed manual is the complete reference for the exact release on that server. |
Use narrow rules when broad host trust is unnecessary
A bare apf -a 198.51.100.25 trusts that address broadly. If the requirement is only SSH from an administration VPN, specify the protocol, direction, destination port, and source:
sudo apf -a "tcp:in:d=22:s=198.51.100.25" "SSH from office VPN example"
sudo apf --lookup 198.51.100.25
sudo apf -g 198.51.100.25
# IPv6 in advanced syntax uses brackets around the address.
sudo apf -a "tcp:in:d=22:s=[2001:db8::25]" "IPv6 SSH source example"
For a targeted deny example, the following blocks traffic from one source to destination port 3306. Because the protocol is omitted, APF creates both TCP and UDP rules:
sudo apf -d "d=3306:s=203.0.113.50" "database probing example"
sudo apf -g 203.0.113.50
sudo apf -u "d=3306:s=203.0.113.50"
sudo apf --lookup 203.0.113.50
Use your real service port and verified source. A firewall allow rule does not authenticate a person, and a deny rule does not repair the vulnerable service that attracted the traffic.
Feature command groups
| Current command | Classic equivalent | Purpose and example | Important caution |
|---|---|---|---|
apf config validate | apf --validate | Validate conf.apf without loading rules: sudo apf config validate. | Run it before apf -s or apf -r, then perform network tests because syntax validation cannot prove policy intent. |
apf config dump | apf -o | Print effective configuration for review or support: sudo apf config dump. | Review the output before sharing it outside the operating team. |
apf cc info CN | apf --cc CN | Show detail for a country or continent code. Use apf cc info without a code for the overview. | Country is not identity. Geolocation changes and can block legitimate VPN, mobile, or cloud traffic. |
apf cc lookup 203.0.113.50 | apf --cc 203.0.113.50 | Looks up the APF GeoIP country result for an IP or CIDR. | The documentation address is only an example. Do not treat one lookup as permanent evidence of a user's location. |
apf cc update | apf --cc-update | Refreshes GeoIP data and its ipsets: sudo apf cc update. | Review source health and resulting counts before enforcing a large country-policy change. |
apf ct status | apf --ct-status | Shows connection-tracking limit configuration and last-scan information. | Confirm port, state, thresholds, exemptions, and escalation settings before enabling blocking. |
apf ct scan | apf --ct-scan | Runs the connection-limit scan and can block offenders. | This can change live policy. Review the status and exemptions first and monitor false positives. |
apf ipset status | No direct classic status flag | Lists APF ipset names: sudo apf ipset status. | Also inspect list age, entry count, source, and the loaded firewall rule that references each set. |
apf ipset update | apf --ipset-update | Hot-reloads configured ipset block lists without restarting the complete firewall. | A bad remote feed can affect many addresses quickly. Monitor download errors and unexpected count changes. |
apf gre status | apf --gre-status | Shows APF-managed GRE tunnel status. | Verify routes and both tunnel endpoints, not only the reported interface state. |
apf gre upapf gre down | apf --gre-upapf --gre-down | Brings configured GRE tunnels up or down. | Changing a tunnel can remove the administration or application route. Use console recovery and a tested path. |
apf --csf-help | Same command | Shows mappings for operators moving from ConfigServer Security and Firewall commands. | Use it as a translation aid, then verify APF behavior. Similar command names do not make the two policy models identical. |
Example: change configuration and reload safely
# Keep the current SSH session and out-of-band console available.
sudo apf -v
sudo apf config validate
sudo apf -r
sudo apf --info
sudo apf --rules
# From a second external session, test SSH and each required service.
# Then confirm the status log and the systemd unit.
sudo apf -t
sudo systemctl status apf --no-pager
Do not use apf -r as the first test of an unreviewed configuration. Do not use apf -f as routine troubleshooting. Validate first, reload from a recoverable session, verify the rules, and prove the network path with a new connection.
The command names and dispatch behavior above were checked directly against the upstream APF executable command dispatcher and the APF README usage reference. On an installed server, apf -v and man apf remain the final checks for that exact release.
Manage trust with narrow rules
APF stores local allow and deny entries in allow_hosts.rules and deny_hosts.rules. The command interface reduces manual editing errors:
sudo apf trust add 198.51.100.25 "administration VPN example"
sudo apf trust deny 203.0.113.50 "confirmed abusive host example"
sudo apf trust lookup 198.51.100.25
sudo apf trust remove 203.0.113.50
The addresses above are documentation examples. Replace them with verified sources from your own policy. Avoid permanently trusting a whole office, hosting-provider, or consumer ISP range when the real requirement is one VPN address and one administration port.
Version 2.0.2 also supports temporary trust entries with time to live:
sudo apf trust temp add 198.51.100.25 1h "approved maintenance example"
sudo apf trust list --temp
Temporary access is useful for maintenance, but expiry is not authorization. Record who approved it, why it exists, which service it reaches, and what evidence confirms that it expired.
Follow a changing address with dynamic DNS
This is one of APF's most practical features. The trust files accept fully qualified domain names as well as IPv4 addresses, IPv6 addresses, and CIDR blocks. APF resolves a hostname before loading its trust rule. When the DNS answer changes, APF can resolve it again without requiring an administrator to edit the firewall by hand.
The current conf.apf defaults are designed for this workflow:
SET_REFRESH="10"
SET_REFRESH_MD5="0"
FQDN_TIMEOUT="10"
SET_REFRESH="10" means APF refreshes the trust system every 10 minutes. The refresh flushes and reloads the TALLOW, TDENY, TGALLOW, and TGDENY chains, downloads enabled global trust files, and re-resolves hostnames in the rules. Set it to 0 only when automatic trust refresh is intentionally disabled.
Keep SET_REFRESH_MD5="0" when a trust entry uses dynamic DNS. With the MD5 optimization enabled, APF can skip a refresh when the trust file itself has not changed. A dynamic hostname can point to a new address while the text in allow_hosts.rules remains exactly the same.
For example, a home administrator with a changing public address can publish that address through a dynamic DNS provider such as Duck DNS, then add the hostname to APF:
getent ahosts your-subdomain.duckdns.org
sudo apf trust add your-subdomain.duckdns.org "home administrator dynamic DNS"
sudo apf -e
sudo apf trust lookup your-subdomain.duckdns.org
sudo apf -g your-subdomain.duckdns.org
Replace your-subdomain with the hostname you control. apf -e performs an immediate trust refresh and DNS re-resolution; the automatic cycle handles later changes. If USE_IPV6="1", APF can resolve and load both A and AAAA answers, so verify both address families.
A hostname allow rule is still a trust rule, not user authentication. APF evaluates local and global allow chains before deny chains, remote block lists, and normal port filtering. Anyone who gains control of the dynamic DNS account or its update token can point that trusted name at another address. Protect the dynamic DNS credentials, monitor unexpected changes, keep console recovery available, and use a VPN or stable bastion when a broad host-trust rule is more access than the server should grant.
Do not store a Duck DNS update token in conf.apf or a trust file. The dynamic DNS updater owns that secret. APF needs only the published hostname.
Use remote lists and global trust deliberately
APF has three related automation models. They refresh on different schedules, so it is worth knowing which one you have enabled.
| Mechanism | Purpose | Refresh behavior |
|---|---|---|
Classic DLIST_* imports | Project Honey Pot, Spamhaus DROP, DShield, reserved networks, and the ECN compatibility list | Downloaded and loaded on a full APF start or restart |
Global trust with USE_RGT | Your centrally maintained glob_allow.rules and glob_deny.rules | Downloaded and reloaded by the trust refresh cycle, which defaults to 10 minutes |
ipset.rules | Large local or remote IP and CIDR sets with efficient matching | The installed cron runs hourly; each list and IPSET_REFRESH control whether an update is due |
Classic remote-list imports
The DLIST_* switches in conf.apf control the remote-list system. Each enabled feed has a companion URL. APF validates downloaded entries and retains a backup so a failed download does not silently replace the last usable file.
DLIST_SPAMHAUSloads the Spamhaus DROP advisory list. It is a list of high-risk netblocks, not a general list of every IP associated with unwanted mail.DLIST_DSHIELDimports DShield's current top suspicious hosts.DLIST_PHPimports the Project Honey Pot harvester and spammer list supplied through R-fx Networks.DLIST_RESERVEDupdates the reserved or unassigned network file. It matters whenBLK_RESNET="1", and the default configuration enables both.DLIST_ECNSHAMEis not a deny feed. WhenSYSCTL_ECN="1", it identifies destinations that need ECN disabled for compatibility.
Do not change a vendor URL merely to point at a convenient mirror. The feed format is part of the integration. Test the source, certificate validation, parser result, entry count, and rollback before enabling a new or replacement URL.
Global allow and deny files
Global trust is valuable when several servers must share one reviewed source of truth. Publish the files from an HTTPS location you control, set GA_URL and GD_URL, and enable USE_RGT="1". APF downloads the files into glob_allow.rules and glob_deny.rules, then loads them into the TGALLOW and TGDENY chains.
USE_RGT="1"
GA_URL="https://security.example.net/apf/glob_allow.rules"
GD_URL="https://security.example.net/apf/glob_deny.rules"
SET_REFRESH="10"
The example host is a placeholder. A production feed needs restricted publishing access, change review, TLS validation, monitoring, and a recovery copy. Global allow deserves the strictest control because APF checks TGALLOW before local and global deny chains and before remote block lists. One mistaken line can allow an address that a later control was expected to block.
Global rule file format
The official glob_allow.rules template and glob_deny.rules template use the same line-oriented syntax. Their effect is different: a rule downloaded into TGALLOW grants the matching traffic, while a rule downloaded into TGDENY blocks it.
A bare IPv4 address, IPv4 CIDR, or IPv6 address applies to the host or network generally:
# one IPv4 address
198.51.100.25
# one IPv4 network
198.51.100.0/24
# one IPv6 address
2001:db8::25
In glob_allow.rules, a bare entry is broad trust. Use it only when that source should bypass later deny, block-list, and normal port-filter checks. In glob_deny.rules, a bare entry is a broad block. When the requirement concerns one service or direction, use the advanced format instead:
proto:flow:[s/d]=port:[s/d]=ip(/mask)
The fields describe protocol, packet direction, source or destination port, and source or destination address. For example, a centrally managed allow file can grant one administration source access only to inbound TCP port 22:
# CHG-142: administration VPN, review 2026-09-01
tcp:in:d=22:s=198.51.100.25
A global deny file can block inbound access to a database port from one network without denying every other conversation with that network:
# Block inbound database probes from this reviewed network
tcp:in:d=3306:s=203.0.113.0/24
Plain IPv6 addresses work as bare entries. In advanced syntax, wrap the IPv6 address or prefix in brackets so its colons are not confused with the rule-field separators:
tcp:in:d=443:s=[2001:db8:1200::/48]
Keep one rule per line. Use comments to record ownership, reason, approval, and review or expiry date. Publish plain text, and replace the remote file atomically so a refresh never downloads a partially written policy. Review both files together because an allow match is evaluated before a deny match.
After enabling global trust, validate and refresh it without waiting for the next interval:
sudo apf config validate
sudo apf -e
sudo apf status
sudo apf -g 198.51.100.25
Use a known documentation or test address only in a non-production feed. In production, search for an exact approved address and an exact denied address, then test the real traffic path from both sources.
Large lists with ipset
The newer ipset.rules subsystem is a better model for large feeds because one iptables rule can reference a kernel hash set instead of adding one firewall rule per address. The installed APF cron calls apf --ipset-update hourly. The default IPSET_REFRESH="21600" makes a list with no per-list interval eligible every six hours, while the hourly cron sets the minimum effective check interval.
You can request an immediate hot reload without restarting the complete firewall:
sudo apf --ipset-update
sudo apf ipset status
sudo apf status
Automatic refresh is powerful because it removes repetitive manual work. It also turns DNS and remote feeds into live firewall dependencies. Monitor download failures, resolution failures, unexpected entry-count changes, and the age of the last successful refresh.
Treat automated blocking as a control
Reactive Address Blocking, remote lists, GeoIP policy, connection limits, and SYN rate controls can reduce noise and contain obvious abuse. They can also block valid traffic when thresholds or data sources do not match the application.
- Start in an observable mode and measure what would be blocked.
- Keep administrative and health-check sources narrowly exempted where justified.
- Set an owner and expiry for temporary blocks.
- Monitor the structured audit log at
/var/log/apf/audit.logand the main APF status log. - Test failover addresses, proxies, NAT gateways, mobile users, and IPv6 separately.
Country filtering is not an identity control. IP geolocation can be stale or ambiguous, and legitimate users may arrive through VPNs, mobile networks, or global services. Use country rules only when the business requirement and false-positive response are clear.
Containers need a separate test plan
Docker, Podman, Kubernetes components, and network plugins may create their own iptables chains, forwarding policy, NAT rules, and address sets. APF's current DOCKER_COMPAT="auto" mode attempts to preserve external chains and container networking during an APF flush. It also disables APF fast-load snapshots when compatibility mode is active.
That feature improves coexistence, but it cannot prove every CNI, proxy, published port, overlay, or service route remains correct. Stage the change on a representative node. Test host ingress, published container ports, service-to-service traffic, outbound NAT, DNS, health probes, and workload restart behavior. For platform-wide firewall and deployment work, see our DevOps Services.
Upgrade an existing APF installation safely
A server still using APF 1.7.5 should be treated as a migration, not a routine package refresh. The modern installer backs up the existing APF directory, and the included importconf utility can carry recognized values into the new configuration while leaving new variables at current defaults. That is helpful, but it does not make the old policy correct.
- Export the active IPv4 and IPv6 rules and copy the complete old APF directory.
- Inventory interfaces, listeners, source restrictions, outbound dependencies, containers, and startup methods again.
- Read every release note between the installed and target versions.
- Import the old configuration into a fresh current template.
- Diff the result and review each carried value, especially modules, ports, interfaces, IPv6, sysctl, remote lists, and hooks.
- Test in development mode with console recovery and two administration sessions.
- Remove the old startup method after the systemd path is verified.
Start from the configuration template shipped with the target release. Imported values still need individual review because a prior file may omit current safety, IPv6, container, audit, GeoIP, or connection-control settings.
Troubleshooting
| Symptom | Likely area | Useful evidence |
|---|---|---|
| A new SSH session fails | Wrong port, interface, source rule, address family, or another firewall manager | ss -lntup, route, APF config, active rules, console test |
| Rules disappear after five minutes | DEVEL_MODE is still enabled | APF config, cron entry, status and audit logs |
| Rules disappear after reboot | Startup unit is disabled, failing, or competing with another loader | systemctl status apf, boot journal, enabled units |
| IPv4 works but IPv6 fails | USE_IPV6, IPv6 port policy, route, or ICMPv6 behavior | IPv6 address and route, ip6tables -S, external IPv6 test |
| Containers lose network | Compatibility detection, forwarding, NAT, CNI, or restart order | Runtime chains before and after APF start, workload and service tests |
| Application can receive but not call dependencies | Outbound filtering is incomplete | Destination, protocol, DNS, route, APF egress rules, application logs |
| Expected host is blocked | Trust order, remote list, GeoIP, RAB, or temporary rule expiry | apf trust lookup, apf -g, audit log, source address |
| Dynamic DNS points to a new address but access fails | The updater, DNS answer, SET_REFRESH, MD5 optimization, or address family | getent ahosts, apf -e, APF status and audit logs |
| Global trust file is stale | USE_RGT, URL, TLS, DNS, file format, or refresh failure | Configured URL, downloaded file, refresh log, expected entry search |
Remote block list is stale after apf -e | Classic DLIST_* feeds need a full start or restart; they are not trust chains | APF restart log, downloaded list timestamp, active chain and entry count |
Operating checklist
- One named firewall manager owns the host policy.
- The current rules, APF configuration, and recovery path are backed up.
- The untrusted interface and every listening service were discovered from evidence.
- IPv4 and IPv6 were both reviewed.
- Development mode remained enabled through a second-session test.
- Container and application traffic was tested from outside the host.
- Dynamic DNS names resolve to the intended IPv4 and IPv6 addresses, and automatic trust refresh is monitored.
- Global trust and remote-list publishers are controlled, reviewed, and recoverable.
- Automated lists and blocking thresholds have owners, logs, and false-positive procedures.
- Persistence was tested through one supported startup method.
- The change record includes rollback, validation, and the next review date.
APF is useful when its policy model matches the way a team operates Linux servers. It is not useful merely because it can generate many rules. A good deployment has one owner, narrow intent, visible evidence, a recovery console, and a test that proves both allowed and denied traffic behave as designed.
Official sources
- R-fx Networks: Advanced Policy Firewall project
- R-fx Networks: APF 2.x documentation
- R-fx Networks: APF source repository
- R-fx Networks: current conf.apf template
- R-fx Networks: global allow template
- R-fx Networks: global deny template
- R-fx Networks: APF releases
- R-fx Networks: APF changelog
- firewalld documentation
- Netfilter project: nftables documentation
- Duck DNS: dynamic DNS update specification


