Running as a systemd service¶
An optional systemd unit runs awtrix-linux in hardened mode as an isolated
system service with a dynamic, non-root user. It is for a Linux host with systemd 250 or newer.
The TC002 does not use it; there a supervisor starts the program (see
AWTRIX NG on the TC002).
The unit template is
packaging/linux/awtrix-ng.service.in.
CMake fills in the install paths and writes awtrix-ng.service into the build directory.
cmake --install places it under share/awtrix-ng/systemd/ of the install prefix, next to the
web UI in share/awtrix-ng/. Installing does not enable anything.
How it works¶
- Credentials. The unit loads
admin.token,tls.crtandtls.keyfrom/etc/awtrix-ngthrough systemd's credential mechanism (LoadCredential=). systemd hands the service private copies owned by the service user with no group or other access, which meets the application's file rules. The unit ships no default credentials. Missing files, wrong permissions or invalid TLS material stop the start. - Settings.
/etc/awtrix-ng/service.envsuppliesAWTRIX_ORIGIN,AWTRIX_LISTENandAWTRIX_PORT. The unit defaults are127.0.0.1and8443; the origin has no default. - Identity and privileges.
DynamicUser=yes, no Linux capabilities,NoNewPrivileges=yes. The port must be above 1023, since no privileged-bind capability is granted. - Isolation. The filesystem is read-only except for the state directory; home directories
and physical devices are hidden. Namespace creation, kernel tunables and modules, real-time
scheduling, writable-and-executable memory and system calls outside
@system-serviceare blocked. Network access stays, for HTTP and MQTT. See the systemd execution model. - State.
StateDirectory=awtrix-ngkeeps data in/var/lib/awtrix-ngacross restarts. With a dynamic user, systemd manages its owner and may expose it through/var/lib/private; do not assign a fixed user ID to it. Core dumps are off,/tmpis private and the process count is limited to 128. - Restarts.
Restart=on-failureafter 3 s, at most three starts per minute. Stop uses SIGTERM, which lets the application save its state (15 s timeout). - MQTT. The shipped unit does not pass
--mqtt-ca-file, so MQTT stays off even when the settings enable it. See Enable MQTT.
Reboot and sleep requests from the application stop the process; they never reboot or power off the host. A factory reset clears the application state and keeps the external credentials. Restart the service yourself after these requests.
Set up the service¶
Build and install the CMake target with your chosen prefix (see AWTRIX on Linux).
Create the credentials with the helper from HTTPS administration. Both commands run as the owner of the directory, root here:
sudo install -d -m 0700 -o root -g root /etc/awtrix-ng
sudo python3 tools/linux/provision.py generate --dir /etc/awtrix-ng \
--origin https://device.example:8443
sudo python3 tools/linux/provision.py check --dir /etc/awtrix-ng \
--origin https://device.example:8443
This leaves root-owned files in /etc/awtrix-ng: the directory with mode 0700, the token and
key with 0600, the certificate with 0644.
To use a certificate from your own certificate authority, keep the admin.token from the
generate run, then replace the self-signed certificate and key with the issued material,
root-owned with the same modes, and validate the set against the CA. chain.pem holds the leaf
first, followed by its issuers:
sudo install -m 0644 -o root -g root chain.pem /etc/awtrix-ng/tls.crt
sudo install -m 0600 -o root -g root leaf.key /etc/awtrix-ng/tls.key
sudo python3 tools/linux/provision.py check --dir /etc/awtrix-ng \
--origin https://device.example:8443 --ca-file ca.pem
Never put these files into the repository or into application backups.
Create /etc/awtrix-ng/service.env, owned by root with mode 0600:
Use the same origin you gave generate or check; its host is in the certificate's Subject
Alternative Name. For access from the local host only, use https://localhost:8443 for both and
the listen address 127.0.0.1.
Copy the unit into the system unit directory, reload systemd and enable it. For the default CMake
prefix /usr/local:
sudo install -m 0644 /usr/local/share/awtrix-ng/systemd/awtrix-ng.service \
/etc/systemd/system/awtrix-ng.service
sudo systemctl daemon-reload
sudo systemctl enable --now awtrix-ng.service
sudo systemctl status awtrix-ng.service
Enable MQTT¶
Add a unit override (systemctl edit awtrix-ng.service) that loads the broker CA as another
credential and appends --mqtt-ca-file with its credential path (%d/<name>) to the existing
start arguments. Set up broker credentials and ACLs as described in
MQTT over verified TLS.
Rotate credentials¶
- New token and certificate: generate a new set into an empty directory, or remove the three
root-owned files and run
generateagain, then restart the service. - CA-issued certificate: replace
tls.crtandtls.keyas shown above, runcheck --ca-file, and restart.admin.tokenstays.
The application reads one consistent credential set at start. Stop the service before taking an offline backup of its state.
Test the real service¶
The integration test creates a uniquely named temporary unit and state directory. It keeps the
shipped security settings, exercises HTTPS and state persistence, checks the actual process
privileges and removes its fixture afterwards. It needs root to start the sandbox; the
application itself runs as a dynamic non-root user. It installs no persistent service and does
not touch /etc:
sudo python3 tests/linux/test_service.py \
--unit .pio/linux/awtrix-ng.service \
--binary .pio/linux/awtrix-linux --webui webui/index.html
The test fails when the host cannot provide the requested sandbox.