Wie man systemd verwendet, um einen Linux-Service beim Booten zu starten
Die Sicherstellung, dass kritische Dienste beim Neustart Ihres Servers automatisch starten, ist eine der grundlegendsten Aufgaben eines Linux-Systemadministrators. Ob Sie eine Webanwendung, eine Datenbank-Engine oder einen benutzerdefinierten Daemon in einer VPS Hosting-Umgebung ausführen – ein unerwarteter Neustart sollte niemals zu längeren Ausfallzeiten führen. Mit systemd – dem modernen Init-System, das die meisten heutigen Linux-Distributionen antreibt – können Sie präzise definieren, wie, wann und als wer Ihre Dienste starten, alles durch eine saubere, deklarative Unit-Datei.
Dieser umfassende Leitfaden führt Sie durch jeden Schritt: Verständnis von systemd, Erstellung einer produktionsreifen Service-Unit-Datei, Überprüfung von Berechtigungen, Testen Ihrer ausführbaren Datei und Verwaltung des Service-Lebenszyklus. Am Ende wird Ihre benutzerdefinierte Anwendung bei jedem Neustart automatisch funktionieren.
Was ist systemd und warum ist es wichtig?
systemd ist ein Init-System und Service-Manager, der ältere Alternativen wie SysVinit und Upstart in den meisten großen Linux-Distributionen ersetzt hat, einschließlich Ubuntu, Debian, CentOS, Rocky Linux, AlmaLinux und Fedora. Anstatt eine sequenzielle Kette von Shell-Skripten beim Start auszuführen, parallelisiert systemd den Service-Start, löst Abhängigkeitsreihenfolgen auf und verwaltet den gesamten Lebenszyklus von Systemprozessen über eine einzige, einheitliche Schnittstelle.
Wichtigste Vorteile von systemd für Server-Umgebungen
| Funktion | Vorteil |
|---|---|
| Paralleler Service-Start | Schnellere Startzeiten auf Multi-Service-Servern |
| Abhängigkeitsverwaltung | Dienste starten nur, wenn ihre Voraussetzungen erfüllt sind |
| Automatische Neustartrichtlinien | Abgestürzte Dienste werden ohne manuelle Eingriffe wiederhergestellt |
| Zentralisiertes Logging über journald | Alle Service-Ausgaben werden in einem durchsuchbaren Journal erfasst |
| Cgroup-basierte Ressourcenkontrolle | CPU- und Speicherlimits werden pro Service durchgesetzt |
| Socket- und Device-Aktivierung | Dienste starten bei Bedarf, nicht bedingungslos |
Für jeden, der Anwendungen auf Dedicated Servern oder VPS-Instanzen verwaltet, führen diese Funktionen direkt zu höherer Verfügbarkeit und vorhersehbarerem Verhalten unter Last.
Systemd Unit-Dateien verstehen
Alles, das systemd verwaltet, wird durch eine Unit-Datei dargestellt – eine Nur-Text-Konfigurationsdatei, die in Abschnitte unterteilt ist. Eine Service-Unit-Datei teilt systemd mit:
- Was der Service ist (Metadaten, Beschreibung, Abhängigkeiten)
- Wie er ausgeführt wird (ausführbarer Pfad, Arbeitsverzeichnis, Benutzerkontext)
- Wann er startet (Boot-Ziel, Reihenfolge relativ zu anderen Units)
- Was zu tun ist, wenn er fehlschlägt (Neustartrichtlinie, Neustartverzögerung)
Service-Unit-Dateien für systemweite Dienste befinden sich in /etc/systemd/system/. Dateien, die hier platziert werden, haben Vorrang vor vom Anbieter bereitgestellten Units in /lib/systemd/system/ und bleiben über Paketaktualisierungen hinweg erhalten.
Schritt für Schritt: Erstellen einer systemd-Service-Unit
Die folgende Anleitung verwendet eine fiktive Anwendung namens myapp. Ersetzen Sie jede Instanz von myapp, myuser und /usr/bin/myapp durch Werte, die für Ihre eigene Umgebung geeignet sind.
Schritt 1: Arbeitsverzeichnis vorbereiten
Entscheiden Sie vor dem Schreiben der Unit-Datei, von wo aus Ihre Anwendung ausgeführt wird. Ein dediziertes Arbeitsverzeichnis hält Konfigurationsdateien, Protokolle und Laufzeitdaten organisiert und macht die Berechtigungsverwaltung unkompliziert.
Erstellen Sie das Verzeichnis, falls es noch nicht vorhanden ist:
sudo mkdir -p /opt/myapp> Warum /opt/ statt /etc/systemd/?
> Der /etc/systemd/-Baum ist für systemds eigene Konfiguration reserviert. Das Platzieren von Anwendungsdaten dort ist nicht standardisiert und kann zu Verwirrung führen. Verwenden Sie /opt/myapp, /srv/myapp oder /var/lib/myapp je nachdem, welche Kategorie der Dateisystem-Hierarchie-Standard am besten zu Ihrer Workload passt.
Weisen Sie das Verzeichnis dem Benutzer zu, der den Service ausführt:
sudo useradd --system --no-create-home --shell /usr/sbin/nologin myuser
sudo chown -R myuser:myuser /opt/myappDie Verwendung eines dedizierten Systemkontos (keine Login-Shell, kein Home-Verzeichnis) ist eine Sicherheitsbest-Practice. Sie begrenzt den Schadensumfang, wenn die Anwendung jemals kompromittiert wird.
Überprüfen Sie das Ergebnis:
ls -ld /opt/myapp
# Expected output: drwxr-xr-x 2 myuser myuser 4096 Jan 1 00:00 /opt/myappSchritt 2: Service-Unit-Datei erstellen
Öffnen Sie eine neue Unit-Datei mit Ihrem bevorzugten Editor:
sudo nano /etc/systemd/system/myapp.serviceFügen Sie den folgenden Inhalt ein und passen Sie die Werte an Ihre Anwendung an:
[Unit]
Description=My Custom Application
Documentation=https://example.com/docs
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/bin/myapp --config /opt/myapp/myapp.conf
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5s
User=myuser
Group=myuser
WorkingDirectory=/opt/myapp
StandardOutput=journal
StandardError=journal
SyslogIdentifier=myapp
# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
[Install]
WantedBy=multi-user.targetSpeichern Sie die Datei mit Ctrl+O und beenden Sie sie mit Ctrl+X.
Schritt 3: Jede Direktive verstehen
[Unit]-Abschnitt
| Direktive | Zweck |
|---|---|
Description | Benutzerfreundlicher Name, der in systemctl status-Ausgabe angezeigt wird |
Documentation | URL oder Man-Page-Referenz für den Service |
After | Stellt sicher, dass der Service *nach* der aufgelisteten Unit aktiv ist |
Wants | Schwache Abhängigkeit – systemd *versucht*, die aufgelistete Unit zu starten, schlägt aber nicht fehl, wenn sie nicht verfügbar ist |
> network-online.target vs network.target: Verwenden Sie network-online.target (kombiniert mit Wants=network-online.target) für Services, die wirklich eine vollständig konfigurierte Netzwerkschnittstelle benötigen – zum Beispiel eine Anwendung, die beim Start eine Verbindung zu einer Remote-Datenbank oder einer externen API herstellt. network.target garantiert nur, dass das Netzwerk-Subsystem *gestartet* wurde, nicht dass Schnittstellen aktiv sind und Adressen zugewiesen sind.
[Service]-Abschnitt
| Direktive | Zweck |
|---|---|
Type=simple | Der von ExecStart gestartete Prozess ist der Hauptprozess (Standard für die meisten Anwendungen) |
ExecStart | Vollständiger Pfad zur Binärdatei und alle Argumente. Verwenden Sie immer absolute Pfade. |
ExecReload | Befehl zum Neuladen der Konfiguration ohne vollständigen Neustart (optional, aber empfohlen) |
Restart=on-failure | Starten Sie den Service neu, nur wenn er mit einem Nicht-Null-Code beendet wird oder von einem Signal getötet wird. Verwenden Sie always, wenn Sie Neustarts auch bei sauberen Beendigungen möchten. |
RestartSec | Sekunden zum Warten, bevor ein Neustart versucht wird |
User / Group | Führen Sie den Prozess als dieser Benutzer/diese Gruppe statt als Root aus |
WorkingDirectory | Legen Sie das aktuelle Verzeichnis fest, bevor Sie ExecStart ausführen |
StandardOutput / StandardError | Leiten Sie stdout/stderr zum systemd-Journal weiter |
SyslogIdentifier | Tag zum Filtern von Journal-Einträgen für diesen Service |
NoNewPrivileges | Verhindert, dass der Prozess zusätzliche Berechtigungen über setuid-Binärdateien erhält |
ProtectSystem=strict | Bindet /usr, /boot und /etc als schreibgeschützt für den Service ein |
ProtectHome | Macht /home, /root und /run/user für den Service unzugänglich |
PrivateTmp | Gibt dem Service seinen eigenen privaten /tmp-Namespace |
[Install]-Abschnitt
| Direktive | Zweck |
|---|---|
WantedBy=multi-user.target | Aktiviert den Service, wenn das System die Standard-Multi-User-Runlevel (nicht grafisch) erreicht. Dies ist das richtige Ziel für praktisch alle Server-Daemons. |
Schritt 4: Datei- und Verzeichnisberechtigungen überprüfen
Bevor Sie systemd neu laden, bestätigen Sie, dass der Service-Benutzer tatsächlich auf alles zugreifen kann, das er benötigt:
# Check working directory ownership and permissions
ls -ld /opt/myapp
# Confirm the executable exists and is executable
ls -l /usr/bin/myapp
# Verify the config file is readable by myuser
sudo -u myuser cat /opt/myapp/myapp.confWenn eine dieser Überprüfungen fehlschlägt, korrigieren Sie die Berechtigungen, bevor Sie fortfahren:
# Make the binary executable
sudo chmod +x /usr/bin/myapp
# Grant read access to the config file
sudo chmod 640 /opt/myapp/myapp.conf
sudo chown myuser:myuser /opt/myapp/myapp.confSchritt 5: Ausführbare Datei manuell testen
Überprüfen Sie immer, dass Ihre Anwendung korrekt ausgeführt wird, *bevor* Sie die Kontrolle an systemd übergeben. Dies isoliert Anwendungsfehler von systemd-Konfigurationsproblemen:
sudo -u myuser /usr/bin/myapp --config /opt/myapp/myapp.confWenn die Anwendung ohne Fehler startet, drücken Sie Ctrl+C, um sie zu stoppen und fortzufahren. Wenn sie fehlschlägt, beheben Sie die Anwendung selbst – überprüfen Sie, dass alle Abhängigkeiten installiert sind, Umgebungsvariablen gesetzt sind und erforderliche Ports verfügbar sind.
Schritt 6: systemd neu laden und Service aktivieren
Nachdem Sie die Unit-Datei gespeichert haben, weisen Sie systemd an, seine Konfiguration erneut zu lesen:
sudo systemctl daemon-reloadAktivieren Sie den Service, damit er bei jedem nachfolgenden Start automatisch startet:
sudo systemctl enable myapp.serviceDieser Befehl erstellt einen Symlink im entsprechenden .wants-Verzeichnis und verknüpft Ihre Unit-Datei in die multi-user.target-Boot-Sequenz. Sie sollten eine Ausgabe ähnlich dieser sehen:
Created symlink /etc/systemd/system/multi-user.target.wants/myapp.service → /etc/systemd/system/myapp.service.Starten Sie den Service sofort ohne Neustart:
sudo systemctl start myapp.serviceSchritt 7: Überprüfen Sie, ob der Service ausgeführt wird
Überprüfen Sie den aktuellen Status des Service:
sudo systemctl status myapp.serviceEin gesunder Service erzeugt eine Ausgabe wie diese:
● myapp.service - My Custom Application
Loaded: loaded (/etc/systemd/system/myapp.service; enabled; vendor preset: disabled)
Active: active (running) since Wed 2025-01-01 12:00:00 UTC; 5s ago
Main PID: 12345 (myapp)
Tasks: 4 (limit: 4915)
Memory: 12.3M
CPU: 45ms
CGroup: /system.slice/myapp.service
└─12345 /usr/bin/myapp --config /opt/myapp/myapp.confWichtige Felder zum Überprüfen:
Loaded– bestätigt, dass die Unit-Datei erfolgreich analysiert wurde und zeigt, ob sieenabledoderdisabledfür den Start istActive: active (running)– der Service wird derzeit ausgeführtMain PID– die Prozess-ID Ihrer Anwendung
Schritt 8: Protokolle mit journalctl überwachen
systemd leitet alle Service-Ausgaben zum Journal weiter, einem strukturierten, durchsuchbaren Log-Speicher. Verwenden Sie journalctl, um ihn zu überprüfen:
# View all logs for myapp (most recent last)
journalctl -u myapp.service
# Follow live log output (like tail -f)
journalctl -u myapp.service -f
# Show only logs since the last boot
journalctl -u myapp.service -b
# Show the last 50 lines
journalctl -u myapp.service -n 50
# Show logs since a specific time
journalctl -u myapp.service --since "2025-01-01 12:00:00"Wenn Ihr Service nicht startet, enthält das Journal fast immer die genaue Fehlermeldung, die erklärt, warum. Dies ist der erste Ort, an dem Sie nachschauen sollten, bevor Sie Änderungen vornehmen.
Schritt 9: Boot-Verhalten testen
Um zu bestätigen, dass der Service einen Neustart übersteht, ohne die Boot-Sequenz manuell zu überprüfen, können Sie dies simulieren:
# Reboot the server (only if safe to do so)
sudo rebootNachdem der Server wieder online ist, überprüfen Sie den Service-Status erneut:
sudo systemctl status myapp.serviceWenn es active (running) anzeigt, ist Ihr Service korrekt für den automatischen Start konfiguriert.
Verwaltung des Service-Lebenszyklus
Sobald Ihr Service ausgeführt wird, verwenden Sie regelmäßig die folgenden Befehle:
Häufige systemctl-Befehle
# Start the service
sudo systemctl start myapp.service
# Stop the service gracefully
sudo systemctl stop myapp.service
# Restart the service (stop + start)
sudo systemctl restart myapp.service
# Reload configuration without restarting (if ExecReload is defined)
sudo systemctl reload myapp.service
# Enable automatic startup at boot
sudo systemctl enable myapp.service
# Disable automatic startup at boot
sudo systemctl disable myapp.service
# Check whether the service is enabled
sudo systemctl is-enabled myapp.service
# Check whether the service is currently active
sudo systemctl is-active myapp.service
# View the full unit file as systemd interprets it
sudo systemctl cat myapp.service
# Edit the unit file and reload in one step
sudo systemctl edit --full myapp.serviceBehebung häufiger Probleme
Service startet nicht: „Datei oder Verzeichnis nicht vorhanden”
Dies bedeutet normalerweise, dass ExecStart auf eine nicht vorhandene Binärdatei verweist oder WorkingDirectory nicht vorhanden ist. Überprüfen Sie beide Pfade:
which myapp
ls -l /opt/myappService startet, wird aber sofort beendet
Überprüfen Sie das Journal auf die eigene Fehlerausgabe der Anwendung:
journalctl -u myapp.service -n 100 --no-pagerÜberprüfen Sie auch, dass Type=simple für Ihre Anwendung korrekt ist. Wenn Ihre Binärdatei sich selbst in den Hintergrund verzweigt, verwenden Sie stattdessen Type=forking.
„Berechtigung verweigert”-Fehler
Der Service-Benutzer hat keinen Zugriff auf eine erforderliche Datei oder ein erforderliches Verzeichnis. Verwenden Sie ls -l, um Berechtigungen zu überprüfen, und sudo -u myuser, um den Zugriff interaktiv zu testen.
Port wird bereits verwendet
Ein anderer Prozess ist an den Port gebunden, den Ihre Anwendung benötigt. Identifizieren Sie ihn mit:
sudo ss -tlnp | grep :<port>Service startet in einer Schleife neu
Wenn Restart=on-failure schnelle Neustartschleifen verursacht, drosselt systemd Neustarts schließlich. Überprüfen Sie StartLimitIntervalSec und StartLimitBurst im [Unit]-Abschnitt, um dieses Verhalten zu optimieren, und untersuchen Sie immer die Grundursache im Journal.
Erweiterte systemd-Muster für Produktionsserver
Umgebungsvariablen und Umgebungsdateien
Codieren Sie Geheimnisse niemals in Unit-Dateien. Verwenden Sie stattdessen eine Umgebungsdatei:
[Service]
EnvironmentFile=/etc/myapp/myapp.env
ExecStart=/usr/bin/myappErstellen Sie /etc/myapp/myapp.env mit chmod 600 und chown root:myuser, um den Zugriff zu beschränken:
DATABASE_URL=postgresql://user:password@localhost/mydb
API_KEY=supersecretkeyService-Abhängigkeiten und Reihenfolge
Wenn Ihre Anwendung von einem Datenbankservice abhängt (z. B. PostgreSQL oder MySQL), deklarieren Sie diese Abhängigkeit explizit:
[Unit]
After=network-online.target postgresql.service
Requires=postgresql.serviceRequires ist eine harte Abhängigkeit – wenn PostgreSQL nicht startet, versucht systemd auch nicht, Ihren Service zu starten.
Watchdog-Integration
Aktivieren Sie für unternehmenskritische Services systemds integrierten Watchdog, um hängende Prozesse zu erkennen:
[Service]
WatchdogSec=30s
Restart=on-watchdogIhre Anwendung muss regelmäßig ###PPT_NOTR_104_CODE
on All Hosting Services
