Przejdź do treści

Ustawienia plików cookie

Prosimy wybrać, na które rodzaje plików cookie Państwo zezwalają. Wybór można zmienić w dowolnym momencie w Ustawieniach plików cookie na dole każdej strony. Polityka prywatności

Niezbędne

Zawsze włączone

Potrzebne do logowania, zachowania koszyka i zapamiętania wyborów. Są zawsze włączone.

Jakie pliki cookie?
  • weboke_sessie, weboke_klant, weboke_remember: sesja i pozostanie zalogowanym
  • weboke_basket: koszyk
  • wkBtwIncl: wyświetlanie cen z VAT lub bez VAT
  • wok_cookies: wybór dotyczący plików cookie, 12 miesięcy

Mierzą, która reklama prowadzi do odwiedzin lub zamówienia, abyśmy nie płacili za reklamy, które nic nie dają.

Jakie pliki cookie?
  • Google Ads przez Google Tag Manager (_gcl_au, _gcl_aw), do 90 dni
  • OpenAI Ads, reklamy w ChatGPT
  • wok_aff: przez którego partnera trafili Państwo do nas (program partnerski), 60 dni

4,6

Kraj i język

Każdy kraj ma własną stronę z cenami i stawką VAT tego kraju.

Wyświetl

Własne usługi i timery

Moduł 6: Usługi i logi · Czas czytania: 11 min

Cel lekcji: Po tej lekcji będą Państwo potrafili uruchomić własny program jako usługę systemd pod osobnym użytkownikiem, z kilkoma opcjami bezpieczeństwa, oraz planować zadania za pomocą timera systemd lub crona.

Kluczowe pojęcia: plik unit, [Unit], [Service], [Install], ExecStart, User=, WorkingDirectory, EnvironmentFile, Restart=, WantedBy, NoNewPrivileges, ProtectSystem, ProtectHome, PrivateTmp, systemd-analyze security, timer, OnCalendar, Persistent, crontab

Dlaczego nie po prostu "nohup" albo "screen"?

Kto instaluje na serwerze własny program (małą aplikację webową, bota, skrypt, który co noc coś wykonuje), za pierwszym razem często uruchamia go ręcznie: node server.js & albo w sesji screen. Działa to do momentu, gdy się Państwo wylogują, serwer się zrestartuje albo program ulegnie awarii. Wtedy program znika i nikt tego nie zauważa.

Program, który ma działać zawsze, powinien być usługą systemd. Wtedy:

  • uruchamia się sam przy starcie systemu;
  • systemd uruchamia go ponownie, gdy ulegnie awarii;
  • jego wyjście trafia do journala (lekcja 6.2);
  • działa pod wybranym przez Państwa użytkownikiem, z uprawnieniami, na które Państwo pozwolą.

Własny plik unit

Załóżmy, że mają Państwo małą aplikację Node.js w /opt/factuurapp, która nasłuchuje na 127.0.0.1:3000. nginx lub Caddy udostępni ją później na zewnątrz (moduł 7).

Krok 1: osobny użytkownik bez powłoki (lekcja 3.2). Aplikacja nie musi działać jako root i nie musi się logować:

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

Sam kod może nadal należeć do roota (aplikacja nie musi modyfikować samej siebie); tylko katalog, do którego zapisuje, należy do użytkownika usługi.

Krok 2: plik unit. Własne unity umieszcza się w /etc/systemd/system/:

# /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

Trzy sekcje:

  • [Unit]: opis i kolejność. After=network-online.target razem z Wants= sprawia, że usługa startuje dopiero wtedy, gdy sieć jest dostępna.
  • [Service]: jak działa program. ExecStart z pełną ścieżką (systemd nie korzysta ze ścieżki wyszukiwania tak jak Państwa powłoka). User= i Group= określają, pod kim działa program. EnvironmentFile wczytuje ustawienia, takie jak hasło do bazy danych, z osobnego pliku, aby nie znajdowały się w unicie.
  • [Install]: co robi enable. WantedBy=multi-user.target oznacza: uruchamiaj razem ze zwykłym startem systemu.

Krok 3: sekrety osobno, ze ścisłymi uprawnieniami.

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

Zawartość to na przykład DATABASE_URL=postgres://factuur:...@127.0.0.1/factuur. systemd wczytuje ten plik jako root, zanim przełączy się na użytkownika usługi, więc 600 należący do roota w zupełności wystarczy.

Krok 4: wczytanie, uruchomienie, sprawdzenie.

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

Opcje bezpieczeństwa: mały wysiłek, duża różnica

Cztery linie pod RestartSec w przykładzie ograniczają możliwości usługi, także wtedy, gdy ktoś znajdzie lukę w Państwa aplikacji:

OpcjaEfekt
NoNewPrivileges=trueproces i jego procesy potomne nigdy nie mogą uzyskać większych uprawnień (także przez sudo ani programy setuid)
ProtectSystem=strictcały system plików jest dla usługi tylko do odczytu, z wyjątkiem tego, na co Państwo pozwolą za pomocą ReadWritePaths=
ProtectHome=true/home, /root i /run/user są niewidoczne
PrivateTmp=truewłasny, pusty /tmp, którego inne programy nie widzą

systemd potrafi ocenić Państwa unit:

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

