Deploying with systemd

Documents the atlasd v0.2 release lineView as Markdown

The bench run from the quickstart used sudo. Production should not: Atlas ships a hardened unit that runs the daemon as an unprivileged user holding exactly one capability, inside a sandbox tight enough that verifying it is part of this guide. A static binary, a config file and this unit are a complete deployment.

1 — Install the binary and config

sudo install -m 0755 atlasd /usr/local/bin/atlasd
sudo mkdir -p /etc/atlas
sudo install -m 0600 node-a.toml /etc/atlas/config.toml
atlasd config check                       # validates /etc/atlas/config.toml

The config directory is canonical at /etc/atlas/; installations migrating from the earlier product name keep working through a legacy-path fallback, with a one-time log suggestion to move. Mode 0600 on the config matters — it contains the node's private key, and the daemon warns about anything looser.

2 — The service unit

Install the packaged unit rather than writing one — its hardening is the product of real deployments:

sudo install -m 0644 nexus-atlasd.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now nexus-atlasd

What the unit gives you:

  • An unprivileged service user (nexus-atlas) with CAP_NET_ADMIN granted via ambient capabilities — enough to create the TUN device and program routes, and nothing else. No root process anywhere.
  • A real sandbox: read-only system, no new privileges, a reduced capability bounding set, a syscall allowlist, restricted address families, and device access limited to /dev/net/tun. Writable paths are exactly the product's own: /etc/atlas (the commit-confirmed apply lifecycle writes staged configs), /var/lib/atlas, /var/log/atlas.
  • Startup that means something: Type=notifysystemctl start returns only when the TUN exists and every link is serviced, so "started" in your orchestration equals "data path up", not "process exec'd".
  • A watchdog fed honestly: WatchdogSec=30s, fed from data-path liveness counters — a wedged data path stops feeding it and systemd restarts the service; a busy-but-healthy daemon never trips it.
  • Crash accounting on the way down: the unit records exit status into the local crash spool, so an unexpected exit is a diagnosable artifact rather than a mystery.

3 — The dashboard as its own service

The web UI runs as a separate templated unit per interface (atlasd web --interface nexus0 --listen 0.0.0.0:9800), serving static assets from /opt/atlas/web. Keep it separate deliberately: the data-path daemon and the HTTP server restart independently, and a host that should be headless simply doesn't run the second unit. Both units share the snapshot handoff in /tmp/atlas/, so private temp directories must stay off for the pair.

Before exposing :9800 beyond localhost: create dashboard accounts (atlasd web adduser), decide the protection posture (protect = "writes" or "all"), and consider tls = true. An accountless dashboard is read-open and write-blocked — right for a bench, wrong for a fleet.

4 — Verify the sandbox

systemctl status nexus-atlasd            # active (running), Type=notify ready
ping -c 3 10.0.100.2                     # the tunnel works
ps -o user= -p $(pidof atlasd)           # nexus-atlas — not root
systemd-analyze security nexus-atlasd    # sandbox scorecard

The last command grades the unit's confinement; the packaged unit scores in the range that makes accreditation reviewers relax. If you tighten it further and the daemon breaks, loosen one directive at a time — every directive in the shipped unit is there because something needed it.

5 — Mandatory access control (optional, recommended on hardened hosts)

Packaging includes both flavors: an SELinux policy module (build and install with the provided Makefile on RHEL-family hosts) and an AppArmor profile (apparmor_parser -r on Debian-family hosts). Each confines the daemon to its documented paths and sockets. Deep-dive material on the confinement design — directive-by-directive rationale, policy internals, verification on a live system — is part of the OS hardening profile available under approved access.

6 — Fleets: Ansible

An Ansible role drives the same artifacts across many hosts — binary delivery with mandatory checksum, config templating, unit installation, and optionally the MAC policy — and can layer onto a STIG-baseline host. Start with one hand-installed node so you know what correct looks like; then let the role make it boring.

7 — Changing config on a running fleet

Edit-and-restart works, but the daemon offers better: the commit-confirmed apply lifecycle. Stage a config, commit it, and confirm within the window — a change that severs your own path to the node reverts itself. Pushing a config to the far end of a link you are about to reconfigure stops being an act of courage.

Esc
↑ ↓ navigateEnter — openEsc — close