Direkt zum Inhalt

Cookie-Einstellungen

Wählen Sie, welche Arten von Cookies Sie erlauben. Sie können Ihre Auswahl jederzeit über Cookie-Einstellungen unten auf jeder Seite ändern. Datenschutzerklärung

Notwendig

Immer aktiv

Nötig zum Einloggen, für Ihren Warenkorb und um Ihre Auswahl zu speichern. Diese sind immer aktiv.

Welche Cookies?
  • weboke_sessie, weboke_klant, weboke_remember: Ihre Sitzung und eingeloggt bleiben
  • weboke_basket: Ihr Warenkorb
  • wkBtwIncl: Preise mit oder ohne MwSt. anzeigen
  • wok_cookies: Ihre Cookie-Auswahl, 12 Monate

Misst, welche Anzeige zu einem Besuch oder einer Bestellung führt, damit wir nicht für Anzeigen zahlen, die nichts bringen.

Welche Cookies?
  • Google Ads über Google Tag Manager (_gcl_au, _gcl_aw), bis zu 90 Tage
  • OpenAI Ads, Anzeigen in ChatGPT
  • wok_aff: über welchen Partner Sie zu uns kamen (Partnerprogramm), 60 Tage

4,6

Land und Sprache

Jedes Land hat seine eigene Website, mit Preisen und MwSt. dieses Landes.

Anzeigen

Modul 6 · 6.3

Eigene Dienste und Timer

Modul 6: Dienste und Logs · Lesezeit: 11 Minuten

Lernziel: Nach dieser Lektion können Sie ein eigenes Programm als systemd-Dienst unter einem eigenen Benutzer mit einigen Sicherheitsoptionen laufen lassen und Aufgaben mit einem systemd-Timer oder cron planen.

Kernbegriffe: Unit-Datei, [Unit], [Service], [Install], ExecStart, User=, WorkingDirectory, EnvironmentFile, Restart=, WantedBy, NoNewPrivileges, ProtectSystem, ProtectHome, PrivateTmp, systemd-analyze security, Timer, OnCalendar, Persistent, crontab

Warum nicht einfach "nohup" oder "screen"?

Wer ein eigenes Programm auf einem Server betreibt (eine kleine Webanwendung, einen Bot, ein Skript, das jede Nacht etwas erledigt), startet es beim ersten Mal oft von Hand: node server.js & oder in einer screen-Sitzung. Das funktioniert, bis Sie sich abmelden, der Server neu startet oder das Programm abstürzt. Dann ist es weg, und niemand bemerkt es.

Ein Programm, das immer laufen muss, gehört als systemd-Dienst eingerichtet. Dann:

  • startet es automatisch beim Hochfahren;
  • startet systemd es neu, wenn es abstürzt;
  • landet die Ausgabe im Journal (Lektion 6.2);
  • läuft es unter einem Benutzer, den Sie wählen, mit den Rechten, die Sie erlauben.

Eine eigene Unit-Datei

Angenommen, Sie haben eine kleine Node.js-Anwendung in /opt/factuurapp, die auf 127.0.0.1:3000 lauscht. nginx oder Caddy machen sie später nach außen erreichbar (Modul 7).

Schritt 1: ein eigener Benutzer ohne Shell (Lektion 3.2). Die Anwendung muss weder root sein noch sich anmelden können:

anna@web1:~$ sudo adduser --system --group --home /opt/factuurapp --no-create-home factuurapp
anna@web1:~$ sudo chown -R factuurapp:factuurapp /opt/factuurapp/data

Der Code selbst darf root gehören (die Anwendung muss sich nicht selbst ändern); nur das Verzeichnis, in das sie schreibt, gehört dem Dienstbenutzer.

Schritt 2: die Unit-Datei. Eigene Units legen Sie in /etc/systemd/system/ ab:

# /etc/systemd/system/factuurapp.service
[Unit]
Description=Factuurapp (Node.js)
After=network-online.target
Wants=network-online.target

[Service]
User=factuurapp
Group=factuurapp
WorkingDirectory=/opt/factuurapp
EnvironmentFile=/etc/factuurapp/env
ExecStart=/usr/bin/node /opt/factuurapp/server.js
Restart=on-failure
RestartSec=5s

NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
ReadWritePaths=/opt/factuurapp/data

[Install]
WantedBy=multi-user.target

