Running a gateway script in tmux or from rc.local loses it on the first crash. A systemd service starts it at boot, restarts it, and collects its logs.
1. Dedicated user and code location
sudo useradd --system --create-home --home-dir /opt/sensor-gateway sensorgw
sudo usermod -a -G gpio,i2c sensorgw # only the hardware groups it needs
sudo -u sensorgw python3 -m venv --system-site-packages /opt/sensor-gateway/.venv
2. Unit file: /etc/systemd/system/sensor-gateway.service
[Unit]
Description=Sensor gateway (MQTT)
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=sensorgw
WorkingDirectory=/opt/sensor-gateway
ExecStart=/opt/sensor-gateway/.venv/bin/python -u gateway.py
Restart=on-failure
RestartSec=5
Environment=MQTT_HOST=localhost
[Install]
WantedBy=multi-user.target
Why these lines:
Restart=on-failure: without it systemd does not restart the service (the default isno).on-failurecovers non-zero exit codes and crashes by signal.alwaysalso restarts clean exits.RestartSec=5: the default is 100 ms, which turns a broken config into a tight crash loop. A few seconds is kinder to the system and to the broker.- Absolute path to the venv interpreter: no
activate, and systemd recommends absolute paths inExecStart. -u: unbuffered output, soprint()lines appear in the journal immediately.network-online.target: wait for the network before connecting to MQTT. Still write the script to retry connections, because Wi-Fi can come up late or drop.
3. Enable, start, observe
sudo systemctl daemon-reload
sudo systemctl enable --now sensor-gateway
systemctl status sensor-gateway
journalctl -u sensor-gateway -f
Tips
- Keep secrets out of the unit file: use
EnvironmentFile=/etc/sensor-gateway.envwithchmod 600. - For SD-card longevity, don't log every sensor sample (see the SD card item).
- Exit with a non-zero code on unrecoverable errors so
Restart=on-failurehandles them.