Eine eigene Unit schreiben
Für jeden Dienst, der nicht aus einem Paket kommt, brauchst du eine Unit. Die drei Abschnitte sind schnell erklärt und der Rest ergibt sich daraus.
[Unit]
Description=Meine Anwendung
Documentation=https://intern.firma.de/wiki/meinapp
# Erst starten, wenn Netzwerk und Datenbank bereit sind
After=network-online.target postgresql.service
Wants=network-online.target
Requires=postgresql.service
# Nach fünf Fehlstarts in 60 Sekunden aufgeben statt endlos zu versuchen.
# Beide Werte gehoeren in [Unit], in [Service] werden sie ignoriert.
StartLimitBurst=5
StartLimitIntervalSec=60
[Service]
Type=notify
User=meinapp
Group=meinapp
WorkingDirectory=/opt/meinapp
ExecStart=/opt/meinapp/bin/server --config /etc/meinapp/config.toml
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.targetAfter regelt nur die Reihenfolge, Requires die Abhängigkeit. Wer nur After setzt, startet zwar später, aber auch dann, wenn die Datenbank gar nicht läuft.
Die wichtigsten Type-Werte
| Type | Bedeutung | Wann |
|---|---|---|
simple | Prozess läuft im Vordergrund, gilt sofort als gestartet | Standardfall, wenn die Anwendung nichts meldet |
notify | Anwendung meldet Bereitschaft selbst über sd_notify | Sauberste Variante, wenn die Anwendung es unterstützt |
forking | Prozess spaltet sich ab, Eltern beendet sich | Klassische Daemons, braucht PIDFile= |
oneshot | läuft einmal und endet | Wartungsaufgaben, meist zusammen mit einem Timer |
sudo systemctl daemon-reload # nach jeder Änderung an Unit-Dateien
sudo systemctl enable --now meinapp
systemctl status meinapp
systemctl cat meinapp # zeigt die effektive Unit samt Drop-ins
systemd-analyze verify meinapp.servicesystemctl cat ist der Befehl, den man am seltensten kennt und am häufigsten braucht: Er zeigt die zusammengesetzte Konfiguration inklusive aller Overrides.