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:
prints a fresh enrollment link.sudo dagda user reset <email>sudo dagda user listshows 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 doctorsays what's wrong) and runsudo 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 (--forceoverrides 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:
- Install the package on the new server the same way you installed it
originally (the install script, or
apt install dagdafrom your licensed repository). Don't rundagda setupyet. - Copy the backup to the new server (e.g.
scpit to/root/). - Restore it:
sudo dagda restore /root/dagda-backup-<timestamp>.tar.zst. This puts the configuration, master key, license and database in place, enablesdagda.serviceand starts it, and prints the remaining steps. - Point DNS for the hub's domain at the new server's address.
- Run
sudo dagda setup --reconfigureand 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 needsnginxandcertbotinstalled, 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 on127.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_urlis not supported. - Agent pushes are capped at 5 MB; the packaged nginx site sets
client_max_body_size 6mto 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.