Skip to content

Powered by Grav

Monitor & abuse-guard internals (code)

Monitor & abuse-guard internals (code)

The runtime tier of BOA at code level: the cron-driven watchdogs, the abuse-guard ban pipeline, the nightly maintenance sweep, and the trust boundary they all sit on.

The runtime tier of BOA: the scripts that live under /var/xdrago/ on a deployed box and run on cron, not the installer that put them there. Everything in this topic is Barracuda-side bash in boa-private (aegir/tools/system/, mirrored to /var/xdrago/ at build time) plus the one PHP boundary that guards the backend user — the Drush extension deny-filter in the omega8cc Drush 8 fork.

It is deliberately not the operator's how-to: those pages read live state and cite defaults; these pages are for the maintainer changing the script.

If you touch a monitor/check/*.sh, the ban pipeline, owl.sh / the night/ workers, or boa_extension_filter.inc, this is the execution model your change lands in.

Two clocks and one privilege boundary organise the whole tier:

  • the per-minute clocksecond.sh + minute.sh, each a one-line crontab entry, fan a set of monitor/check/*.sh watchdogs out several times a minute;
  • the nightly clock — one crontab entry (owl.sh) drives a per-account / per-site maintenance sweep that drops privilege to each tenant's user;
  • the trust boundary — every one of these runs as root or as aegir/oN, reads tenant-writable paths and tenant-supplied Drush aliases, and must never let tenant input escalate. The abuse-guard, the path validators and the extension filter all sit on that line.

The deployed tier in one pass

Nothing here is loaded from the build tree at runtime. _xdrago_install_upgrade() (lib/functions/system.sh.inc:9152) cp -afs the entire aegir/tools/system/* tree into /var/xdrago/ and installs cron/crontabs/root into /var/spool/cron/crontabs/root (system.sh.inc:9179, :9203, :9240) — so on a box every path below is /var/xdrago/..., and the crontab is the single source of truth for what runs when.

TXT
/var/spool/cron/crontabs/root  (from aegir/tools/system/cron/crontabs/root)
   ├─ * * * * *  second.sh ──▶ _proc_control fan-out (12 watchdogs)   [1 deploy surfaces]
   │                         └▶ hackcheck.sh · hackftp.sh · escapecheck.sh (SSH/FTP IDS)
   ├─ * * * * *  minute.sh  ──▶ _launch_auto_healing × _ITER passes:
   │                            system unbound valkey|redis mysql php
   │                            fpm_tune nginx nginx_guard java
   │                                            │
   │                                            └▶ nginx_guard.sh ──▶ scan_nginx.sh   [2 abuse-guard]
   ├─ * * * * *  guest-fire.sh   web.log ─▶ csf -td 900                    [2 ban pipeline]
   ├─ 01 5 …     guest-water.sh  archive ─▶ csf.deny (_NR_TEST ≥12/≥24)    [2 ban pipeline]
   ├─ */2 …      ip_access.sh · user_admin_access.sh · ai_policy.sh ·
   │             nginx_deny.sh · nginx_deny6.sh                            [2 / 4]
   ├─ */3 …      manage_ltd_users.sh   (per-user FPM pool, jailed shells)  [4 security model]
   ├─ * * * * *  runner.sh   (Aegir task queue drain)
   └─ 15 4 …     owl.sh ──▶ night/night.inc.sh + 90-global-post.sh         [3 nightly worker]
                     └▶ per account: night/10-account.sh ──▶ night/20-sites.sh
                          (su -s /bin/bash - <HM_U>  → drush8 @<site>)     [3 / 4]
  • [1] Deploy surfaces. second.sh and minute.sh are the fan-out engines. minute.sh classifies the box (_monitor_box_classCI/SLOW/NORMAL) and loops _launch_auto_healing _ITER times spaced _SLEEP seconds apart (default NORMAL = 9×5 s, minute.sh); second.sh runs _proc_control, the twelve service watchdogs split out of the legacy proc_num_ctrl.pl, plus the SSH/FTP IDS scanners. There are 27 monitor/check/*.sh on disk; only the dispatched subset actually runs each tick.
  • [2] Abuse-guard. nginx_guard.shscan_nginx.sh is the web IDS; the detection→ban→enforce pipeline (scan_nginxweb.logguest-fire.shguest-water.shnginx_deny.sh → the $is_banned geo) is the same mechanism the operator guide documents, re-read here at code level: the run model, the detector functions and the escalation arithmetic.
  • [3] Nightly worker. owl.sh is a single-threaded (optionally _NIGHT_PARALLEL) orchestrator that sources night/night.inc.sh (the shared Tier-0 helper library) and night/90-global-post.sh, then invokes night/10-account.sh as a subprocess per /data/disk/* account, which in turn drives night/20-sites.sh per site. The split exists so one copy of the drush8 wrappers and chattr helpers is shared, not duplicated.
  • [4] Security model. The cross-cutting boundary: the anti-lockout allow logic in ip_access.sh, the _validate_safe_dir path gate the night workers run before any tenant-derived chown/chmod, the per-user FPM disable_functions injection in manage_ltd_users.sh, the chattr +i immutability locks, and the one PHP boundary — boa_extension_filter.inc, which stops tenant-dropped *.drush.inc from auto-loading as a privileged backend identity.

Each leaf below zooms into one of these boxes.

Adjacent developing topics

  • Install & staged-setup internals — how aegir/tools/system/* and the crontab get onto a box: the staged AegirSetup* engine and the _xdrago_install_upgrade() path in system.sh.inc that this topic's deploy surfaces assume already ran.
  • Web & search stack internals — the Provision Nginx templates (server.tpl.php edge maps, vhost_include.tpl.php guard chain) that emit the 444s and access.log lines scan_nginx scores, and the $is_banned geo the ban pipeline feeds back into.
  • Ægir backend APIs — the Drush 8 fork whose preflight.inc loads the extension filter, and the Provision/Hosting backend the nightly drush8 @<site> calls drive.
  • Build & test — verifying a change to any of these scripts: a rebuild is the only path that re-runs _xdrago_install_upgrade and lands the edit on a box.

Reference

  • Variables and Commands — the consolidated _VAR and CLI tables, including the _NGINX_* abuse-guard knobs, _MONITOR_FANOUT_*, _NIGHT_*, _INCIDENT_REPORT, _PHP_FPM_DENY and the csf verbs cited throughout this topic.
  • Discontinued features — retired monitor scripts and superseded ban/escalation mechanics land there; check it before documenting anything found only in old trees, CHANGELOG.txt history, or the legacy docs/ctrl/*.ctrl reference files (several of those markers — e.g. .no.sql.cpu.limit.cnf, .ip.protected.vhost.whitelist.cnf — have zero live readers and must not be presented as current).

© 2026 BOA Documentation. All rights reserved.