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:
scan_nginx.shscores each realip client IP from the Nginx access log and writes offenders to/var/xdrago/monitor/log/web.log(plus an archive log).guest-fire.shreadsweb.logand 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 incsf.allowon port 80, so an allow-listed operator is never web-banned.guest-water.shescalates repeat offenders from the archive: an IP seen ≥12 times gets a persistentcsf.deny; at ≥24 it is denied with the do-not-delete marker so the block survives the normal rotation cleanup.nginx_deny.shregenerates the$is_bannedgeo set from the current CSF state, so the next request from a banned IP is dropped at Nginx with444— 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 bynginx_deny6.shinto the same$is_bannedgeo (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 disabled —
LF_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.shhard-whitelists the proxy IP(s): added tocsf.allowon ports 80 and 443 pluscsf.ignore, applied immediately (csf -r) and persisted to/root/.migration.proxy.ips.cnfso the*-water.shticks re-assert them across reloads. - L7 (Nginx realip) —
migration_proxy_realip.shemitsset_real_ip_from <proxy-ip>lines (a.cmigsibling of the Cloudflare realip include) from/data/conf/.migration_proxy_trust.cnfso 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
- Security model — CSF is protections #4 and #5 in the
built-in model, plus the
_NGINX_DOS_*tunables. - SYNPROXY DDoS protection — the SYNPROXY layer between the TCP stack and CSF.
- Abuse Guard (nginx IDS) — the scan_nginx scoring and ban pipeline CSF feeds.
- Troubleshooting — blocked-IP recovery how-to.