CSF + LFD firewall lifecycle

CSF (ConfigServer Security & Firewall) and LFD (Login Failure Daemon) are BOA's host firewall layer. CSF handles all host-level firewalling on BOA — the Proxmox firewall daemons are explicitly disabled in BOA's bare-metal deployment. The lifecycle functions live in lib/functions/firewall.sh.inc.

What CSF + LFD do

  • CSF — packet-level firewall (iptables wrapper). Manages inbound/outbound rules, port-knocking, SYN-flood, port scans, etc.
  • LFD — log-watching daemon. Tails system and application logs for repeated failed logins and reports to CSF for IP blocking.

The pair installs together. BOA bundles and configures both with opinionated defaults appropriate for a multi-Aegir hosting host.

Auto-install

CSF auto-installs in PUBLIC mode regardless of _XTRAS_LIST — you do not have to explicitly request it. In LOCAL mode CSF does not install (workstation use; the dev VM has the host firewall instead).

CSF lifecycle functions in firewall.sh.inc

Function Purpose
_csf_install First-time install + initial rule set
_csf_lfd_install_upgrade Upgrade CSF/LFD to current versions
_fix_lfd_uidignore Whitelist system UIDs in /etc/csf/csf.uidignore
_fix_lfd_whitelist Manage the CSF allow-list of trusted IPs
_ensure_ipset_symlinks Ensure ipset integration is wired
_csf_lfd_gateway_allow Whitelist the host's own default gateway
_add_ip_if_missing Idempotent add of a specific IP to the allow list

These run during barracuda install and barracuda upgrade — operators do not invoke them directly.

Nginx Abuse Guard integration

BOA wires CSF into the Nginx Abuse Guard — the Nginx-side detection of DoS-like request patterns. The pipeline is not LFD-driven: dedicated BOA monitor scripts score offenders from the access log and feed CSF, and the resulting CSF state is mirrored back into Nginx so banned IPs are dropped at the edge.

The flow:

  1. scan_nginx.sh scores each realip client IP from the Nginx access log and writes offenders to /var/xdrago/monitor/log/web.log (plus an archive log).
  2. guest-fire.sh reads web.log and applies a temporary block — csf -td <ip> 900 -p 80 (and -p 443), i.e. a 15-minute (900 s) deny on the web ports. It first clears any IP already allowed in csf.allow on port 80, so an allow-listed operator is never web-banned.
  3. guest-water.sh escalates repeat offenders from the archive: an IP seen ≥12 times gets a persistent csf.deny; at ≥24 it is denied with the do-not-delete marker so the block survives the normal rotation cleanup.
  4. nginx_deny.sh regenerates the $is_banned geo set from the current CSF state, so the next request from a banned IP is dropped at Nginx with 444 — even when the client arrives behind Cloudflare (the geo lookup uses the recovered realip). CSF is IPv4-only, so an IPv6 web offender is instead banned at the Nginx layer by nginx_deny6.sh into the same $is_banned geo (see Abuse Guard) — an IPv6 client can only reach the origin via the trusted realip proxy.

Because the geo file is a derived mirror of CSF, fully regenerated each pass, bans self-expire without manual cleanup. The full data flow, scoring detectors and self-cycling behaviour are documented in the Abuse Guard topic — this page only summarises where CSF sits in the loop. The _NGINX_DOS_* tunables are on the security model page.

/root/.hr.monitor.cnf enables a more aggressive mode — recommended on hosts attacked by spambots / fake-UA crawlers.

BOA CSF tuning defaults

BOA ships an opinionated csf.conf tuned for large-scale attack resilience. The non-stock default that matters most for the ban loop:

  • DNS reverse-lookup checks are disabledLF_LOOKUPS="0", CC_LOOKUPS="0", ST_LOOKUP="0". Reverse DNS inside CSF's connection-tracking path adds measurable latency to the block decision during large-scale attacks, so BOA turns it off.

