DocsOperationsDeployment & systemd

Deployment & systemd

ngstoned is meant to run as a long-lived systemd service on the VPS, restarted automatically on crash and surviving reboots without re-issuing certificates.

The systemd unit#

ngstoned.serviceini
[Unit]
Description=ngstone edge server
After=network-online.target
Wants=network-online.target
 
[Service]
Type=simple
ExecStart=/usr/local/bin/ngstoned --domain ngstone.site --cert-email you@ngstone.site
DynamicUser=yes
StateDirectory=ngstoned
AmbientCapabilities=CAP_NET_BIND_SERVICE
NoNewPrivileges=yes
EnvironmentFile=/etc/ngstoned/ngstoned.env
Restart=always
RestartSec=2
 
[Install]
WantedBy=multi-user.target

DynamicUser & StateDirectory#

DynamicUser=yes paired with StateDirectory=ngstoned is the mechanism systemd provides specifically to make dynamic, unprivileged users work with persistent state. systemd creates the directory under /var/lib/private/ and re-chowns it to the current transient UID on every service start, so the certificate cache survives restarts intact even though the UID changes each time.

Reference the certificate path via ${STATE_DIRECTORY}/certs (or the systemd-bind-mounted /var/lib/ngstoned/certs) rather than hardcoding /var/lib/private/... — the literal private path silently becomes a different, unmanaged directory if DynamicUser is ever removed from the unit.

Binding to port 443#

AmbientCapabilities=CAP_NET_BIND_SERVICE lets the process bind privileged ports without running as root. It composes cleanly with both DynamicUser=yes and NoNewPrivileges=yesNoNewPrivileges only blocks privilege gain via setuid binaries or file capabilities; it does not strip an ambient capability the service manager itself granted.

Secrets#

Never pass secrets as ExecStart flags

/proc/<pid>/cmdline is world-readable on stock Linux, so a token hash or API token passed as a command-line flag is readable by any local user via ps auxww. Put NGSTONE_TOKEN_SHA256 and NGSTONE_CF_API_TOKEN in the unit's EnvironmentFile= instead — ngstoned reads both in preference to the equivalent -token-sha256/-cf-api-token flags for exactly this reason. (The plaintext token itself, NGSTONE_TOKEN, belongs on the agent side, not on the VPS.)

Restart behavior#

Restart=always means a crash or OOM typically recovers in under two seconds. Because certificates are cached under StateDirectory, a restart makes zero ACME traffic — provided the unit is configured correctly. Get DynamicUser/StateDirectorywrong and every restart instead re-issues against Let's Encrypt's rate limits, which is the failure this unit is written specifically to avoid.