Tradycja to nie podtrzymywanie popiołów, ale przekazywanie płomienia.

– Gustav Mahler

Czym jest systemd timers?

Systemd Timers to jednostki (units) systemu inicjalizacji i zarządzania usługami systemd, które służą do kontrolowania i uruchamiania innych usług (zazwyczaj skryptów lub programów) w oparciu o czas lub zdarzenia.

W przeciwieństwie do klasycznego crona, który opiera się na jednym globalnym demonie sprawdzającym pliki crontab co minutę, systemd timers są wbudowaną częścią jądra zarządzania systemem operacyjnym.

Możliwości systemd timers:

  • Precyzja milisekundowa: Możliwość planowania zadań z dokładnością nieosiągalną dla crona (którego minimum to 1 minuta).
  • Zintegrowane logowanie: Pełna integracja z journald – logi z każdego zadania trafiają automatycznie do centralnego dziennika, eliminując potrzebę przekierowywania wyjścia do plików tekstowych lub wysyłania lokalnych e-maili.
  • Zarządzanie zależnościami: Timer uruchomi zadanie dopiero wtedy, gdy spełnione zostaną określone warunki (np. podniesiony interfejs sieciowy lub zamontowany dysk backupowy).
  • Tolerancja na wyłączenie systemu (Persistent=true): Jeśli maszyna była wyłączona w czasie, gdy zadanie miało się uruchomić, systemd wykona je natychmiast po starcie. Zastępuje to przestarzałe i uciążliwe narzędzie anacron.
  • Losowe opóźnienia (RandomizedDelaySec): Zapobiegają nagłym przeciążeniom maszyn (tzw. “thundering herd” effect) poprzez uruchamianie zadań z lekkim przesunięciem czasowym.
  • Bezpieczne piaskownice (sandboxing): Łatwa izolacja uruchamianych skryptów – możemy odebrać im dostęp do sieci, katalogów domowych lub ograniczyć uprawnienia bez skomplikowanych konfiguracji chroot.

Weryfikacja dostępności

Systemd jest standardowym systemem inicjalizacji we wszystkich nowoczesnych dystrybucjach Linux. Aby upewnić się, że Twoje środowisko jest gotowe, sprawdź wersję systemd w terminalu:

systemctl --version

Jeśli zobaczysz numer wersji (np. systemd 252 lub nowszy), oznacza to, że masz pełne wsparcie dla wszystkich opisywanych niżej funkcji.


Anatomia systemd timer: Podwójna natura

To najważniejszy koncept, który na początku może wydawać się skomplikowany, ale jest kluczem do elastyczności systemd. W cronie jedna linia tekstu definiuje i czas, i polecenie. W systemd zadanie dzielimy na dwie osobne jednostki (pliki) umieszczone w katalogu /etc/systemd/system/:

  1. Plik usługi (.service) – definiuje CO ma zostać uruchomione (np. skrypt backupu).
  2. Plik timera (.timer) – definiuje KIEDY usługa ma zostać uruchomiona oraz jak ma się zachowywać.

Oba te pliki powinny mieć taką samą nazwę bazową, różniąc się jedynie rozszerzeniem (np. backup-web.service oraz backup-web.timer). Dzięki temu systemd automatycznie wie, którą usługę ma wywołać dany timer.

1. Definiowanie Usługi (nazwa.service)

Stwórzmy przykładowy plik /etc/systemd/system/backup-web.service:

[Unit]
Description=Kopia zapasowa bazy danych i plików WWW
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup-web.sh
User=backupuser
Group=backupuser

krótkie objaśnienie dla **backup-web.service **

  • [Unit]: Sekcja zawierająca metadane i definicje zależności.
    • Description: Czytelny opis widoczny w logach i statusie systemu.
    • After=network.target: Usługa zostanie uruchomiona dopiero po tym, jak sieć zostanie w pełni skonfigurowana. To zapobiega błędom wysyłania kopii na zdalny serwer.
  • [Service]: Sekcja opisująca samo wykonanie zadania.
    • Type=oneshot: Kluczowy typ dla zadań wsadowych (cron-like). Informuje systemd, że usługa wykonuje jedno konkretne zadanie i natychmiast się kończy. Systemd czeka na zakończenie tego procesu przed przejściem dalej.
    • ExecStart: Pełna ścieżka do skryptu lub polecenia, które ma zostać wykonane.
    • User / Group: Zabezpieczenie – skrypt nie będzie uruchamiany jako wszechpotężny root, lecz z uprawnieniami dedykowanego użytkownika backupuser.

      2. Definiowanie Timera (nazwa.timer)

Teraz stwórzmy pasujący plik /etc/systemd/system/backup-web.timer:

[Unit]
Description=Uruchamia cykliczny backup stron WWW

[Timer]
OnCalendar=daily
Persistent=true
RandomizedDelaySec=15m
Unit=backup-web.service

[Install]
WantedBy=timers.target

krótkie objaśnienie dla backup-web.timer

  • [Timer]: Najważniejsza sekcja, w której programujemy czas.
    • OnCalendar=daily: Definiuje harmonogram w formacie kalendarzowym. Skrót daily oznacza uruchamianie codziennie o północy (* - * - * 00:00:00).
    • Persistent=true: Opcja zbawienna dla laptopów i serwerów domowych. Jeśli komputer był wyłączony o północy, systemd wykryje to przy starcie i natychmiast uruchomi zaległe zadanie.
    • RandomizedDelaySec=15m: Dodaje losowe opóźnienie od 0 do 15 minut. Pomaga to rozłożyć obciążenie dysków i sieci w czasie, zwłaszcza gdy na jednym serwerze działa wiele timerów.
    • Unit=backup-web.service: Jawne wskazanie, którą usługę ma odpalić ten timer. Jeśli nazwy plików są identyczne, ten parametr można pominąć, ale jego dodanie poprawia czytelność.
  • [Install]: Sekcja instalacji.
    • WantedBy=timers.target: Określa, że ta jednostka powinna zostać aktywowana podczas uruchamiania specjalnej grupy systemd obsługującej timery.

Zarządzanie i weryfikacja

Wirtuoz terminala musi umieć kontrolować swoje instrumenty. Po utworzeniu lub edycji plików unitów, musisz powiadomić o tym systemd i aktywować timer.

Aktywacja timera

# 1. Przeładuj konfigurację systemd, aby wykryć nowe pliki
sudo systemctl daemon-reload

# 2. Włącz i uruchom timer natychmiast (**--now** łączy enable i start)
sudo systemctl enable --now backup-web.timer

Sprawdzanie statusu timera

Możesz sprawdzić stan swojego timera dokładnie tak samo, jak zwykłej usługi systemowej:

systemctl status backup.timer

Lista wszystkich aktywnych timerów

To jedno z najbardziej przydatnych poleceń. Pozwala zobaczyć pełny harmonogram zadań w Twoim systemie:

systemctl list-timers

krótkie objaśnienie dla systemctl list-timers

Analiza wyników polecenia:

  • NEXT: Dokładna data i godzina najbliższego uruchomienia zadania, wraz z czasem pozostałym (np. Tue 2026-06-16 00:00:00 CEST; 10h left).
  • LEFT: Odliczanie na żywo – ile czasu pozostało do startu.
  • LAST: Kiedy usługa została uruchomiona po raz ostatni (np. Mon 2026-06-15 00:01:23 CEST; 13h ago).
  • PASSED: Ile czasu upłynęło od ostatniego wykonania zadania.
  • UNIT: Nazwa jednostki .timer.
  • ACTIVATES: Nazwa jednostki .service, którą dany timer kontroluje i uruchomi o wskazanym czasie.

Dzięki temu jednemu poleceniu masz pełny, czytelny i posortowany chronologicznie wgląd we wszystkie planowane automatyzacje w systemie.

Podgląd logów (journald)

Koniec z szukaniem zaginionych logów w plikach /var/log/syslog czy przekierowywaniem błędów do /dev/null. Systemd automatycznie zbiera wszystko, co Twój skrypt wypisze na standardowe wyjście (stdout) i wyjście błędów (stderr).

# Podgląd logów dla konkretnej USŁUGI (nie timera!)
journalctl -u backup-web.service

# Podgląd logów w czasie rzeczywistym (opcja -f jak follow)
journalctl -u backup-web.service -f

Typy timerów: Czas rzeczywisty vs Monotoniczny

Systemd oferuje dwa zupełnie różne podejścia do określania czasu uruchomienia zadania. Wybór zależy od tego, co chcesz osiągnąć.

1. Timery czasu rzeczywistego (Calendar Timers)

Działają w oparciu o czas zegarowy (kalendarz), podobnie jak cron. Używają opcji OnCalendar.

Składnia kalendarza systemd wygląda następująco: DzieńTygodnia Rok-Miesiąc-Dzień Godzina:Minuta:Sekunda

Gwiazdka * oznacza “każdy”. Oto kilka przydatnych wzorców:

OnCalendar=daily                     # Codziennie o północy
OnCalendar=weekly                    # W każdą niedzielę o północy
OnCalendar=*-*-* 03:00:00            # Codziennie o 3 rano
OnCalendar=Mon,Wed 12:00:00          # W każdy poniedziałek i środę o 12:00
OnCalendar=*-*-01 04:30:00           # Pierwszego dnia każdego miesiąca o 4:30
OnCalendar=*-03..05-01 00:00:00      # Pierwszego marca, kwietnia i maja o północy

Genialne narzędzie pomocnicze:
Systemd posiada wbudowany parser, który pozwala przetestować składnię kalendarza przed wdrożeniem:

systemd-analyze calendar "Mon,Tue 15:30:00"

Polecenie to rozbije składnię na czynniki pierwsze, pokaże znormalizowany format oraz listę kolejnych dat, w których zadanie się uruchomi. Koniec ze zgadywaniem gwiazdek!

2. Timery monotoniczne (Monotonic Timers)

Działają w oparciu o czas, który upłynął od konkretnego zdarzenia systemowego (np. uruchomienia komputera lub zakończenia poprzedniego zadania). Są idealne do regularnego uruchamiania skryptów w tle, niezależnie od strefy czasowej czy zegara systemowego.

Wymagają podania interwału czasowego (np. 5m – 5 minut, 2h – 2 godziny, 1d – 1 dzień).

[Timer]
OnBootSec=10m          # Uruchom pierwszy raz 10 minut po starcie systemu
OnUnitActiveSec=1h     # Następnie uruchamiaj zadanie dokładnie co godzinę od ostatniego uruchomienia
Unit=my-cleanup.service

Dzięki OnUnitActiveSec eliminujesz problem crona, w którym skrypt uruchamiany “co godzinę” mógł zacząć nakładać się na siebie, jeśli poprzednie wykonanie trwało dłużej niż 60 minut. Systemd cierpliwie poczeka, aż poprzednie zadanie się skończy i dopiero wtedy rozpocznie odliczanie kolejnej godziny.


Praktyczny przykład: Bezpieczny backup i czyszczenie homelabu

Przełóżmy teorię na praktykę. Stworzymy system, który codziennie w nocy zarchiwizuje katalog z dokumentami, a następnie bezpiecznie usunie kopie starsze niż 30 dni.

Krok 1: Skrypt bash (/usr/local/bin/homelab-backup.sh)

#!/usr/bin/env bash
set -euo pipefail

BACKUP_DIR="/var/backups/homelab"
SOURCE_DIR="/home/ubikone/Dokumenty"
DATE=$(date +%Y%m%d_%H%M%S)
ARCHIVE="${BACKUP_DIR}/docs_${DATE}.tar.gz"

echo "[INFO] Rozpoczynam backup katalogu: ${SOURCE_DIR}"
mkdir -p "${BACKUP_DIR}"

# Tworzenie archiwum
tar -czf "${ARCHIVE}" "${SOURCE_DIR}"
echo "[INFO] Kopia zapisana: ${ARCHIVE}"

# Sprzątanie starych kopii (>30 dni)
echo "[INFO] Szukam kopii starszych niż 30 dni do usunięcia..."
find "${BACKUP_DIR}" -name "docs_*.tar.gz" -type f -mtime +30 -delete -print

echo "[INFO] Backup zakończony pomyślnie!"

Nie zapomnij nadać uprawnień do uruchamiania: sudo chmod +x /usr/local/bin/homelab-backup.sh

Krok 2: Usługa systemd (/etc/systemd/system/homelab-backup.service)

[Unit]
Description=Kopia zapasowa dokumentów homelabu
Documentation=https://ubikcode.pages.dev

[Service]
Type=oneshot
ExecStart=/usr/local/bin/homelab-backup.sh

# Podstawowe zabezpieczenia (Sandboxing)
ProtectSystem=strict
ReadWritePaths=/var/backups/homelab
ProtectHome=read-only
PrivateTmp=true

Krok 3: Timer systemd (/etc/systemd/system/homelab-backup.timer)

