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-run is 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-password and backup key create.
  • Exit codes: 0 success · 1 error (work interrupted) · 2 work pending / findings · 3 precondition 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.
E-mail 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):

  1. sudo adactl status — exit 0 means nothing pending; note the schema and rollback base lines and free disk.
  2. sudo adactl verify.
  3. Take an encrypted full backup: sudo adactl backup full --passphrase-file /root/backup.pass (copy it off the server).
  4. 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.
  5. 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:

  1. Preconditions: root, healthy stack, Docker Compose ≥ 2.24, free disk for the images and for the release archive.
  2. 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/adactl is re-pointed to the new tool.
  3. Images are loaded and verified against the manifest; nothing is switched yet.
  4. The database migrations the new image will apply are counted. If at least one exists, a full backup is mandatory (the --passphrase-file is required; there is no skip flag). If they cannot be counted, the upgrade stops.
  5. The kit is laid over the installation; .env (except ADA_VERSION), secrets/ and agent packages are never touched.
  6. Agent packages, ADA_VERSION, one up -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).