16.6 Server operations
16.6.1 adactl
adactl is the operations tool installed on the server
(/usr/local/sbin/adactl, installation directory
/opt/ada-classification by default). Run it with
sudo. Every command accepts --help.
Design rules you can rely on:
- Measure first, then change. Destructive commands
list what they will do and ask you to type the server’s host name;
--dry-runis available on every destructive command. - No secrets on the command line or screen. Passwords
and passphrases are read from 0600 files (
--password-file,--passphrase-file). Only two commands print a secret, on explicit request:admin initial-passwordandbackup key create. - Exit codes:
0success ·1error (work interrupted) ·2work pending / findings ·3precondition or usage error — nothing was changed.
| Task | Command |
|---|---|
| What is installed and running, pending work (licence missing, backup key missing, first password not changed …) | sudo adactl status [--json] |
Installation health (permissions, compose, five services,
/healthz, schema, agent packages, watchdog, hardening
profile) |
sudo adactl verify [--json] |
| First-boot admin password (shown once) | sudo adactl admin initial-password |
| Licence | sudo adactl license request ·
license install <license.lic> --accept-eula <version> [--password-file <f>]
· license status |
| TLS certificates | sudo adactl cert csr --scope admin\|client --password-file <f>
· cert install <cert.pem> --password-file <f> ·
cert import --cert <pem> --key <pem> --password-file <f> [--chain <pem>] |
| Agent enrolment token | sudo adactl token show [--out <file>] (writes to
a 0600 file; logged as setup_token_viewed) ·
token rotate [--grace <days>] (default 14; enrolled
agents unaffected) |
| Full backup without a console session | sudo adactl backup full --passphrase-file <f> [--out <dir>]
(default /var/backups/ada) |
| Backup key | sudo adactl backup key create |
| Internal root CA | sudo adactl ca status ·
ca backup --passphrase-file <f> ·
ca restore <file> --passphrase-file <f> ·
ca rotate --passphrase-file <f> |
| Host-side support bundle | sudo adactl support [--out <file.tar.gz>] [--lines N] |
| Hardening baseline (read-only) | sudo adactl harden [--json] [--modules <list>] [--list] |
| Upgrade / rollback | sudo adactl upgrade <release-dir> --passphrase-file <f>
· sudo adactl rollback [<version>] |
| Container logs | sudo adactl logs [ada-api\|ada-web\|ada-db\|ada-docker-guard\|ada-ml] [--lines N] |
| docker compose in the right project | sudo adactl compose -- <args> |
| Outbound integrations | sudo adactl integrations [status] ·
integrations start\|stop smtp\|syslog\|directory (restarts
the API; refuses to start an unconfigured integration) |
| SSH welcome screen | sudo adactl motd show\|remove\|install |
| Remove | sudo adactl uninstall (keeps data volumes) ·
uninstall --purge --passphrase-file <f> (destroys all
data after writing an encrypted recovery archive) ·
purge-volumes ·
factory-reset --yes-i-lose-the-root-ca |
| Hand-made installation | sudo adactl adopt <dir> [--dry-run] |
16.6.2 Support bundles: console vs host
| Console ⬇ Support bundle (section 16.1.6) | sudo adactl support |
|
|---|---|---|
| Needs | Administrator session | Root on the host; works when the console is down |
| Contents | Server status, System journals, container log tails, redacted configuration, agent inventory, audit counts | OS/clock/disk/RAM, Docker and compose versions and state, container
inspect summaries (environment variable names only),
container log tails, .env key names with masked values,
secrets/ permissions, network listeners,
/healthz, /api/version,
/api/status, factory-clean report, watchdog state and
journal |
| Output | zip | ada-support-<host>-<date>.tar.gz
(0600) |
| Redaction | Key-based + known secret values | Key-based + known secret values (needs sudo for the
value layer; otherwise it says value layer: degraded) |
For a single agent, request diagnostics from the agent’s detail panel on Agents; the agent uploads a zip that the server keeps (last 3 per agent, 30 days).
16.6.3 Host watchdog
All in-product health checks and alerts run inside the API server. If
the API itself dies or hangs, the host watchdog is what
notices. It is a systemd timer on the host
(ada-watchdog.timer, every minute), installed by the
standard installation; it needs only curl and the Docker
CLI.
| Aspect | Behaviour |
|---|---|
| Check | Calls https://127.0.0.1/healthz and classifies: API
down, web down, database unreachable, starting, Docker down. |
Uses the SMTP settings from Settings → Email,
mirrored automatically into the data volume (readable while the API is
down; last good copy cached). ADA_WATCHDOG_SMTP_* in
.env overrides the mirror. |
|
| When | First mail after 3 consecutive failing checks, a reminder every 120
minutes while down, one RECOVERED mail. Tunable:
ADA_WD_FAILS_BEFORE_ALERT,
ADA_WD_REMIND_MIN. |
| Self-heal | On by default (ADA_WD_AUTOHEAL): restarts
ada-api, ada-web or
ada-docker-guard when the container is exited or unhealthy,
at most once per 15 minutes per service
(ADA_WD_HEAL_WINDOW_MIN). Never touches the database, and
never restarts the API while the database is unreachable. |
| Console | The Host Watchdog row on Status (section 16.1.3). |
| Verify on host | systemctl list-timers ada-watchdog.timer ·
journalctl -t ada-watchdog -n 5 |
| Install manually | sudo sh deploy/watchdog/install-watchdog.sh (in the
installation directory) |
adactl upgrade and adactl rollback pause
the watchdog for the whole run and start it again on every exit
path.
16.6.4 Upgrading the server
Upgrade the server before the agents. The supported
path is adactl upgrade.
Before you start (about 5 minutes):
sudo adactl status— exit 0 means nothing pending; note the schema and rollback base lines and free disk.sudo adactl verify.- Take an encrypted full backup:
sudo adactl backup full --passphrase-file /root/backup.pass(copy it off the server). - Make sure a root-CA backup taken since installation or the last
rotation exists off the server; if not,
sudo adactl ca backup --passphrase-file /root/ca.pass. - Read the release notes.
Upgrade:
tar -xf ada-release-<version>.tar
sudo adactl upgrade ./ada-release-<version> --dry-run
sudo adactl upgrade ./ada-release-<version> --passphrase-file /root/backup.pass
Add --yes for unattended runs. The tool works in
measured steps:
- Preconditions: root, healthy stack, Docker Compose ≥ 2.24, free disk for the images and for the release archive.
- The whole release package is copied to
/var/lib/ada/releases/<version>/(rollback reads it, so no external files are needed later) and/usr/local/sbin/adactlis re-pointed to the new tool. - Images are loaded and verified against the manifest; nothing is switched yet.
- The database migrations the new image will apply are counted. If at
least one exists, a full backup is mandatory (the
--passphrase-fileis required; there is no skip flag). If they cannot be counted, the upgrade stops. - The kit is laid over the installation;
.env(exceptADA_VERSION),secrets/and agent packages are never touched. - Agent packages,
ADA_VERSION, oneup -d, health wait.
Exit 3 means nothing was changed. If anything fails, the
exact rollback command for this server is printed.
Verify (about 3 minutes):
sudo adactl status, sudo adactl verify,
readlink -f /usr/local/sbin/adactl (must point into the new
release directory), curl -sk https://127.0.0.1/healthz →
{"status":"ok"}. In the console, check
Status (version, DB schema, agents online) and the
Audit Log chain badge.
Rollback:
sudo adactl rollback [--dry-run] restores the previous
version from /var/lib/ada/releases/. It first compares the
database schema with the target image; if the database has migrations
the older image does not know, the rollback is refused
and the restore path (restore the pre-upgrade .adabk into
the older version) is printed instead.
16.6.5 Verifying the audit chain from the host
The console verifies the chain on every Audit Log load. On a server without a licence (where the API returns HTTP 423), verify from inside the container:
sudo adactl compose -- exec ada-api node dist/cli-audit-verify.js --json
Exit codes: 0 chain intact · 2 chain broken
(integrity finding, also appended to
audit-verify-findings.log) · 1 could not be
measured (fix the environment and retry — this is not an integrity
finding) · 3 usage error.
16.6.6 Host hardening
sudo adactl harden measures the host against controls
H-01 … H-25 (mapped to CIS Ubuntu and CIS Docker;
modules such as container, apparmor, firewall, auditd, journald, sshd,
apt, perms, time, docker, sysctl, db, tls, backup) and prints the fixing
command for each finding. It changes nothing. Exit
2 means “there are findings”, not “the installation is
broken”; on a stock Ubuntu host several warnings are host-policy
decisions for your organisation.
Applying is a separate, deliberate step through
deploy/harden.sh in the installation directory:
| Command | Effect |
|---|---|
sudo sh deploy/harden.sh --apply --dry-run |
Print the plan; write nothing. |
sudo sh deploy/harden.sh --apply |
Apply 8 controls (auditd rules, journald persistence, apt, file
permissions, time sync, Docker daemon.json, sysctl, backup
directory) with a rollback journal and a dead-man timer. |
sudo sh deploy/harden.sh --confirm <run-id> |
Cancel the dead-man timer after you have proven you can still sign in. |
sudo sh deploy/harden.sh --revert |
Undo the last run. |
sh deploy/harden.sh --recipe --modules sshd,firewall --mgmt-cidr <cidr> |
Print a runbook for the controls that are deliberately not automated (SSH, firewall, binding port 9443 to a management network). |