Die drei Abschnitte:

  • [Unit]: Beschreibung und Reihenfolge. After=network-online.target mit Wants= sorgt dafür, dass der Dienst erst startet, wenn das Netzwerk bereit ist.
  • [Service]: wie das Programm läuft. ExecStart mit dem vollständigen Pfad (systemd verwendet keinen Suchpfad wie Ihre Shell). User= und Group= legen fest, unter wem es läuft. EnvironmentFile liest Einstellungen wie ein Datenbankpasswort aus einer separaten Datei, damit sie nicht in der Unit stehen.
  • [Install]: was enable bewirkt. WantedBy=multi-user.target bedeutet: beim normalen Hochfahren mitstarten.

Schritt 3: Geheimnisse getrennt, mit strengen Rechten.

anna@web1:~$ sudo mkdir /etc/factuurapp
anna@web1:~$ sudo install -m 600 -o root -g root /dev/null /etc/factuurapp/env
anna@web1:~$ sudoedit /etc/factuurapp/env

Inhalt zum Beispiel DATABASE_URL=postgres://factuur:...@127.0.0.1/factuur. systemd liest die Datei als root, bevor es zum Dienstbenutzer wechselt, daher genügt 600 mit root als Eigentümer.

Schritt 4: laden, starten, prüfen.

anna@web1:~$ sudo systemctl daemon-reload
anna@web1:~$ sudo systemctl enable --now factuurapp
anna@web1:~$ systemctl status factuurapp
anna@web1:~$ journalctl -u factuurapp -f

Sicherheitsoptionen: wenig Aufwand, großer Unterschied

Die vier Zeilen unter RestartSec im Beispiel schränken ein, was der Dienst kann, auch wenn jemand eine Lücke in Ihrer Anwendung findet:

OptionWirkung
NoNewPrivileges=trueder Prozess und seine Kindprozesse können niemals mehr Rechte erlangen (auch nicht über sudo oder setuid-Programme)
ProtectSystem=strictdas gesamte Dateisystem ist für den Dienst schreibgeschützt, außer dem, was Sie mit ReadWritePaths= erlauben
ProtectHome=true/home, /root und /run/user sind unsichtbar
PrivateTmp=trueein eigenes, leeres /tmp, das andere Programme nicht sehen

systemd kann Ihre Unit bewerten:

anna@web1:~$ systemd-analyze security factuurapp
...
→ Overall exposure level for factuurapp.service: 4.9 OK 🙂

Je niedriger die Zahl, desto besser. Ein Dienst ohne Optionen erreicht etwa 9 ("UNSAFE"). Sie müssen nicht auf null kommen: Jede Option, die Sie hinzufügen, kann etwas blockieren, das die Anwendung braucht. Fügen Sie sie einzeln hinzu und testen Sie nach jedem Schritt. Funktioniert etwas nicht mehr, steht der Grund meist im Journal ("Read-only file system", "Permission denied").

Aufgaben planen: Timer

Für etwas, das zu festen Zeiten passieren soll (ein Backup, ein Aufräumskript, ein Bericht), brauchen Sie einen Timer. Ein systemd-Timer besteht aus zwei Units mit demselben Namen: einer .service, die festlegt, was passieren soll, und einer .timer, die festlegt, wann.

# /etc/systemd/system/opruimen.service
[Unit]
Description=Oude exportbestanden opruimen

[Service]
Type=oneshot
User=factuurapp
ExecStart=/usr/bin/find /opt/factuurapp/data/export -type f -mtime +30 -delete
# /etc/systemd/system/opruimen.timer
[Unit]
Description=Dagelijks oude exportbestanden opruimen

[Timer]
OnCalendar=*-*-* 03:15:00
RandomizedDelaySec=10m
Persistent=true

[Install]
WantedBy=timers.target

Type=oneshot bedeutet: Das Programm läuft und ist danach fertig. OnCalendar ist der Zeitplan: jeden Tag um 03:15. Sie können auch daily, weekly oder Mon *-*-* 02:00 schreiben; systemd-analyze calendar "Mon *-*-* 02:00" zeigt, wann das nächste Mal ist. Persistent=true ist wichtig: War der Server um 03:15 ausgeschaltet, läuft die Aufgabe direkt nach dem Hochfahren nachträglich. RandomizedDelaySec verteilt den Startzeitpunkt etwas.

Aktiviert wird der Timer, nicht der Service:

anna@web1:~$ sudo systemctl daemon-reload
anna@web1:~$ sudo systemctl enable --now opruimen.timer
anna@web1:~$ systemctl list-timers opruimen
NEXT                        LEFT     LAST PASSED UNIT           ACTIVATES
Tue 2026-11-10 03:19:42 CET 15h left -    -      opruimen.timer opruimen.service
anna@web1:~$ sudo systemctl start opruimen.service    # jetzt einmal von Hand testen
anna@web1:~$ journalctl -u opruimen.service

Und cron?

cron ist das ältere, einfachere Werkzeug und funktioniert nach wie vor gut. Eine Zeile in der crontab eines Benutzers (crontab -e):

15 3 * * * /usr/local/bin/opruimen.sh

Die fünf Felder sind Minute, Stunde, Tag des Monats, Monat und Wochentag. Vor- und Nachteile im Vergleich:

cronsystemd-Timer
Einrichteneine Zeilezwei Dateien
Verpasster Lauf (Server aus)wird übersprungenmit Persistent=true nachgeholt
Ausgabe und Fehlerper Mail, wenn der Server mailen kann; sonst verlorenim Journal
Sicherheitsoptionen, Benutzerüber das Skript selbstalles von systemd (siehe oben)
Sehen, wann er liefumständlichsystemctl list-timers und das Journal

Für einen Server, den Sie ernsthaft verwalten, sind Timer die bessere Wahl, besonders für Backups (Lektion 8.2): Sie wollen sicher wissen, dass sie gelaufen sind und was sie gemeldet haben. Eine cron-Zeile, die still fehlschlägt, bemerken Sie erst, wenn Sie das Backup brauchen.

Unter AlmaLinux und Rocky Linux

Units und Timer funktionieren genau gleich. Ein Unterschied: SELinux kann einen eigenen Dienst blockieren, der Dateien an einem Ort liest oder schreibt, den SELinux nicht erwartet, oder der auf einem ungewöhnlichen Port lauscht. Die Meldung steht in /var/log/audit/audit.log. Schalten Sie SELinux nicht ab, um das Problem zu lösen; suchen Sie das richtige Label oder die richtige Regel (zum Beispiel mit semanage).

Zusammenfassung

  • Ein Programm, das immer laufen muss, gehört als systemd-Dienst eingerichtet: automatischer Start, Neustart bei einem Absturz, Logs im Journal.
  • Eigene Units in /etc/systemd/system/, mit User= ein eigener Benutzer ohne Shell, Geheimnisse in einem EnvironmentFile mit Rechten 600.
  • NoNewPrivileges, ProtectSystem=strict mit ReadWritePaths, ProtectHome und PrivateTmp begrenzen den Schaden bei einer Lücke; systemd-analyze security bewertet die Unit.
  • Ein Timer ist eine .service plus eine .timer mit OnCalendar; Persistent=true holt verpasste Läufe nach. Aktivieren Sie den Timer, nicht den Service.
  • cron funktioniert noch, aber Timer liefern bessere Logs und verpassen keine Läufe.

Quiz

1. Ihre Anwendung läuft als Dienst mit User=root. Warum ist ein eigener Benutzer besser?



2. Sie haben eine .service und eine .timer erstellt. Was aktivieren Sie mit enable --now?



3. Was bewirkt Persistent=true in einem Timer?



4. Sie fügen ProtectSystem=strict hinzu, und Ihre Anwendung meldet danach "Read-only file system" beim Speichern von Uploads. Was ist die richtige Lösung?



5. Wo hinterlegen Sie das Datenbankpasswort Ihres eigenen Dienstes?



Aufgabe

Aufgabe O6.3: Ein eigener Dienst mit Timer. Erstellen Sie auf Ihrem Server einen kleinen eigenen Dienst mit Timer, zum Beispiel ein Skript, das jede Nacht den freien Speicherplatz und systemctl --failed in eine Datei oder ins Journal schreibt. Verwenden Sie einen eigenen Benutzer, Type=oneshot, mindestens zwei Sicherheitsoptionen und Persistent=true. Testen Sie mit systemctl start, sehen Sie sich die Ausgabe im Journal an und notieren Sie die Bewertung von systemd-analyze security. Fügen Sie Ihre .service und .timer ein und beantworten Sie die Fragen in der Checkliste.

Aufgabe O6.3: Ein eigener Dienst mit Timer

Diese Aufgabe machen Sie selbst; niemand prüft sie nach. Haken Sie ab, was Sie erledigt haben, und markieren Sie die Aufgabe als erledigt.




Ihre Haken und Notizen bleiben nur in diesem Browser; wir senden sie nirgendwohin. Sind Sie angemeldet, speichern wir in Meine Kurse nur, dass Sie die Aufgabe erledigt haben.

Weiterführende Informationen

Einen Moment bitte…

Richten Sie Ihre Domains ein

Legen Sie für jede Domain die Nameserver, die Verknüpfung mit Ihrem Hosting und den künftigen Inhaber fest.

Ihre Domains werden geladen…