Im niższa liczba, tym lepiej. Usługa bez żadnych opcji uzyskuje około 9 ("UNSAFE"). Nie trzeba dążyć do zera: każda dodana opcja może zablokować coś, czego aplikacja potrzebuje. Prosimy dodawać je pojedynczo i testować po każdym kroku. Jeśli coś przestanie działać, informację zwykle znajdą Państwo w journalu ("Read-only file system", "Permission denied").

Planowanie zadań: timery

Do czynności, które mają się odbywać o stałych porach (kopia zapasowa, skrypt porządkujący, raport), potrzebny jest timer. Timer systemd składa się z dwóch unitów o tej samej nazwie: .service, który mówi, co ma się wydarzyć, oraz .timer, który mówi, kiedy.

# /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 oznacza: program się wykonuje i potem kończy działanie. OnCalendar to harmonogram: codziennie o 03:15. Można też wpisać daily, weekly lub Mon *-*-* 02:00; systemd-analyze calendar "Mon *-*-* 02:00" pokazuje, kiedy nastąpi kolejne uruchomienie. Persistent=true jest ważne: jeśli o 03:15 serwer był wyłączony, zadanie wykona się zaraz po starcie systemu. RandomizedDelaySec nieco rozprasza moment startu.

Włącza się timer, a nie usługę:

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    # teraz jednorazowo przetestuj ręcznie
anna@web1:~$ journalctl -u opruimen.service

A cron?

cron to starsze, prostsze narzędzie, które nadal dobrze działa. Linia w crontabie użytkownika (crontab -e):

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

Pięć pól to minuta, godzina, dzień miesiąca, miesiąc i dzień tygodnia. Zalety i wady obok siebie:

crontimer systemd
Konfiguracjajedna liniadwa pliki
Pominięte uruchomienie (serwer wyłączony)zostaje pominiętez Persistent=true wykonuje się później
Wyjście i błędymailem, jeśli serwer potrafi wysyłać pocztę; w przeciwnym razie przepadająw journalu
Opcje bezpieczeństwa, użytkownikprzez sam skryptwszystko z systemd (patrz wyżej)
Sprawdzenie, kiedy się wykonałotrudnesystemctl list-timers i journal

Na serwerze zarządzanym na poważnie timery są lepszym wyborem, zwłaszcza dla kopii zapasowych (lekcja 8.2): chcą Państwo mieć pewność, że się wykonały i co zwróciły. Linię crona, która po cichu zawodzi, zauważą Państwo dopiero wtedy, gdy kopia zapasowa będzie potrzebna.

Na AlmaLinux i Rocky Linux

Unity i timery działają dokładnie tak samo. Jedna różnica: SELinux może zablokować własną usługę, która czyta lub zapisuje pliki w miejscu, którego SELinux się nie spodziewa, albo nasłuchuje na nietypowym porcie. Komunikat znajduje się w /var/log/audit/audit.log. Prosimy nie wyłączać SELinux, aby rozwiązać problem; należy znaleźć właściwą etykietę lub regułę (na przykład za pomocą semanage).

Podsumowanie

  • Program, który ma działać zawsze, powinien być usługą systemd: sam się uruchamia, restartuje po awarii, a logi trafiają do journala.
  • Własne unity w /etc/systemd/system/, z User= jako osobny użytkownik bez powłoki, sekrety w EnvironmentFile z uprawnieniami 600.
  • NoNewPrivileges, ProtectSystem=strict z ReadWritePaths, ProtectHome i PrivateTmp ograniczają szkody w razie luki; systemd-analyze security ocenia unit.
  • Timer to .service plus .timer z OnCalendar; Persistent=true nadrabia pominięte uruchomienia. Włącza się timer, a nie usługę.
  • cron nadal działa, ale timery dają lepsze logi i nie pomijają uruchomień.

Quiz

1. Państwa aplikacja działa jako usługa z User=root. Dlaczego osobny użytkownik jest lepszy?



2. Utworzyli Państwo .service oraz .timer. Co należy włączyć za pomocą enable --now?



3. Co robi Persistent=true w timerze?



4. Dodają Państwo ProtectSystem=strict, a aplikacja zgłasza potem "Read-only file system" przy zapisywaniu przesłanych plików. Jakie jest właściwe rozwiązanie?



5. Gdzie należy umieścić hasło do bazy danych własnej usługi?



Zadanie

Zadanie O6.3: Własna usługa z timerem. Proszę utworzyć na swoim serwerze małą własną usługę z timerem, na przykład skrypt, który co noc zapisuje wolne miejsce na dysku oraz systemctl --failed do pliku lub journala. Proszę użyć osobnego użytkownika, Type=oneshot, co najmniej dwóch opcji bezpieczeństwa oraz Persistent=true. Proszę przetestować za pomocą systemctl start, sprawdzić wyjście w journalu i zanotować wynik systemd-analyze security. Proszę wkleić swój .service oraz .timer i odpowiedzieć na pytania z listy kontrolnej.

Zadanie O6.3: Własna usługa z timerem

To zadanie wykonuje się samodzielnie, nikt go nie sprawdza. Prosimy zaznaczyć wykonane punkty i oznaczyć zadanie jako wykonane.




Zaznaczenia i notatki pozostają tylko w tej przeglądarce; nie są nigdzie wysyłane. Po zalogowaniu w Moje kursy zapisywana jest jedynie informacja, że zadanie zostało wykonane.

Przeczytaj więcej

Chwileczkę…

Konfiguracja domen

Dla każdej domeny można ustawić serwery nazw, powiązanie z hostingiem oraz to, kto zostanie właścicielem.

Wczytywanie domen…