Dagda

Dagda admin guide

Users & roles

Dagda has two roles: admin (full access — users, servers, alerts, license, settings) and viewer (read-only access to every server's dashboards). There is no per-server viewer scoping in this version — a viewer sees the whole fleet.

Invites

Admin → Users: fill in the Invite a user form (name, email, role) and click Create invite link. Dagda creates a single-use link valid for 48 hours, emails it if email is configured, and always shows it as a copyable link too. The invitee opens it, scans their own authenticator QR code, and is signed in — no admin ever sees another user's TOTP secret.

Recovery

  • Lost your device? Use one of your 10 recovery codes at sign-in instead of a TOTP code. Each code works once. Regenerate a fresh set any time from your Account page (the Recovery codes panel; you'll need a current TOTP code to do this). If email is configured on this hub, you can also sign in with a one-time code sent to your address instead of a TOTP code.
  • Locked out entirely? An admin can reset your authenticator (on the Users page, the user's Reset authenticator button), which revokes your sessions and current secret and issues you a fresh enrollment link.
  • No admin left with access? From a root shell on the hub:
    sudo dagda user reset <email>
    
    prints a fresh enrollment link. sudo dagda user list shows every user and their status; sudo dagda user add --admin <email> creates a new admin directly; sudo dagda user disable <email> / enable <email> disables or re-enables an account. The last enabled admin can never be demoted or disabled — by the UI or the CLI — so you can't lock yourself out entirely.

Servers

Admin → Servers (admin-only) lists every host in your fleet: add a server (or click Add server on the Fleet overview), rename, disable, remove (revokes its key immediately; its history is kept until normal retention or an explicit purge), rekey, and the enrollment log. sudo dagda hosts lists them from the command line; on an agent, sudo dagda join <hubUrl> <token> performs the enrollment manually if you didn't use the install-script one-liner — then run sudo systemctl enable --now dagda to start it. To keep the token out of your shell history and the process list, pipe it in instead: echo <token> | sudo dagda join <hubUrl> --token-stdin (the first line of standard input is read as the token).

Alerts & channels

Alert thresholds (disk, memory, load, TLS expiry, etc.), notification channels (ntfy, Pushover, Telegram, email) and the off-box heartbeat URL are all configured on Admin → Settings, per hub — agents receive the updated thresholds on their next push. The Alerts & notifications page (open to every signed-in user) shows current alerts, delivery history and a Send test notification button, and explains how to set up each channel. Any admin can opt into receiving alert emails for themselves from their Account page ("Email me when alerts fire"); there is no hardcoded recipient.

License

Install a license from the UI (Admin → License) or:

sudo dagda license install <file>
sudo dagda license show

With no license, Dagda runs a 14-day trial capped at 3 hosts. Licensed or not, monitoring and alerting never stop — an expired license only blocks adding new servers and shows a persistent banner to admins.

Automatic license updates. Renewals, tier changes and the switch from a trial to a paid license arrive on their own: about once a day (hourly while you are on a trial or within 30 days of expiry) the hub asks Old Cart's license server at dagdamonitor.com whether a newer license exists for its license ID, and installs it only if it verifies. It sends the license ID, the issue date of the installed license and a one-time proof that it holds your repository token — never the token itself and never monitoring data. Admin → License shows the last check, a Check now button, and the switch "Install renewed licenses automatically" to turn the daily check off; installing a license file by hand always works. A hub checks on its own schedule once it runs from the package with its dagda setup configuration.

Renewals keep your license ID and repository token, so a new license simply refreshes your hub's own APT credentials — servers you enrolled earlier keep the credentials they were given when they joined and need no changes of their own. A trial hub is upgraded the same way: the paid license reuses the trial's ID and token, so servers added during the trial keep monitoring and keep receiving updates.

dagda license show also names the certificate that vouches for your license (Certificate: C-… (valid until …)). A certificate reaching its end date does not affect licenses it already signed: each license is valid until its own expiry. License files issued before Dagda 0.2.0 (version 1) are no longer accepted; Old Cart re-issues them as version 2 under the same license ID and repository token.

Updates

Dagda ships over a signed APT repository tied to your license. Once a day the hub compares the installed and available package versions; this relies on the host's own periodic apt update (e.g. cron or unattended-upgrades) — the service itself never runs apt update. When a newer version is published, admins see a banner with the exact command to run: sudo apt update && sudo apt install dagda. Any schema change is preceded automatically by a backup (see below) before it's applied. Never apt purge dagda unless you want its configuration and data deleted — apt remove keeps them.

The Old Cart signing key (/usr/share/keyrings/oldcart.gpg) is owned by the dagda package, so a signing-key update arrives as an ordinary package update. apt remove dagda keeps it (with the repository source and credentials, so you can reinstall with apt install dagda); apt purge dagda removes it.

Upgrade the hub first, then your agents. The hub's wire protocol accepts the current version and the one before it, not versions newer than itself — an agent upgraded ahead of its hub can end up speaking a protocol the hub doesn't recognize yet and be refused. If you rely on unattended-upgrades on your agents, either point it at a slower schedule than the hub's, or pause it and upgrade agents by hand shortly after you've confirmed the hub upgraded cleanly.

Undoing an upgrade

sudo apt install dagda=<previous-version> only works when the new version didn't change the database schema (check the CHANGELOG). If it did, the older code can't read a database a newer version has already migrated: restore the automatic pre-migration backup instead — Dagda takes one in /var/lib/dagda/backups before every schema upgrade — with sudo dagda restore <file>. Dagda refuses to start on a database created by a newer version and tells you which backup to restore, so you're never left guessing.

Backups

sudo dagda backup [--out <dir>]

Takes a consistent snapshot of the database plus the files it depends on (/etc/dagda/dagda.toml, /etc/dagda/master.key and the installed license, /var/lib/dagda/license.json), packed as .tar.zst (or .tar.gz if the zstd binary isn't installed), written mode 0600. Without --out, it's written to /var/lib/dagda/backups and the newest 7 are kept automatically. --out is a directory (created mode 0700 if it doesn't exist); the archive gets its usual dagda-backup-<timestamp> name inside it, and backups written there are never rotated. A dagda-backup.timer runs this nightly. The backup only reads the database — it never changes it.

One is also taken automatically before any database schema upgrade (at most one per service start, however many parts of the schema change). If that pre-migration backup fails — most often because the disk is full — the upgrade is not applied and the service does not start until it's fixed: free up disk space in /var/lib/dagda (sudo dagda doctor shows disk usage), then sudo systemctl restart dagda.

Backups, restores and the pre-migration backup never run at the same time: a second dagda backup or dagda restore started while another is running stops straight away with "another dagda backup is running" — just try again once the first one has finished. The pre-migration backup waits up to 10 seconds for the running one; if it's still busy, that start fails and systemd retries it automatically a few seconds later (each retry waits on the lock again), so the upgrade goes ahead once the other backup is done.

When the service does not start

How dagda.service behaves after a failed start depends on the cause (the reason is always the last line of journalctl -u dagda -n 50):

  • Backup lock busy (another backup or restore is running during the pre-migration backup): the start is retried automatically until the lock is free. Nothing to do.
  • Any other pre-migration backup failure, a failed schema migration, or a database created by a newer version of Dagda: the service exits with code 75 and stays stopped (no restart loop) until you fix the cause — free disk space, or restore the backup the message names — and then run sudo systemctl restart dagda.
  • Invalid configuration (/etc/dagda/dagda.toml): exit code 78; the service stays stopped until you fix the file (sudo dagda doctor says what's wrong) and run sudo systemctl restart dagda.

Package installs and upgrades, and dagda restore, check that the service actually came up afterwards. If it didn't, they print a boxed message starting "dagda did not start" (with the address that didn't answer), followed by what to run: sudo dagda doctor and journalctl -u dagda -n 50. Right after an upgrade the service may still be starting because a pre-migration backup is running — check again in a minute before digging in.

Treat backup files as sensitive — they contain your master key, which decrypts every stored secret (sign-in authenticators, notification tokens) — and copy them off this host over a secure channel (e.g. scp to a machine only you control, or an encrypted backup system): a backup stored only on the machine it protects doesn't protect against losing that machine.

sudo dagda restore <file> [--force]

Stops the service, puts the database, config, master key and license back where they came from, and restarts it. Before changing anything it checks the archive thoroughly, and that there is enough free disk space to stage it (at least twice the archive's size plus twice its largest file). It refuses:

  • a hub backup onto an agent (or vice versa), unless you pass --force;
  • a backup made by a newer version of Dagda whose database is ahead of what this version understands — upgrade Dagda first (sudo apt update && sudo apt install dagda), then restore (--force overrides this, at your own risk).

The files it replaces are kept in a pre-restore-<timestamp> folder (mode 0700) inside the data directory — delete it once you've confirmed the restored install works. If anything fails while the files are being put in place, every file is put back exactly as it was.

Restoring onto a new server

To move a hub to a new machine, or rebuild one that was lost:

  1. Install the package on the new server the same way you installed it originally (the install script, or apt install dagda from your licensed repository). Don't run dagda setup yet.
  2. Copy the backup to the new server (e.g. scp it to /root/).
  3. Restore it: sudo dagda restore /root/dagda-backup-<timestamp>.tar.zst. This puts the configuration, master key, license and database in place, enables dagda.service and starts it, and prints the remaining steps.
  4. Point DNS for the hub's domain at the new server's address.
  5. Run sudo dagda setup --reconfigure and enter the same domain when asked (leave the license question empty: the restored license is already installed). It keeps the restored configuration and master key and writes the nginx site and the TLS certificate. It needs nginx and certbot installed, and tells you if they aren't.

Agents reconnect on their own once the hub answers at its address again: their keys are in the restored database, so nothing needs to be done on them. A backup from the old pre-Dagda monitor (no dagda.toml in it) can't be restored onto a server that hasn't been set up: run sudo dagda setup first.

Doctor

sudo dagda doctor [--json]

Checks configuration validity, file permissions (including the database file), free disk space, that the service is active, license status, TLS certificate expiry (hub), NTP sync, hub reachability (agent), detected optional components (MySQL, PHP-FPM, Laravel, UFW, fail2ban), that the master key actually matches the sealed secrets in the database, whether the database was upgraded by a newer version of Dagda (which this version refuses to start on — doctor names the backup to restore), and any pre-restore-<timestamp> folder left over from an earlier dagda restore. Exits 0 if everything is fine, 1 if something needs attention and 2 if something is broken — including a dagda.toml that doesn't parse, which doctor reports as a result rather than aborting. Run it whenever something looks off, and especially after restoring a backup or moving a master key by hand: a mismatched key makes every sign-in fail with a "server key mismatch" error, and doctor catches that first.

Support bundle

sudo dagda support-bundle [--mask-ips] [--out <file>]

Produces a redacted diagnostic archive: your configuration with every secret value replaced, dagda doctor's check output, a license summary (licensee and expiry only — never the license signature or your repository token), recent service logs with tokens and secrets scrubbed, and version/platform information. --mask-ips also blurs IP addresses everywhere in the bundle. It never includes the database, the master key or your server list. Review it before sending anyway.

--out names the archive file to write (the extension follows whichever compressor ran; the actual path is printed); an existing directory or a name like . is refused. Run under sudo, the archive is handed back to your own user so you can attach it without sudo. Even with a dagda.toml that doesn't parse, a bundle is still produced with what can be determined without it.

Operations notes

  • If you put another reverse proxy or CDN in front of Dagda's own nginx, make sure it also sets X-Real-IP — Dagda only trusts that header from connections arriving on 127.0.0.1, and needs a real client IP for sign-in and enrollment rate limiting.
  • The hub's public URL must be a domain name; an IPv6-literal public_url is not supported.
  • Agent pushes are capped at 5 MB; the packaged nginx site sets client_max_body_size 6m to leave headroom.

Getting help

Stuck, or found a bug? Email support@dagdamonitor.com — a dagda support-bundle (see above) attached to your message saves a round-trip. See https://dagdamonitor.com for more about Dagda.