15%

15% auf alle Hosting-Dienste sparen

Teste deine Fähigkeiten und erhalte Rabatt auf jeden Hosting-Plan

Benutze den Code:

Skills
Anfangen
10.11.2023

So aktivieren Sie das automatische Laden von Skripten in Ubuntu: Drei produktionsreife Methoden

Das Aktivieren des automatischen Ladens von Skripten in Ubuntu bedeutet, das Betriebssystem so zu konfigurieren, dass es beim Systemstart automatisch ein oder mehrere Shell-Skripte oder Dienste ausführt, ohne manuellen Eingriff. Dies wird durch drei primäre Mechanismen erreicht: das veraltete SysVinit-basierte /etc/init.d/-Verzeichnis, den /etc/rc.local-Kompatibilitäts-Shim und das moderne systemd-Service-Unit-Framework — Letzteres ist der maßgebliche, empfohlene Ansatz für alle Ubuntu-Versionen ab 15.04.

Für Systemadministratoren, die Workloads in einer VPS Hosting-Umgebung betreiben, ist die Startautomatisierung keine Annehmlichkeit — sie ist eine Zuverlässigkeitsanforderung. Ein falsch konfigurierter oder fehlender Autostart-Eintrag bedeutet, dass kritische Daemons, Monitoring-Agenten, Backup-Skripte oder benutzerdefinierte Netzwerkkonfigurationen nach einem Neustart stillschweigend nicht gestartet werden, was zu Dienstausfällen führt, die im Nachhinein schwer zu diagnostizieren sind.

Warum die Automatisierung von Startskripten auf Ubuntu-Servern wichtig ist

Jeder produktive Ubuntu-Server sammelt im Laufe der Zeit Betriebsskripte an: Datenbank-Vorwärm-Routinen, Log-Rotations-Trigger, VPN-Tunnel-Initialisierer, Firewall-Regel-Loader und Anwendungs-Integritätsprüfungen. Ohne einen strukturierten Autoloading-Mechanismus sind diese Skripte vollständig auf manuelle Ausführung angewiesen — ein einziger verpasster Schritt nach einem Kernel-Update oder einem Notfall-Neustart kann zu Ausfallzeiten führen.

Ubuntus Startup-Automatisierungs-Ökosystem hat sich erheblich weiterentwickelt:

  • SysVinit (vor Ubuntu 15.04): Sequenziell, langsam, skriptbasiert. Jeder Dienst blockierte den nächsten.
  • Upstart (Ubuntu 6.10–15.04): Ereignisgesteuert, schneller, aber jetzt veraltet.
  • systemd (Ubuntu 15.04+): Parallele Dienstaktivierung, Abhängigkeitsgraphen, Socket-Aktivierung, cgroup-basierte Ressourcenkontrolle und strukturierte Protokollierung über journald.

Zu verstehen, mit welcher Schicht Sie arbeiten — und warum — verhindert, dass Sie eine funktionierende Lösung in einer Testumgebung einsetzen, die in der Produktion stillschweigend versagt.

Methode 1: Verwendung des /etc/init.d/-Verzeichnisses (SysVinit / LSB-Skripte)

Funktionsweise

Das /etc/init.d/-Verzeichnis ist das traditionelle Zuhause für Linux Standard Base (LSB)-Init-Skripte. Jedes Skript in diesem Verzeichnis ist ein Shell-Skript, das auf standardisierte Befehle reagiert: start, stop, restart, status und optional reload. Das Dienstprogramm update-rc.d erstellt symbolische Links in den /etc/rcN.d/-Runlevel-Verzeichnissen und bestimmt, wann und in welcher Reihenfolge das Skript während der Boot- und Shutdown-Sequenzen ausgeführt wird.