[Unit]
Description=Harmonogram codziennego backupu homelabu

[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
RandomizedDelaySec=5m

[Install]
WantedBy=timers.target

Krok 4: Uruchomienie

sudo systemctl daemon-reload
sudo systemctl enable --now homelab-backup.timer

I gotowe! Twój domowy serwer ma teraz w pełni zautomatyzowany, bezpieczny i odporny na wyłączenia system kopii zapasowych.


Aspekty bezpieczeństwa i piaskownica (Sandboxing)

UWAGA: Usługi systemd domyślnie działają z pełnymi uprawnieniami roota!

Uruchamianie skryptów automatyzacji niesie za sobą ryzyko. Jeśli Twój skrypt backupu zostanie zmodyfikowany przez intruza, systemd uruchomi go jako root. Dlatego ogromną przewagą systemd timers nad cronem jest łatwość, z jaką możemy odciąć usłudze dostęp do systemu i zamknąć ją w bezpiecznej piaskownicy.

Kluczowe parametry bezpieczeństwa do umieszczenia w sekcji **[Service]:**

  • User=username / Group=groupname: Uruchamia skrypt jako zwykły użytkownik zamiast roota (jeśli skrypt nie wymaga uprawnień administratora).
  • ProtectSystem=strict: Blokuje możliwość zapisu w kluczowych katalogach systemowych (/usr, /boot, /etc). Usługa widzi je jako tylko do odczytu.
  • ProtectHome=true (lub read-only): Blokuje dostęp do katalogów domowych użytkowników w /home i /root. Skrypt nie będzie mógł podejrzeć Twoich prywatnych plików.
  • PrivateTmp=true: Tworzy osobną, izolowaną przestrzeń dla plików tymczasowych /tmp dla tej usługi. Inne procesy nie zobaczą jej plików tymczasowych.
  • NoNewPrivileges=true: Uniemożliwia procesowi usługi (i jej procesom potomnym) podnoszenie swoich uprawnień (np. za pomocą setuid binaries).
  • PrivateDevices=true: Odbiera dostęp do fizycznych urządzeń systemowych w /dev (takich jak dyski twarde na niskim poziomie czy karty sieciowe).

Dzięki tym kilku prostym liniom, Twój system automatyzacji staje się odporny na eskalację uprawnień. Nawet jeśli skrypt zostanie przejęty, szkody zostaną ograniczone do minimum.


Tabela porównawcza: Systemd Timers vs Cron

Cecha Cron Systemd Timers
Natywne logowanie Słabe (wymaga przekierowań / wysyła lokalne e-maile) Wybitne (automatyczna integracja z journald)
Obsługa zależności Brak Pełna (uruchomienie po sieci, montowaniu dysków)
Tolerancja na wyłączenie Brak (wymaga zewnętrznego anacron) Pełna (Persistent=true wbudowane w standard)
Losowe opóźnienia Brak (wymaga hacków typu sleep $RANDOM w skrypcie) Pełna (RandomizedDelaySec jako prosty parametr)
Izolacja i bezpieczeństwo Bardzo trudna Prosta (wbudowane opcje sandboxingu systemd)
Precyzja czasu Do 1 minuty Do milisekund
Zarządzanie Edycja pliku tekstowego crontab -e Standardowe komendy systemowe (systemctl)
Przejrzystość Trudne wyszukiwanie zadań wielu użytkowników Proste systemctl list-timers dla całego systemu

Przydatne zasoby


Podsumowanie

Systemd timers to bezsprzecznie nowoczesny standard zarządzania czasem i automatyzacją w świecie Linuksa. Ich elastyczność, precyzja, odporność na przestoje oraz natywne bezpieczeństwo deklasują klasycznego crona na niemal każdym polu.

Kluczowe punkty do zapamiętania:

  • Systemd timer to zawsze para plików: .service (co robić) oraz .timer (kiedy robić).
  • Korzystaj z Persistent=true na urządzeniach, które nie pracują 24/7.
  • Logi sprawdzaj za pomocą journalctl -u nazwa.service – tam znajdziesz wszystko, co Twój skrypt wypisał na konsolę.
  • Wykorzystuj monotoniczne timery (OnUnitActiveSec), aby zapobiec nakładaniu się zadań.
  • Zawsze dbaj o bezpieczeństwo – izoluj swoje usługi za pomocą wbudowanych mechanizmów sandboxingowych.