Modul 6 · 6.3
Lastne storitve in časovniki
Modul 6: Storitve in dnevniki · Čas branja: 11 minut
Učni cilj: Po tej lekciji boste znali lasten program zagnati kot storitev systemd pod lastnim uporabnikom, z nekaj varnostnimi možnostmi, in načrtovati opravila s časovnikom systemd ali s cronom.
Ključni pojmi: datoteka enote, [Unit], [Service], [Install], ExecStart, User=, WorkingDirectory, EnvironmentFile, Restart=, WantedBy, NoNewPrivileges, ProtectSystem, ProtectHome, PrivateTmp, systemd-analyze security, časovnik (timer), OnCalendar, Persistent, crontab
Zakaj ne preprosto "nohup" ali "screen"?
Kdor na strežnik namesti lasten program (majhno spletno aplikacijo, bota, skript, ki vsako noč nekaj naredi), ga prvič pogosto zažene ročno: node server.js & ali v seji screen. To deluje, dokler se ne odjavite, se strežnik ne znova zažene ali se program ne sesuje. Takrat ga ni več in nihče tega ne opazi.
Program, ki mora vedno teči, naj bo storitev systemd. Takrat:
- se samodejno zažene ob zagonu sistema;
- ga systemd znova zažene, če se sesuje;
- njegov izpis pristane v journalu (lekcija 6.2);
- teče pod uporabnikom, ki ga izberete Vi, s pravicami, ki jih dovolite Vi.
Lastna datoteka enote
Recimo, da imate majhno aplikacijo Node.js v /opt/factuurapp, ki posluša na 127.0.0.1:3000. nginx ali Caddy jo bo pozneje objavil navzven (modul 7).
1. korak: lasten uporabnik brez lupine (lekcija 3.2). Aplikaciji ni treba biti root in se ni treba prijavljati:
anna@web1:~$ sudo adduser --system --group --home /opt/factuurapp --no-create-home factuurapp
anna@web1:~$ sudo chown -R factuurapp:factuurapp /opt/factuurapp/dataKoda sama lahko ostane v lasti uporabnika root (aplikaciji ni treba spreminjati same sebe); samo mapa, v katero piše, je v lasti uporabnika storitve.
2. korak: datoteka enote. Lastne enote shranite v /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.targetTrije razdelki:
- [Unit]: opis in vrstni red.
After=network-online.targetskupaj zWants=poskrbi, da se storitev zažene šele, ko je omrežje na voljo. - [Service]: kako program teče.
ExecStarts polno potjo (systemd ne uporablja iskalne poti, kot jo uporablja Vaša lupina).User=inGroup=določata, pod kom teče.EnvironmentFileprebere nastavitve, kot je geslo za podatkovno bazo, iz ločene datoteke, da niso zapisane v enoti. - [Install]: kaj naredi
enable.WantedBy=multi-user.targetpomeni: zaženi se ob običajnem zagonu sistema.
3. korak: skrivnosti ločeno, s strogimi pravicami.
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/envVsebina je na primer DATABASE_URL=postgres://factuur:...@127.0.0.1/factuur. systemd datoteko prebere kot root, preden preklopi na uporabnika storitve, zato zadošča 600 v lasti uporabnika root.
4. korak: nalaganje, zagon, preverjanje.
anna@web1:~$ sudo systemctl daemon-reload
anna@web1:~$ sudo systemctl enable --now factuurapp
anna@web1:~$ systemctl status factuurapp
anna@web1:~$ journalctl -u factuurapp -fVarnostne možnosti: malo truda, velika razlika
Štiri vrstice pod RestartSec v primeru omejujejo, kaj storitev lahko počne, tudi če nekdo najde ranljivost v Vaši aplikaciji:
| Možnost | Učinek |
|---|---|
NoNewPrivileges=true | proces in njegovi podrejeni procesi nikoli ne morejo dobiti več pravic (tudi ne prek sudo ali programov setuid) |
ProtectSystem=strict | celoten datotečni sistem je za storitev samo za branje, razen tistega, kar dovolite z ReadWritePaths= |
ProtectHome=true | /home, /root in /run/user so nevidni |
PrivateTmp=true | lasten, prazen /tmp, ki ga drugi programi ne vidijo |
systemd lahko Vašo enoto oceni:
anna@web1:~$ systemd-analyze security factuurapp
...
→ Overall exposure level for factuurapp.service: 4.9 OK 🙂Nižja kot je številka, bolje je. Storitev brez možnosti doseže okoli 9 ("UNSAFE"). Do nič Vam ni treba priti: vsaka možnost, ki jo dodate, lahko pokvari nekaj, kar aplikacija potrebuje. Dodajajte jih eno za drugo in po vsakem koraku preizkusite. Če kaj ne deluje več, je razlog navadno zapisan v journalu ("Read-only file system", "Permission denied").
Načrtovanje opravil: časovniki
Za nekaj, kar se mora zgoditi ob določenih časih (varnostna kopija, skript za čiščenje, poročilo), potrebujete časovnik. Časovnik systemd sestavljata dve enoti z enakim imenom: .service, ki pove, kaj naj se zgodi, in .timer, ki pove, kdaj.
# /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.targetType=oneshot pomeni: program se izvede in je nato končan. OnCalendar je urnik: vsak dan ob 03:15. Lahko napišete tudi daily, weekly ali Mon *-*-* 02:00; systemd-analyze calendar "Mon *-*-* 02:00" pokaže, kdaj bo to naslednjič. Persistent=true je pomembna: če je bil strežnik ob 03:15 izklopljen, se opravilo izvede takoj po zagonu. RandomizedDelaySec trenutek zagona nekoliko razprši.
Vklopite časovnik, ne storitve:
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 # zdaj enkrat ročno preizkusite
anna@web1:~$ journalctl -u opruimen.serviceKaj pa cron?
cron je starejše, preprostejše orodje in še vedno dobro deluje. Vrstica v crontabu uporabnika (crontab -e):
15 3 * * * /usr/local/bin/opruimen.shPet polj pomeni minuto, uro, dan v mesecu, mesec in dan v tednu. Prednosti in slabosti drugo ob drugi:
| cron | časovnik systemd | |
|---|---|---|
| Nastavitev | ena vrstica | dve datoteki |
| Zamujen zagon (strežnik izklopljen) | se preskoči | z Persistent=true se izvede naknadno |
| Izpis in napake | po e-pošti, če strežnik lahko pošilja pošto; sicer izgubljeno | v journalu |
| Varnostne možnosti, uporabnik | prek samega skripta | vse iz systemd (zgoraj v lekciji) |
| Kdaj se je izvedel | težko ugotoviti | systemctl list-timers in journal |
Za strežnik, ki ga resno upravljate, so časovniki boljša izbira, zlasti za varnostne kopije (lekcija 8.2): želite zagotovo vedeti, da so se izvedle in kaj so izpisale. Vrstico cron, ki tiho odpove, opazite šele, ko varnostno kopijo potrebujete.
Na AlmaLinux in Rocky Linux
Enote in časovniki delujejo popolnoma enako. Ena razlika: SELinux lahko zaustavi lastno storitev, ki bere ali piše datoteke na mestu, ki ga SELinux ne pričakuje, ali ki posluša na neobičajnih vratih. Sporočilo najdete v /var/log/audit/audit.log. SELinux ne izklopite, da bi to rešili; poiščite pravo oznako ali pravilo (na primer z semanage).
Povzetek
- Program, ki mora vedno teči, naj bo storitev systemd: samodejni zagon, ponovni zagon ob sesutju, dnevniki v journalu.
- Lastne enote v
/etc/systemd/system/, zUser=lasten uporabnik brez lupine, skrivnosti vEnvironmentFiles pravicami 600. NoNewPrivileges,ProtectSystem=strictzReadWritePaths,ProtectHomeinPrivateTmpomejijo škodo ob ranljivosti;systemd-analyze securityoceni enoto.- Časovnik je
.serviceplus.timerzOnCalendar;Persistent=truenadoknadi zamujene zagone. Vklopite časovnik, ne storitve. - cron še vedno deluje, vendar časovniki dajejo boljše dnevnike in ne zamudijo nobenega zagona.
Kviz
Naloga
Naloga O6.3: Lastna storitev s časovnikom. Na svojem strežniku ustvarite majhno lastno storitev s časovnikom, na primer skript, ki vsako noč zapiše prosti prostor na disku in systemctl --failed v datoteko ali v journal. Uporabite lastnega uporabnika, Type=oneshot, vsaj dve varnostni možnosti in Persistent=true. Preizkusite z systemctl start, oglejte si izpis v journalu in si zapišite oceno systemd-analyze security. Prilepite svoji datoteki .service in .timer ter odgovorite na vprašanja na kontrolnem seznamu.
Naloga O6.3: Lastna storitev s časovnikom
To nalogo opravite sami; nihče je ne pregleda. Odkljukajte, kar ste naredili, in nalogo označite kot opravljeno.
S Persistent=true se opravilo po zagonu vseeno izvede. Ocena pod 6 je dobra za prvo storitev; pravice pisanja samo prek ReadWritePaths.
Vaše kljukice in zapiski ostanejo samo v tem brskalniku, nikamor jih ne pošiljamo. Če ste prijavljeni, v Moji tečaji shranimo samo podatek, da ste nalogo opravili.
Za nadaljnje branje
- Priročnik DirectAdmin 15.1: Cronjob opravila: samodejno izvajanje opravil
- Priročnik
systemd.exec(5)(User=, ProtectSystem=, NoNewPrivileges=): https://manpages.debian.org/trixie/systemd/systemd.exec.5.en.html - Priročnik
systemd.timer(5)(OnCalendar=, Persistent=): https://manpages.debian.org/trixie/systemd/systemd.timer.5.en.html - Priročnik
systemd.time(7)(urniki): https://manpages.debian.org/trixie/systemd/systemd.time.7.en.html