Auf modernen Ubuntu-Systemen, die systemd ausführen, werden diese Skripte weiterhin durch eine Kompatibilitätsschicht namens systemd-sysv-generator unterstützt, die LSB-Init-Skripte automatisch in transiente systemd-Units konvertiert. Das bedeutet, dass Ihre /etc/init.d/-Skripte weiterhin ausgeführt werden, aber von systemd umschlossen werden, anstatt direkt von SysVinit ausgeführt zu werden.

Schrittweise Implementierung

Schritt 1: Erstellen Sie Ihr Skript

Schreiben Sie Ihr Skript und stellen Sie sicher, dass es der LSB-Header-Konvention folgt. Ein minimales, produktionssicheres Beispiel:

#!/bin/bash
### BEGIN INIT INFO
# Provides:          examplescript
# Required-Start:    $remote_fs $syslog $network
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Example autoload script
# Description:       Runs a custom initialization task at boot
### END INIT INFO

case "$1" in
  start)
    echo "Starting examplescript..."
    /usr/local/bin/examplescript.sh &
    ;;
  stop)
    echo "Stopping examplescript..."
    pkill -f examplescript.sh
    ;;
  restart)
    $0 stop
    $0 start
    ;;
  status)
    pgrep -f examplescript.sh > /dev/null && echo "Running" || echo "Stopped"
    ;;
  *)
    echo "Usage: $0 {start|stop|restart|status}"
    exit 1
    ;;
esac
exit 0

Schritt 2: Platzieren Sie das Skript in /etc/init.d/

sudo cp examplescript /etc/init.d/examplescript

Schritt 3: Machen Sie es ausführbar

sudo chmod +x /etc/init.d/examplescript

Schritt 4: Registrieren Sie es beim Runlevel-System

sudo update-rc.d examplescript defaults

Das Argument defaults registriert das Skript zum Starten in den Runlevels 2, 3, 4 und 5 sowie zum Stoppen in den Runlevels 0, 1 und 6 — das Standardverhalten für die meisten Server-Daemons.

Schritt 5: Registrierung überprüfen

ls -la /etc/rc2.d/ | grep examplescript

Sie sollten einen Symlink wie S01examplescript sehen, der auf /etc/init.d/examplescript zurückzeigt.

Kritischer Fallstrick

Der häufigste Fehler bei dieser Methode ist das Weglassen des LSB-Header-Blocks. Ohne ihn kann update-rc.d die Abhängigkeitsreihenfolge nicht bestimmen, und systemd-sysv-generator kann eine falsche Ausführungsreihenfolge relativ zur Netzwerkverfügbarkeit oder Dateisystem-Einhängepunkten zuweisen. Definieren Sie Required-Start-Abhängigkeiten immer explizit.

Um das Skript aus dem Autostart zu entfernen, ohne es zu löschen:

sudo update-rc.d examplescript disable

Um es vollständig zu entfernen:

sudo update-rc.d examplescript remove

Methode 2: Verwendung von /etc/rc.local (Kompatibilitäts-Shim)

Funktionsweise

/etc/rc.local ist ein veralteter Mechanismus, der ein Shell-Skript einmalig ausführt, nachdem alle Standard-Mehrbenutzerdienste gestartet wurden. Es ist die einfachste mögliche Autostart-Methode — keine Dienstverwaltung, keine Abhängigkeitsdeklarationen, keine Neustart-Logik. Auf Ubuntu 18.04 und später wird die Unterstützung für rc.local durch die systemd-Unit rc-local.service bereitgestellt, die standardmäßig deaktiviert ist und explizit aktiviert werden muss.

Wann es verwendet werden sollte

Verwenden Sie /etc/rc.local nur für:

  • Einmalige Initialisierungsbefehle, die nicht als Dienste verwaltet werden müssen
  • Schnelles Prototyping oder Testen, bevor ein systemd-Unit formalisiert wird
  • Einfache Umgebungsvariablen-Exporte oder Kernel-Parameter-Anpassungen

Verwenden Sie /etc/rc.local nicht für dauerhaft laufende Daemons. Da es blockierend und sequenziell ohne Prozessüberwachung ausgeführt wird, verzögert oder verhindert ein hängender Befehl in rc.local den Abschluss der Boot-Sequenz.

