Systemd Stufe 2 Fortgeschritten: Unterschied zwischen den Versionen
Zur Navigation springen
Zur Suche springen
(Neue Seite: systemd Stufe 2 (Units schreiben)) |
(Links zu Stufe 3 und Lernpfad) |
||
| Zeile 3: | Zeile 3: | ||
! Stufe 1 · Basic !! Stufe 2 · Fortgeschritten !! Stufe 3 · Security | ! Stufe 1 · Basic !! Stufe 2 · Fortgeschritten !! Stufe 3 · Security | ||
|- | |- | ||
| − | | [[Systemd Stufe 1 Basic|Ich verwende es]] || '''Ich schreibe Units''' || Ich härte und untersuche | + | | [[Systemd Stufe 1 Basic|Ich verwende es]] || '''Ich schreibe Units''' || [[Systemd Stufe 3 Security|Ich härte und untersuche]] |
|} | |} | ||
| Zeile 236: | Zeile 236: | ||
=Weiter= | =Weiter= | ||
*[[Systemd Stufe 1 Basic|Zurück: Stufe 1]] | *[[Systemd Stufe 1 Basic|Zurück: Stufe 1]] | ||
| − | *Stufe 3: | + | *[[Systemd Stufe 3 Security|Weiter: Stufe 3, härten und untersuchen]] |
| + | *[[Systemd Lernpfad|Übersicht: Lernpfad systemd]] | ||
Version vom 17. Oktober 2026, 15:33 Uhr
| Stufe 1 · Basic | Stufe 2 · Fortgeschritten | Stufe 3 · Security |
|---|---|---|
| Ich verwende es | Ich schreibe Units | Ich härte und untersuche |
Einfach erklärt
- Eine Unit ist eine kleine Textdatei. Sie beschreibt, was gestartet wird, wann und wovon es abhängt.
- Man schreibt kein Startskript mehr, sondern sagt systemd nur, was man haben will. Den Rest erledigt systemd.
- Units der Pakete liegen unter /usr/lib, eigene und geänderte Units unter /etc. Was in /etc liegt, gewinnt.
- Wants sagt, was mitgestartet wird. After sagt, was vorher fertig sein muss. Das sind zwei getrennte Dinge.
Animation
Wo Units liegen
| Verzeichnis | Wer schreibt dort | Vorrang |
|---|---|---|
| /etc/systemd/system/ | der Admin | höchster |
| /run/systemd/system/ | Programme zur Laufzeit, weg nach dem Neustart | mittel |
| /usr/lib/systemd/system/ | die Pakete, wird bei Updates überschrieben | niedrigster |
- Liegt eine Unit mit gleichem Namen in /etc, wird die aus /usr/lib ignoriert.
- Drop-ins ändern nur einzelne Zeilen: /etc/systemd/system/name.service.d/override.conf
- systemctl cat name zeigt die Unit samt allen Drop-ins, so wie systemd sie wirklich sieht.
Aufbau einer Unit
- vi /etc/systemd/system/simple-http.service
[Unit] Description=Einfacher Webserver für Downloads After=network.target [Service] Type=exec User=kit WorkingDirectory=/home/kit/Downloads ExecStart=/usr/bin/python3 -m http.server 8000 Restart=on-failure RestartSec=2 [Install] WantedBy=multi-user.target
| Zeile | Bedeutung |
|---|---|
| [Unit]: Beschreibung und Abhängigkeiten | |
| Description= | Text, der bei status und im Journal erscheint |
| After=network.target | erst starten, wenn die Netzwerkverwaltung läuft |
| [Service]: wie der Dienst läuft | |
| Type=exec | systemd startet das Programm und wartet, bis es wirklich ausgeführt wird |
| User=kit | läuft als Benutzer kit, nicht als root |
| WorkingDirectory= | in diesem Verzeichnis startet der Prozess, http.server zeigt genau dieses an |
| ExecStart= | der Befehl, immer mit absolutem Pfad |
| Restart=on-failure | bei Absturz oder Fehlercode neu starten |
| RestartSec=2 | 2 Sekunden warten vor dem Neustart |
| [Install]: wird nur von enable und disable gelesen | |
| WantedBy=multi-user.target | enable legt einen Link in multi-user.target.wants/ an |
In Betrieb nehmen
- systemctl daemon-reload
- systemctl enable --now simple-http
- systemctl status simple-http
- journalctl -fu simple-http
- sudo ss -lntp | grep 8000
- curl -s http://localhost:8000/ | head -3
- Achtung: http.server lauscht auf allen Netzwerkkarten. Nur lokal: --bind 127.0.0.1
Prüfen vor dem Start
- systemd-analyze verify /etc/systemd/system/simple-http.service
- Keine Ausgabe heißt: keine Fehler gefunden.
Wants, Requires und After
| Anweisung | Bedeutung | Wenn die andere Unit scheitert |
|---|---|---|
| Wants=b | b wird mitgestartet | egal, a läuft trotzdem |
| Requires=b | b wird mitgestartet | a scheitert mit |
| After=b | a startet erst, wenn b fertig ist | startet nichts von selbst |
| Before=b | a muss fertig sein, bevor b startet | startet nichts von selbst |
- Wants und Requires sagen was, After und Before sagen wann. Meist braucht man beides.
- After= allein startet nichts. Es ordnet nur, falls die andere Unit ohnehin gestartet wird.
- In der Praxis nimmt man fast immer Wants. Requires nur, wenn ohne die andere Unit wirklich nichts geht.
- network.target: Die Netzwerkverwaltung läuft. Für Server, die lauschen, reicht das.
- network-online.target: Es gibt wirklich eine Verbindung. Dann braucht man Wants= und After=.
Type=: wann ein Dienst als gestartet gilt
| Type | Gestartet, wenn … | Beispiel |
|---|---|---|
| simple | der Prozess angelegt ist | einfache Programme (Standard) |
| exec | das Programm wirklich ausgeführt wird, meldet Tippfehler im Pfad als Fehler | besser als simple |
| forking | der Startprozess sich beendet hat und ein Kind weiterläuft | alte Daemons |
| oneshot | das Programm fertig ist | Skripte, z.B. Firewall laden |
| notify | der Dienst selbst „bereit“ meldet | nginx, postgresql |
- Bei oneshot mit RemainAfterExit=yes bleibt die Unit nach dem Skript „active“. So kann ein späteres stop noch ExecStop= ausführen.
Restart=: wann neu gestartet wird
| Restart | Exit-Code ≠ 0 | Absturz durch Signal (kill -9, SIGSEGV) | normales Ende |
|---|---|---|---|
| no | – | – | – |
| on-failure | ja | ja | – |
| on-abort | – | ja | – |
| always | ja | ja | ja |
- on-abort startet bei einem Python-Fehler (Exit-Code 1) nicht neu. Meist will man on-failure.
- Startet ein Dienst mehr als 5-mal in 10 Sekunden, gibt systemd auf: Start request repeated too quickly. Danach hilft systemctl reset-failed name.
Units ändern
| Befehl | Wirkung |
|---|---|
| systemctl edit ssh | legt einen Drop-in an, nur die Änderungen |
| systemctl edit --full ssh | kopiert die ganze Unit nach /etc |
| systemctl revert ssh | alle eigenen Änderungen verwerfen |
| systemctl daemon-reload | nach Änderungen mit vi oder nano, nicht nötig nach systemctl edit |
- Besser edit als --full: Bei --full bekommt man Änderungen aus Paket-Updates nicht mehr mit.
- Einen Wert ersetzen statt ergänzen, z.B. ExecStart: erst leeren, dann neu setzen.
[Service] ExecStart= ExecStart=/usr/bin/python3 -m http.server 8080
Timer statt cron
- Ein Timer startet eine andere Unit. Beide heißen gleich: backup.timer startet backup.service.
- /etc/systemd/system/backup.service
[Unit] Description=Nächtliches Backup [Service] Type=oneshot ExecStart=/usr/local/sbin/backup.sh
- /etc/systemd/system/backup.timer
[Unit] Description=Backup jede Nacht um 2 Uhr [Timer] OnCalendar=*-*-* 02:00:00 Persistent=true [Install] WantedBy=timers.target
- systemctl daemon-reload
- systemctl enable --now backup.timer
- systemctl list-timers backup.timer
- Persistent=true: War der Rechner um 2 Uhr aus, läuft das Backup beim nächsten Start nach.
- Zeitangaben testen:
- systemd-analyze calendar "Mon *-*-* 02:00"
Original form: Mon *-*-* 02:00
Normalized form: Mon *-*-* 02:00:00
Next elapse: Mon 2026-10-19 02:00:00 CEST
Beispiel: Firewall vor dem Netz
- Eine Firewall muss stehen, bevor das Netz hochkommt, sonst gibt es ein Zeitfenster ohne Schutz.
- /etc/systemd/system/firewall.service
[Unit] Description=Firewall-Regeln laden Before=network-pre.target Wants=network-pre.target [Service] Type=oneshot RemainAfterExit=yes ExecStart=/usr/local/sbin/firewall start ExecStop=/usr/local/sbin/firewall stop [Install] WantedBy=multi-user.target
Stolperfallen
- daemon-reload vergessen. systemd arbeitet dann mit der alten Version weiter. status warnt: changed on disk.
- Kein Shell. In ExecStart= gehen keine Umleitungen und Pipes. Dafür: ExecStart=/bin/bash -c "befehl >> /tmp/log"
- Relativer Pfad. ExecStart= braucht den vollen Pfad, sonst status=203/EXEC.
- Kein Zugriff. Darf User= nicht in WorkingDirectory=, kommt status=200/CHDIR.
- Beim Timer den Timer aktivieren, nicht den Service.
- Ganze Unit nach /etc kopiert. Updates des Pakets kommen nicht mehr an. Besser systemctl edit.
Aufgaben
Grundaufgaben
- Lassen Sie sich mit systemctl cat die Unit von cron anzeigen. Wo liegt sie, und wovon hängt sie ab?
- Legen Sie simple-http.service an, starten Sie den Dienst und rufen Sie die Seite mit curl auf.
- Beenden Sie den Prozess mit kill -9 und beobachten Sie status. Was macht systemd?
- Ändern Sie mit systemctl edit den Port auf 8080. Prüfen Sie mit systemctl cat, was daraus geworden ist.
- Bauen Sie einen Dienst für den iperf3-Server (iperf3 -s), der als Benutzer nobody läuft.
- Schreiben Sie einen Timer, der jede Minute das Datum an /tmp/zeit.log anhängt.
Für Schnelle
- Ersetzen Sie Restart=on-failure durch on-abort. Lassen Sie den Dienst einmal mit kill -9 und einmal mit einem Fehlercode enden. Was ist der Unterschied?
- Bauen Sie einen Dienst, der sofort mit exit 1 endet und Restart=always hat. Was passiert nach einigen Sekunden?
- Schreiben Sie die Firewall-Unit und prüfen Sie mit systemd-analyze critical-chain network-pre.target, dass sie vor dem Netz startet.

