Operation and Maintenance
Operation and maintenance
Service commands
Each role installs a different set of units. The standard systemd verbs apply to all of them:
The units, depending on role: axiom-border, axiom-influxdb, containerd, oda-lite.
Where the logs live
This is the single most useful thing to know when something misbehaves, because the important detail is not in the journal:
| Service | Journal | Own file | Rotation |
|---|---|---|---|
axiom-border |
systemd events and early startup errors only — with the shipped default, very little | /opt/axiom-border/logs/axiom-border.log — all the detail: probes, MQTT, scans, rules |
Automatic, tunable in configuration.yaml |
axiom-influxdb |
Everything: startup, crashes, slow queries, compactions | None | journald drop-in: 500 MB, 1 day per file |
containerd |
Everything: runtime, namespaces, OCI errors | None | journald drop-in |
oda-lite |
Startup, crashes and early warnings only — 3 to 5 lines in normal operation | /var/log/oda-lite/oda-lite.log — plugin activity, HTTP errors towards central, emitted metrics |
Automatic: every 24 h or at 100 MB, 7 archives kept |
| Lifecycle scripts | — | /var/log/axiom-border-install.log — install, upgrade and uninstall appended together |
Not rotated; clear it by hand if it grows |
The rule of thumb
To diagnose application logic, read the file. To diagnose a crash or a failure to start, read
the journal. Looking for probe results in journalctl is the most common wasted hour.
Everything at once, which is often what you want:
Log levels
Axiom Border — the logger block of configuration.yaml. Set logLevel to DEBUG, INFO, WARN
or ERROR, then restart the service. See Configuration.
oda-lite agent — /etc/oda-lite/oda-lite.conf, [agent] section: log_level and debug. Restart
the service afterwards.
InfluxDB and containerd — the level comes from binary flags in the unit file. Changing it means editing the unit, and is not recommended.
Turn DEBUG back off
DEBUG on a busy probe generates enough volume to fill a disk. Raise it to reproduce a problem, then
put it back to INFO. Do not leave it on “just in case”.
Rotation and disk usage
Axiom Border’s own log rotates through the logger settings: maxSize (MB per file, default 20),
maxBackups (default 20) and compress (gzip the rotated files).
The journald drop-in installed by the bundle is global — SystemMaxUse=500M and MaxFileSec=1day
apply to the entire host journal, not only to Axiom Border. On a host sharing other workloads, adjust it
or replace it with per-unit drop-ins.
To see what is consuming space:
Backup and restore
| Resource | Path | Suggested frequency |
|---|---|---|
| Configuration | /opt/axiom-border/config/configuration.yaml |
On every change |
| Local state — rules, aliases, executions | /opt/axiom-border/db.dat |
Daily |
| InfluxDB data — metrics, alarms | /var/lib/influxdb2/ |
Per retention policy |
| Logs | /opt/axiom-border/logs/ |
On demand |
Stop the service first, for a consistent snapshot:
Restore is the inverse:
Offline maintenance
Refreshing the web and CVE vulnerability templates
The OT/ICS suite ships with the product and needs no maintenance. The web and CVE templates do, and on
an air-gapped probe the refresh is manual: generate a snapshot of the upstream nuclei-templates tree
on a machine with internet, transfer it, then swap it in.
Keep .old until you have confirmed a few successful scans, then delete it. Templates are read when the
service starts, so a restart is required after swapping them.
Loading AI images
AI images are not part of the bundle — they are distributed separately as OCI tarballs, and
resources/iaimages/ ships empty as a placeholder.
Upgrading
Extract the new bundle of the same role on the target and run upgrade.sh. It aborts if the bundle
role does not match the installed role — changing role requires uninstall followed by install.
| Flag | Meaning |
|---|---|
--force-conf-regen |
Regenerate the oda-lite configuration from the new template, saving the current one as .bak-<timestamp> |
-h, --help |
Print help and exit |
| Variable | Default | Meaning |
|---|---|---|
HEALTHCHECK_RETRIES |
12 | Attempts before declaring failure |
HEALTHCHECK_INTERVAL |
5 | Seconds between attempts — 12 × 5 s gives a 60 s window |
AXIOM_API_PORT |
8083 | API port used for the health check |
What it does: verifies the previous installation and role match, stops the role’s services (leaving
InfluxDB and containerd running, so data in flight is not disturbed), takes timestamped backups of the
binary and db.dat, replaces the binary and updatable assets, starts the service, and health-checks it.
Preserved across upgrade: config/, db.dat, .influx-creds, parquet/, logs/,
/var/lib/influxdb2/, resources/iaimages/ and the oda-lite configuration.
Replaced: the binary, MIBS/, resources/gojascripts/, vulnscan-templates/, the documentation
and the lifecycle scripts.
Failed upgrades roll back automatically
If the health check fails all 12 attempts, upgrade.sh restores the previous binary, confirms the
old version answers with HTTP 200, and exits with code 2. The probe is left operational on the old
version and the backup is kept at /opt/axiom-border/axiom-border.bak-<timestamp>. An upgrade that
reports a rollback has not broken anything — diagnose, then retry with a corrected bundle.
Back up db.dat before upgrading
The local state file db.dat is not migrated automatically. If a new version changes its format, the
file may have to be regenerated, and that loses local state — rules, aliases and execution history.
Always take a copy before upgrading, and if the new version will not start cleanly, restore the copy and
revert the binary.
Uninstalling
It stops and disables the role’s services, removes only the units it created, removes the journald
and sshd drop-ins, and asks whether to keep the data — InfluxDB data, db.dat, logs and
configuration.yaml. Answer non-interactively with AXIOM_KEEP_DATA=true|false.
It removes shared binaries only where the manifest marks them as installed by this deployment. It does
not remove nmap, rsyslog or network-manager even if it installed them — those are host
infrastructure and are left to the operator. It does not revert the netplan switch by default.
| Variable | Effect |
|---|---|
AXIOM_KEEP_DATA=true|false |
Answers the data-retention question without prompting |
AXIOM_RESTORE_NETPLAN=1 |
Restores /etc/netplan/ from the backup, re-applies it, and switches back to systemd-networkd |
AXIOM_FORCE_CLEAN=1 |
Destructive. Without a manifest, claims every detected artefact as its own — including global binaries that may belong to other software such as Docker or Kubernetes |
Running it on a clean system is safe and idempotent: it reports there is nothing to uninstall and exits 0.
AXIOM_FORCE_CLEAN can remove another product’s binaries
Use it only after confirming nothing else on the host depends on containerd, runc, nerdctl or the CNI plugins. Without the flag, a manifest-less uninstall stays conservative and touches only artefacts that are unmistakably Axiom Border’s.
AXIOM_RESTORE_NETPLAN=1 warns about possible connectivity loss. In practice an established SSH session
usually survives, since the TCP connection is not torn down and the IP is retained — but do not count on
it over a link you cannot recover from out-of-band.
Troubleshooting by symptom
Quick triage
| Symptom | Look here first |
|---|---|
| Service will not start | journalctl -u <service> -n 50 --no-pager |
| Service active but no results | /opt/axiom-border/logs/axiom-border.log |
| Metrics not reaching InfluxDB | journalctl -u axiom-influxdb plus the agent log |
| Monitoring node not reaching central | tail -f /var/log/oda-lite/oda-lite.log | grep "outputs.http" |
| SSH, USB or interface events missing | The agent log, filtering by plugin name |
| Service restart-looping | journalctl -u <service> --since "5 min ago", looking for start-limit |
| Install or upgrade behaved oddly | tail -200 /var/log/axiom-border-install.log |
| Disk filling up | du -sh /var/log/oda-lite /opt/axiom-border/logs /var/log/journal/ |
Detailed cases
The service will not start. Three usual causes: the binary lost its execute bit
(chmod +x /opt/axiom-border/axiom-border), a required port is occupied, or the YAML is invalid.
Validate the configuration directly:
Login fails with the correct password. login.pass must be the SHA-256 digest, not the
plaintext. Recalculate and restart:
A port is in use. Identify the holder, then either stop it or move the Axiom Border port:
Ports 8083, 1883 and 1888 move via apiPort, mqtt.broker.port and mqtt.broker.ws.port. Ports 9090
and 9091 move in /etc/oda-lite/oda-lite.conf.
Vulnerability scans return zero findings, suspiciously. The web template directory is probably empty or incomplete:
It should list per-protocol directories such as http/, network/ and ssl/. CVE templates live under
http/cves/, not at the root. Refresh them as described above. OT/ICS findings are unaffected, because
that suite ships with the product.
Sniffing captures nothing. Check the interface exists (ip -o link show), that the service runs as
root (systemctl show axiom-border -p User), and that there is actually traffic
(sudo tcpdump -i <iface> -c 10).
The UI loads but every API call returns 401. The JWT is missing or expired. Clear the browser’s
localStorage and log in again.
nmap probes hang or take very long. A large target range with poor reachability, a high timeout,
or udp: true with many ports. Narrow the range, lower the timeout, disable UDP.
High memory usage. Check for an AI capability working a large dataset, an Influx bucket with no
retention policy, or logLevel: DEBUG left on.
“Orphaned installation detected.” Bundle artefacts exist without an .install-manifest. Three ways
out: AXIOM_CLEAN_RESIDUALS=1 sudo bash install.sh moves the leftovers aside, sudo bash upgrade.sh
preserves data, sudo bash uninstall.sh cleans best-effort.
upgrade.sh exits with code 2 reporting a rollback. The new binary failed its health check and the
old one is back in service. Diagnose with the journal, the application log and the install log, then
retry with a corrected bundle.
The monitoring node floods the journal with “connection refused” to port 9090. The central node is not up, a firewall blocks it, or the URL is wrong. The agent keeps retrying and buffers metrics while it waits, so a short outage loses nothing — a long one eventually will.
Error executing 'netstat': exit status 1. Minimal Ubuntu Server images lack net-tools. Not
blocking — the other plugins continue:
NetworkManager is active but interfaces show as unmanaged. The netplan renderer was not switched
over. Re-run install.sh --switch-to-network-manager; it detects the current state and completes the
switch without reinstalling NetworkManager.
/etc/oda-lite/oda-lite.conf.new contains literal ${VARIABLE} placeholders. The file is an
unexpanded template. Do not copy it over the live configuration — the agent would not start. Delete
it and re-run the upgrade with the current bundle.
scp or tar -xzf fail with Permission denied in /tmp. Some base images ship /tmp with wrong
permissions. It should be drwxrwxrwt: