← Zurück

systemd-template


title: Eigener systemd-Service für Apps slug: systemd-service tags: [systemd, linux, services, howto] updated: 2025-10-16 summary: Eigene Applikation als systemd-Service betreiben: Unit-Datei, Restart-Policy, Status & Logs.



Eigener systemd-Service für Apps (Python, Node, Go, …)

Ziel: Eigene Anwendung als systemd-Service betreiben: Start beim Boot, automatischer Neustart bei Fehlern, Logs über journalctl.

Beispiele orientieren sich an Ubuntu Server (22.04/24.04), funktionieren aber sinngemäß auf allen Distributionen mit systemd.

Inhalt

  • Überblick: Was ist ein systemd-Service?
  • Beispiel-Unit für eine eigene App
  • Service-Datei anlegen & aktivieren
  • Status & Logs prüfen
  • Wichtige Direktiven kurz erklärt
  • Varianten (Environment-Datei, andere Pfade)
  • Checkliste bei Problemen

Überblick: Was ist ein systemd-Service?

  • systemd verwaltet Dienste über Unit-Dateien im INI-Format (key=value in Sektionen).
  • Ein Service besteht typischerweise aus den Sektionen
    [Unit] → Metadaten & Abhängigkeiten,
    [Service] → wie der Prozess gestartet wird,
    [Install] → wie der Dienst beim Booten „eingehängt“ wird.
  • Unit-Dateien werden als *.service gespeichert, z. B. meineapp.service.

Typische Pfade für System-Units

  • /etc/systemd/system → eigene/überschreibende System-Dienste (Admin-Konfiguration).
  • /usr/lib/systemd/system oder /lib/systemd/system → Dateien, die von Paketen installiert werden.

Für eigene Services reicht normalerweise: /etc/systemd/system.


Beispiel: Minimaler Service für /opt/myapp

Beispiel: Python-App, die als Benutzer appuser unter /opt/myapp läuft.

[Unit]
Description=Meine App
After=network.target

[Service]
User=appuser
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/python3 /opt/myapp/app.py
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Platzhalter anpassen:

  • User=appuser → unprivilegierter Benutzer, unter dem die App laufen soll.
  • WorkingDirectory=/opt/myapp → Ordner, in dem deine App liegt.
  • ExecStart=... → Befehl zum Starten deiner App (Python, Node, Binary, …).

Schritt 1 – Service-Datei unter /etc/systemd/system anlegen

sudo nano /etc/systemd/system/meineapp.service
  1. Inhalt aus dem Beispiel oben einfügen.
  2. Benutzer, Pfade, ExecStart an deine App anpassen.
  3. Datei speichern (Strg+O, Enter) und Editor schließen (Strg+X).

Damit liegt die Unit-Datei an einem Pfad, den systemd standardmäßig einliest.


Schritt 2 – Dienst laden, aktivieren & starten

Nach dem Anlegen oder Ändern der Unit-Datei:

sudo systemctl daemon-reload
sudo systemctl enable --now meineapp

Was passiert hier technisch?

  • daemon-reload liest die Unit-Dateien neu ein.
  • enable legt passende Symlinks an (z. B. unter multi-user.target.wants/), damit der Dienst beim Boot automatisch gestartet wird.
  • --now sorgt zusätzlich dafür, dass der Dienst direkt gestartet bzw. gestoppt wird (je nach Kommando).

Alternativ:

# nur aktivieren, aber jetzt noch nicht starten
sudo systemctl enable meineapp

# nur jetzt starten, ohne Autostart zu setzen
sudo systemctl start meineapp

Schritt 3 – Status & Logs des Dienstes prüfen

Status & letzte Logs in einem:

systemctl status meineapp

Typische Dinge, auf die du achten solltest:

  • „Active: active (running)“ → Dienst läuft.
  • „Active: failed“ → Startfehler, unten in der Ausgabe stehen die relevanten Zeilen.

Live-Logs verfolgen:

journalctl -u meineapp -f
  • -u meineapp → nur Logs dieses Dienstes.
  • -f → „follow“ / Live-Ansicht (wie tail -f).

Wichtige Direktiven im Beispiel erklärt

[Unit] Sektion

  • Description=
    Kurze Beschreibung, die z. B. in systemctl status angezeigt wird.

  • After=network.target
    Gibt die Startreihenfolge an: Der Dienst wird erst gestartet, nachdem network.target erreicht ist.
    Hinweis: After= setzt primär eine Reihenfolge, es garantiert nicht, dass das Netzwerk schon komplett „fertig“ ist. Für harte Abhängigkeiten gibt es Requires= / Wants=.

[Service] Sektion

  • User=
    Benutzer, als der der Dienst läuft. Für Web-/App-Dienste solltest du in der Regel nicht root verwenden.

  • WorkingDirectory=
    Verzeichnis, in dem der Prozess gestartet wird. Praktisch, wenn dein Startbefehl relative Pfade nutzt.

  • ExecStart=
    Voller Befehl zum Starten deiner App (mit absolutem Pfad zum Interpreter bzw. Binary).
    Beispiele:

/usr/bin/python3 /opt/myapp/app.py
/usr/bin/node /opt/myapp/server.js
/opt/myapp/myapp-binary
  • Restart=on-failure
    Dienst wird automatisch neu gestartet, wenn der Prozess mit Fehlercode endet (nicht bei normalem Exit).

  • RestartSec=5
    Wartezeit in Sekunden, bevor systemd einen Neustart versucht.

[Install] Sektion

  • WantedBy=multi-user.target
    Sorgt dafür, dass systemctl enable meineapp einen Symlink in multi-user.target.wants/ erstellt.
    Ergebnis: Der Dienst startet im normalen Multi-User-Modus automatisch mit.

Varianten & sinnvolle Erweiterungen

Environment-Datei nutzen

Konfiguration sauber von der Unit-Datei trennen:

  1. Environment-Datei anlegen:
sudo nano /etc/default/meineapp

Beispielinhalt:

APP_ENV=production
APP_PORT=8080
  1. Service-Datei erweitern:
[Service]
User=appuser
WorkingDirectory=/opt/myapp
EnvironmentFile=/etc/default/meineapp
ExecStart=/usr/bin/python3 /opt/myapp/app.py
Restart=on-failure
RestartSec=5

In deiner App kannst du dann APP_ENV / APP_PORT auslesen (z. B. über Umgebungsvariablen).

Nach Änderungen:

sudo systemctl daemon-reload
sudo systemctl restart meineapp

Andere Pfade für Unit-Dateien

  • Eigene Services / Overrides:
    /etc/systemd/system/*.service
  • Von Paketen gelieferte Units:
    /usr/lib/systemd/system/*.service oder /lib/systemd/system/*.service`

Empfehlung: Eigene Dienste und Anpassungen immer unter /etc/systemd/system halten, damit Paket-Updates deine Konfiguration nicht überschreiben.


Checkliste / Troubleshooting für systemd-Services

Konfiguration prüfen

sudo systemctl daemon-reload

Service manuell steuern

sudo systemctl start meineapp
sudo systemctl stop meineapp
sudo systemctl restart meineapp

Status & letzte Logs

systemctl status meineapp
journalctl -u meineapp -n 50 --no-pager

Start beim Booten checken

systemctl is-enabled meineapp
systemctl list-unit-files 'meineapp*'

Wirksame Unit-Definition anzeigen

systemctl cat meineapp

Typische Fehlerquellen

  • Pfade in ExecStart falsch oder Binary nicht ausführbar.
  • WorkingDirectory existiert nicht oder hat falsche Rechte.
  • Benutzer in User= hat keinen Zugriff auf Dateien/Ports.
  • Fehlende/kaputte Environment-Datei (EnvironmentFile= zeigt ins Leere).
  • daemon-reload nach Änderungen vergessen → systemd nutzt noch die alte Version.

Wenn der Dienst zwar startet, aber sofort wieder stirbt:

journalctl -u meineapp -b

durchgehen und die eigentliche Exception/Fehlermeldung suchen.