Schrittweise Implementierung

Schritt 1: Prüfen Sie, ob /etc/rc.local existiert

ls -la /etc/rc.local

Falls es nicht existiert, erstellen Sie es:

sudo bash -c 'cat > /etc/rc.local << EOF
#!/bin/bash
exit 0
EOF'
sudo chmod +x /etc/rc.local

Schritt 2: Aktivieren Sie die systemd-Unit rc-local (Ubuntu 18.04+)

sudo systemctl enable rc-local
sudo systemctl start rc-local

Schritt 3: Fügen Sie Ihren Befehl vor exit 0 ein

sudo nano /etc/rc.local

Fügen Sie Ihren Befehl oberhalb der exit 0-Zeile ein:

#!/bin/bash
/usr/local/bin/examplescript.sh >> /var/log/examplescript.log 2>&1 &
exit 0

Das & am Ende ist für jeden lang laufenden Befehl unerlässlich — es verzweigt den Prozess in den Hintergrund, damit rc.local nicht blockiert.

Schritt 4: Ausführung überprüfen

sudo systemctl status rc-local

Kritischer Fallstrick

Auf Ubuntu 20.04 und 22.04 hat rc-local.service ein fest codiertes 30-Sekunden-Timeout. Wenn Ihr Skript länger als 30 Sekunden benötigt, markiert systemd den Dienst als fehlgeschlagen und nachfolgende Befehle in rc.local werden nicht ausgeführt. Leiten Sie die Ausgabe um und setzen Sie lang laufende Prozesse explizit in den Hintergrund.

Methode 3: Verwendung von systemd-Service-Units (Empfohlen)

Warum systemd der richtige Ansatz für die Produktion ist

systemd ist nicht einfach ein Ersatz für SysVinit — es ist ein vollständiger System- und Sitzungsmanager, der Abhängigkeitsauflösung, parallelen Start, Socket- und D-Bus-Aktivierung, bedarfsgesteuerte Dienst-Erzeugung, Prozessüberwachung mit automatischem Neustart, cgroup-basierte Ressourcenisolierung und strukturierte Log-Aggregation durch journald bietet. Für jede Workload, die auf einem Dedicated Server oder produktiven VPS läuft, sind systemd-Units der einzig geeignete Mechanismus zur Verwaltung automatisch geladener Skripte.

Aufbau einer systemd-Unit-Datei

Eine .service-Unit-Datei ist in drei obligatorische Abschnitte unterteilt:

  • [Unit]: Metadaten, menschenlesbare Beschreibung und Abhängigkeitsdeklarationen (After=, Requires=, Wants=).
  • [Service]: Ausführungsparameter — die auszuführende Binärdatei oder das Skript, der Diensttyp, die Neustart-Richtlinie, Umgebungsvariablen und Sicherheits-Sandboxing-Optionen.
  • [Install]: Definiert, welches systemd-Target diese Unit aktiviert (WantedBy=multi-user.target ist der Standard für Server-Daemons).

Schrittweise Implementierung

Schritt 1: Bereiten Sie Ihr Skript vor

Stellen Sie sicher, dass Ihr Skript ausführbar ist und sich in einem stabilen Pfad befindet:

sudo cp examplescript.sh /usr/local/bin/examplescript.sh
sudo chmod +x /usr/local/bin/examplescript.sh

Schritt 2: Erstellen Sie die Unit-Datei

sudo nano /etc/systemd/system/examplescript.service

Eine produktionsreife Unit-Datei mit Sicherheitshärtung:

[Unit]
Description=Example Autoload Script
Documentation=https://your-internal-wiki/examplescript
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/examplescript.sh
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5s
StandardOutput=journal
StandardError=journal
SyslogIdentifier=examplescript
User=nobody
Group=nogroup
NoNewPrivileges=true
ProtectSystem=strict
PrivateTmp=true