The stock CSF recidivism control LF_REPEATBLOCK is left at "0" (disabled) — BOA does not use CSF's built-in repeat-offender escalation. The "≥24 hits → do-not-delete" escalation described in the ban loop above is implemented in guest-water.sh (its archive-hit threshold), not in csf.conf; do not look for a recidivist setting in the shipped config. Operator hand-edits to /etc/csf/csf.conf are preserved across upgrades by mergecsf (below).

Migration-proxy trust

During an xmass/xoct migration the old host becomes a trusted reverse proxy forwarding all sites to the new host. BOA trusts that proxy at two layers, driven by control files so trust is removed cleanly when the migration ends:

  • L4 (CSF/lfd)migration_proxy_trust.sh hard-whitelists the proxy IP(s): added to csf.allow on ports 80 and 443 plus csf.ignore, applied immediately (csf -r) and persisted to /root/.migration.proxy.ips.cnf so the *-water.sh ticks re-assert them across reloads.
  • L7 (Nginx realip)migration_proxy_realip.sh emits set_real_ip_from <proxy-ip> lines (a .cmig sibling of the Cloudflare realip include) from /data/conf/.migration_proxy_trust.cnf so the new host recovers the real client behind the proxy hop.

Both layers fail closed. Their CIDR validators reject 0.0.0.0/0, any /0 prefix, and any 0.0.0.0/* host, so a stray control-file line can never trust the whole internet. An empty or all-invalid control file is treated as teardown — the include and CSF entries are removed rather than left stale. Use --csf-only on the old/proxy host (it needs only to never ban the new host) and --permanent to keep a proxy in service indefinitely. Cross-link: Migration & cloning.

Shared nginx-config reload lock

The BOA nginx-config generators — ip_access.sh, user_admin_access.sh, cloudflare_realip.sh, nginx_deny.sh, nginx_deny6.sh, ai_policy.sh and migration_proxy_realip.sh — hold a shared advisory lock /run/boa_nginx_config.lock (flock -w 30) so their nginx -t plus reload operations never overlap and race. A generator that cannot grab the lock within 30 s skips and retries on its next tick. Full detail in the Abuse Guard topic.

Operator commands

# Show current CSF status + summary
csf -l            # list rules
csf -d 1.2.3.4    # add IP to deny list
csf -dr 1.2.3.4   # remove from deny list
csf -a 1.2.3.4    # add to allow list
csf -ar 1.2.3.4   # remove from allow list
csf -tf           # flush temp blocks
csf -df           # flush deny list
csf -r            # restart firewall

# LFD status
lfd -s            # show LFD status
service lfd restart

For a comprehensive reference, man csf and man lfd.

Recover access if your own IP got blocked

The most common operator emergency — your IP got blocked and you cannot SSH in.

If you still have an active SSH session that is not blocked yet (another window, another IP, jump host):

csf -dr <your-blocked-ip>
csf -a <your-blocked-ip>

If you have lost SSH entirely, your options are VNC/console access via your provider's web panel, or out-of-band recovery if your provider offers it.

To proactively whitelist your home IP (so you can never block yourself):

# Add to /etc/csf/csf.allow
echo "203.0.113.42 # operator home IP" >> /etc/csf/csf.allow
csf -r

Whitelisted ≠ exempt from LFD

A whitelist allows packet flow but does not exempt an IP from LFD login-failure tracking. If your whitelisted IP is generating brute-force-pattern auth failures, LFD will still block it. Practical implication: scripted SSH attempts from a whitelisted IP that misconfigure their key or username repeatedly still get blocked. The whitelist is not a get-out-of-jail-free card.

mergecsf — config merging tool

aegir/tools/bin/mergecsf merges operator-customised CSF config with BOA-provided defaults on upgrade. Operators do not invoke it directly; it runs as part of barracuda upgrade. If you have hand-edits to /etc/csf/csf.conf, mergecsf preserves them across BOA upgrades.

Disabling CSF temporarily

csf -x   # Stop CSF
csf -e   # Re-enable

Use only for short windows (testing, troubleshooting). The host is unprotected during the disable window.

Related