[Install]
WantedBy=multi-user.target

Schritt 3: Laden Sie den systemd-Daemon neu

Nach dem Erstellen oder Ändern einer Unit-Datei müssen Sie den Konfigurations-Index des Daemons neu laden:

sudo systemctl daemon-reload

Schritt 4: Aktivieren Sie den Dienst für den Autostart

sudo systemctl enable examplescript.service

Dies erstellt einen Symlink in /etc/systemd/system/multi-user.target.wants/, der auf Ihre Unit-Datei zeigt.

Schritt 5: Starten Sie den Dienst sofort

sudo systemctl start examplescript.service

Schritt 6: Status und Logs überprüfen

sudo systemctl status examplescript.service
sudo journalctl -u examplescript.service -f

Verstehen der systemd-Diensttypen

Die Direktive Type= im Abschnitt [Service] ist einer der am häufigsten missverstandenen Parameter. Die Wahl des falschen Typs führt dazu, dass systemd die Dienstbereitschaft falsch meldet, was zu Abhängigkeitsfehlern führt.

TypVerhaltenAnwendungsfall
simpleDer von ExecStart gestartete Prozess ist der Hauptprozess. systemd betrachtet ihn sofort als bereit.Skripte und einfache Daemons, die nicht forken
forkingDer Prozess forkt und der Elternprozess beendet sich. systemd verfolgt das Kind über eine PID-Datei.Traditionelle Unix-Daemons (z. B. Apache mit PidFile)
oneshotDer Prozess läuft bis zum Abschluss und beendet sich. systemd wartet, bevor abhängige Units gestartet werden.Einmalige Initialisierungsaufgaben, Setup-Skripte
notifyDer Prozess signalisiert Bereitschaft über sd_notify().Daemons mit nativer systemd-Integration
idleDie Ausführung wird verzögert, bis alle aktiven Jobs verteilt sind.Hintergrundaufgaben mit niedriger Priorität

Für ein Skript, das einmalig beim Start ausgeführt wird und sich beendet, verwenden Sie Type=oneshot mit RemainAfterExit=yes, um die Unit nach Abschluss des Skripts im Zustand „aktiv” zu halten.

Erweitert: Abhängigkeitsreihenfolge mit After= und Wants=

Ein häufiger Produktionsfehler tritt auf, wenn ein Skript, das Netzwerkkonnektivität benötigt, startet, bevor der Netzwerk-Stack vollständig initialisiert ist. Die korrekte Abhängigkeitskette für netzwerkabhängige Skripte lautet:

After=network-online.target
Wants=network-online.target

Dies unterscheidet sich von After=network.target, das nur garantiert, dass die Netzwerkschnittstellen konfiguriert wurden — nicht, dass sie tatsächlich online und erreichbar sind. Die Abhängigkeit network-online.target erfordert, dass systemd-networkd-wait-online.service oder ein Äquivalent die Konnektivität bestätigt.

Vergleich: Alle drei Methoden auf einen Blick

Funktion/etc/init.d//etc/rc.localsystemd-Unit
Für die Produktion empfohlenNeinNeinJa
Unterstützung für parallelen StartNeinNeinJa
Prozessüberwachung / automatischer NeustartNeinNeinJa
AbhängigkeitsverwaltungBegrenzt (LSB-Header)KeineVollständig
Strukturierte ProtokollierungNeinNeinJa (journald)
Sicherheits-SandboxingNeinNeinJa
KomplexitätNiedrigSehr niedrigMittel
Unterstützt auf Ubuntu 22.04+Über KompatibilitätsschichtÜber rc-local.serviceNativ
Geeignet für dauerhaft laufende DaemonsTeilweiseNeinJa
Geeignet für einmalige InitialisierungsaufgabenJaJaJa (oneshot)

Häufige Fehler und wie man sie vermeidet

Skripte unnötigerweise als Root ausführen. Die Direktiven User= und Group= in systemd-Unit-Dateien ermöglichen es Ihnen, Berechtigungen abzugeben. Ein Skript, das nur in /var/log/myapp/ schreiben muss, benötigt keine Root-Rechte — erstellen Sie einen dedizierten Systembenutzer und weisen Sie die Verzeichniseigentümerschaft entsprechend zu.

Ausgabe in rc.local nicht umleiten. Ohne Ausgabeumleitung geht jede echo– oder Fehlerausgabe von rc.local-Befehlen an die Systemkonsole und geht verloren. Fügen Sie immer >> /var/log/yourscript.log 2>&1 an.

Absolute Pfade inkonsistent verwenden. systemd-Dienste laufen in einer minimalen Umgebung ohne den PATH des Benutzers. Verwenden Sie immer absolute Pfade für jede in ExecStart referenzierte Binärdatei, einschließlich Interpreter wie /usr/bin/python3 oder /bin/bash.

daemon-reload nach dem Bearbeiten von Unit-Dateien vergessen. systemd speichert den Inhalt von Unit-Dateien im Cache. Wenn Sie eine .service-Datei bearbeiten und sudo systemctl daemon-reload nicht ausführen, verwendet systemd weiterhin die alte Konfiguration.

Unit-Dateien für benutzerdefinierte Skripte in /lib/systemd/system/ ablegen. Das Verzeichnis /lib/systemd/system/ wird vom Paketmanager verwaltet. Benutzerdefinierte Unit-Dateien gehören in /etc/systemd/system/, das Vorrang hat und Paket-Upgrades überlebt.

Praktische Entscheidungsmatrix: Welche Methode verwenden

Verwenden Sie dieses Framework, um die geeignete Methode für Ihr spezifisches Szenario auszuwählen:

  • Dauerhaft laufender Daemon, der bei Fehler neu gestartet werden muss — systemd-Unit mit Restart=on-failure
  • Einmaliges Setup-Skript, das vor anderen Diensten abgeschlossen sein muss — systemd-Unit mit Type=oneshot und Before=-Abhängigkeiten
  • Skript, das vollständige Netzwerkkonnektivität benötigt — systemd-Unit mit After=network-online.target
  • Schneller Einzeiler zum Testen oder Prototyping/etc/rc.local (vorübergehend)
  • Legacy-Anwendung, die mit einem LSB-Init-Skript geliefert wird/etc/init.d/ mit update-rc.d
  • Alles, was in der Produktion läuft — systemd, immer

Für Administratoren, die mehrere Ubuntu-Server verwalten, sollten Sie die systemd-Unit-Verwaltung mit Konfigurationsverwaltungstools wie Ansible kombinieren, das .service-Dateien idempotent über Ihre gesamte Flotte hinweg bereitstellen und aktivieren kann. Wenn Sie eine verwaltete Umgebung mit vollem Root-Zugriff zur Implementierung dieser Konfigurationen benötigen, bietet VPS Hosting mit einem VPS Control Panel die Flexibilität, systemd-Dienste direkt ohne Einschränkungen zu verwalten.

Für Teams, die ressourcenintensive Workloads betreiben, die Startskripte zur Initialisierung von GPU-Treibern, CUDA-Umgebungen oder ML-Inferenz-Servern benötigen, profitieren GPU Hosting-Umgebungen besonders von systemds After=-Abhängigkeitsketten, die sicherstellen, dass Treiber vollständig geladen sind, bevor Anwendungsdienste versuchen, sich an Hardware-Ressourcen zu binden.

Wenn Ihre automatisch geladenen Skripte mit Webserver-Konfigurationen oder Datenbank-Initialisierungsroutinen interagieren, die an eine Control-Panel-Umgebung gebunden sind, erfordern VPS mit cPanel-Installationen besondere Sorgfalt — cPanel verwaltet seine eigene Dienstüberwachungsschicht, und benutzerdefinierte systemd-Units müssen so definiert werden, dass Konflikte mit cPanels Dienstverwaltungs-Hooks vermieden werden.

Technische Checkliste der wichtigsten Erkenntnisse

Bevor Sie ein Startskript auf einem Ubuntu-Server bereitstellen, überprüfen Sie Folgendes:

  • Speicherort der Unit-Datei: Benutzerdefinierte Skripte gehören in /etc/systemd/system/, nicht in /lib/systemd/system/
  • Ausführbarkeits-Bit: Mit ls -la /path/to/script.sh bestätigen — das x-Bit muss gesetzt sein
  • Absolute Pfade: Jede Binärdatei in ExecStart verwendet einen vollständigen Pfad; keine Abhängigkeit von $PATH
  • Abhängigkeitsdeklarationen: After=network-online.target für jedes netzwerkabhängige Skript
  • Diensttyp: Type=simple für persistente Daemons, Type=oneshot für Skripte, die ausgeführt werden und sich beenden
  • Berechtigungsminimierung: User=, Group=, NoNewPrivileges=true, ProtectSystem=strict
  • Protokollierung konfiguriert: StandardOutput=journal und StandardError=journal für die journald-Integration
  • daemon-reload ausgeführt: Führen Sie sudo systemctl daemon-reload immer nach dem Erstellen oder Bearbeiten von Unit-Dateien aus
  • Enable vs. start: enable erstellt den Autostart-Symlink; start führt ihn sofort aus — beide sind erforderlich
  • Mit journalctl getestet: Erfolgreiche Ausführung mit sudo journalctl -u yourservice.service --since "5 minutes ago" bestätigen

FAQ

Was ist der Unterschied zwischen systemctl enable und systemctl start?

systemctl enable erstellt einen symbolischen Link, der dazu führt, dass der Dienst beim nächsten Start automatisch gestartet wird. systemctl start startet den Dienst sofort in der aktuellen Sitzung. In der Regel benötigen Sie beide Befehle, wenn Sie einen neuen Dienst zum ersten Mal einrichten.

Warum schlägt mein systemd-Dienst mit „executable not found” fehl, obwohl das Skript existiert?

Dies bedeutet fast immer, dass der ExecStart-Pfad falsch ist oder dem Skript das ausführbare Bit fehlt. Überprüfen Sie mit which yourscript und ls -la /path/to/script. Bestätigen Sie auch, dass die erste Zeile Ihres Skripts ein gültiger Shebang ist (#!/bin/bash oder #!/usr/bin/env python3), da systemd standardmäßig keine Shell für ExecStart aufruft.

Kann ich ein Skript beim Start nur einmal ausführen, nicht bei jedem Boot?

Verwenden Sie Type=oneshot mit einer ConditionPathExists=!/var/run/myscript.done-Direktive im Abschnitt [Unit]. Das Skript erstellt die Sentinel-Datei beim ersten Ausführen; nachfolgende Boots überspringen die Ausführung, da die Bedingung nicht erfüllt ist.

Wird /etc/rc.local auf Ubuntu 22.04 noch unterstützt?

Ja, aber es ist standardmäßig deaktiviert. Sie müssen die rc-local.service-Unit manuell mit sudo systemctl enable rc-local aktivieren und sicherstellen, dass die Datei existiert und ausführbar ist. Es wird als Kompatibilitätsmaßnahme unterstützt, nicht als empfohlene Praxis.

Wie überprüfe ich, warum ein Startskript nicht ausgeführt wurde?

Führen Sie sudo journalctl -u yourservice.service -b aus, um alle Log-Einträge für diese Unit seit dem letzten Boot anzuzeigen. Bei rc.local-Fehlern überprüfen Sie sudo systemctl status rc-local.service und sehen Sie sich /var/log/syslog auf Einträge an, die während der Boot-Sequenz zeitgestempelt wurden.

15%

15% auf alle Hosting-Dienste sparen

Teste deine Fähigkeiten und erhalte Rabatt auf jeden Hosting-Plan

Benutze den Code:

Skills
Anfangen