Moodul 6 · 6.3
Oma teenused ja taimerid
Moodul 6: Teenused ja logid · Lugemisaeg: 11 minutit
Õpieesmärk: Pärast seda õppetundi oskad käivitada oma programmi systemd-teenusena eraldi kasutaja all koos mõne turvavalikuga ning ajastada ülesandeid systemd-taimeri või croniga.
Põhimõisted: unit-fail, [Unit], [Service], [Install], ExecStart, User=, WorkingDirectory, EnvironmentFile, Restart=, WantedBy, NoNewPrivileges, ProtectSystem, ProtectHome, PrivateTmp, systemd-analyze security, taimer, OnCalendar, Persistent, crontab
Miks mitte lihtsalt "nohup" või "screen"?
Kes paneb serverisse oma programmi (väikese veebirakenduse, boti, skripti, mis igal ööl midagi teeb), käivitab selle esimesel korral sageli käsitsi: node server.js & või screen-seansis. See töötab seni, kuni logid välja, server taaskäivitub või programm jookseb kokku. Siis on see kadunud ja keegi ei märka.
Programm, mis peab alati töötama, peaks olema systemd-teenus. Siis:
- käivitub see alglaadimisel ise;
- käivitab systemd selle krahhi korral uuesti;
- jõuab väljund journalisse (õppetund 6.2);
- töötab see sinu valitud kasutaja all ja nende õigustega, mida sina lubad.
Oma unit-fail
Oletame, et sul on väike Node.js-rakendus kaustas /opt/factuurapp, mis kuulab aadressil 127.0.0.1:3000. nginx või Caddy avab selle hiljem välismaailmale (moodul 7).
Samm 1: eraldi kasutaja ilma shellita (õppetund 3.2). Rakendus ei pea olema root ega pea sisse logima:
anna@web1:~$ sudo adduser --system --group --home /opt/factuurapp --no-create-home factuurapp
anna@web1:~$ sudo chown -R factuurapp:factuurapp /opt/factuurapp/dataKood ise võib jääda root'i omandisse (rakendus ei pea ennast muutma); teenuse kasutajale kuulub ainult kaust, kuhu rakendus kirjutab.
Samm 2: unit-fail. Oma unit'id pane kausta /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.targetKolm plokki:
- [Unit]: kirjeldus ja järjekord.
After=network-online.targetkoosWants=tagab, et teenus käivitub alles siis, kui võrk on olemas. - [Service]: kuidas programm töötab.
ExecStarttäieliku teega (systemd ei kasuta otsinguteed nagu su shell).User=jaGroup=määravad, kelle all see töötab.EnvironmentFileloeb seaded, näiteks andmebaasi parooli, eraldi failist, nii et need ei ole unit'is kirjas. - [Install]: mida teeb
enable.WantedBy=multi-user.targettähendab: käivitu tavalise alglaadimise ajal.
Samm 3: saladused eraldi ja rangete õigustega.
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/envSisu näiteks DATABASE_URL=postgres://factuur:...@127.0.0.1/factuur. systemd loeb faili root'ina enne teenuse kasutajale ümberlülitumist, seega piisab, kui fail on root'i omandis õigustega 600.
Samm 4: laadi, käivita, kontrolli.
anna@web1:~$ sudo systemctl daemon-reload
anna@web1:~$ sudo systemctl enable --now factuurapp
anna@web1:~$ systemctl status factuurapp
anna@web1:~$ journalctl -u factuurapp -fTurvavalikud: vähe vaeva, suur vahe
Näites RestartSec all olevad neli rida piiravad, mida teenus teha saab, ka siis, kui keegi leiab su rakendusest turvaaugu:
| Valik | Mõju |
|---|---|
NoNewPrivileges=true | protsess ja selle alamprotsessid ei saa kunagi rohkem õigusi (ka mitte sudo või setuid-programmide kaudu) |
ProtectSystem=strict | kogu failisüsteem on teenusele ainult loetav, välja arvatud see, mida lubad ReadWritePaths= abil |
ProtectHome=true | /home, /root ja /run/user on nähtamatud |
PrivateTmp=true | oma tühi /tmp, mida teised programmid ei näe |
systemd oskab su unit'it hinnata:
anna@web1:~$ systemd-analyze security factuurapp
...
→ Overall exposure level for factuurapp.service: 4.9 OK 🙂Mida väiksem number, seda parem. Ilma valikuteta teenus saab umbes 9 ("UNSAFE"). Nullini ei pea jõudma: iga lisatud valik võib lõhkuda midagi, mida rakendus vajab. Lisa neid ükshaaval ja testi pärast iga sammu. Kui miski enam ei tööta, leiad põhjuse tavaliselt journalist ("Read-only file system", "Permission denied").
Ülesannete ajastamine: taimerid
Kui midagi peab juhtuma kindlatel aegadel (varukoopia, koristusskript, aruanne), vajad taimerit. systemd-taimer koosneb kahest sama nimega unit'ist: .service ütleb, mida teha, ja .timer ütleb, millal.
# /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 tähendab: programm töötab ja on seejärel valmis. OnCalendar on ajakava: iga päev kell 03:15. Võid kirjutada ka daily, weekly või Mon *-*-* 02:00; systemd-analyze calendar "Mon *-*-* 02:00" näitab, millal see järgmine kord on. Persistent=true on oluline: kui server oli kell 03:15 välja lülitatud, käivitub ülesanne kohe pärast alglaadimist. RandomizedDelaySec hajutab käivitusaega veidi.
Sisse lülitad taimeri, mitte teenuse:
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 # testi nüüd üks kord käsitsi
anna@web1:~$ journalctl -u opruimen.serviceAga cron?
cron on vanem ja lihtsam tööriist ning töötab endiselt hästi. Rida kasutaja crontab'is (crontab -e):
15 3 * * * /usr/local/bin/opruimen.shViis välja on minut, tund, kuupäev, kuu ja nädalapäev. Plussid ja miinused kõrvuti:
| cron | systemd-taimer | |
|---|---|---|
| Seadistamine | üks rida | kaks faili |
| Vahele jäänud käivitus (server väljas) | jäetakse vahele | Persistent=true abil tehakse järele |
| Väljund ja vead | e-postiga, kui server saab kirju saata; muidu kaovad | journalis |
| Turvavalikud, kasutaja | skripti enda kaudu | kõik systemd võimalused (vt eespool) |
| Näha, millal see töötas | keeruline | systemctl list-timers ja journal |
Serveri puhul, mida haldad tõsiselt, on taimerid parem valik, eriti varukoopiate jaoks (õppetund 8.2): tahad kindlalt teada, et need töötasid ja mida need väljastasid. Vaikselt ebaõnnestuvat cron-rida märkad alles siis, kui vajad varukoopiat.
AlmaLinuxis ja Rocky Linuxis
Unit'id ja taimerid töötavad täpselt samamoodi. Üks erinevus: SELinux võib takistada sinu teenust, mis loeb või kirjutab faile kohas, mida SELinux ei oota, või kuulab ebatavalisel pordil. Teade on kirjas failis /var/log/audit/audit.log. Ära lülita SELinuxit lahenduseks välja; otsi õige silt või reegel (näiteks semanage abil).
Kokkuvõte
- Programm, mis peab alati töötama, peaks olema systemd-teenus: käivitub ise, taaskäivitub krahhi korral, logid on journalis.
- Oma unit'id kausta
/etc/systemd/system/,User=abil eraldi kasutaja ilma shellita, saladused failisEnvironmentFileõigustega 600. NoNewPrivileges,ProtectSystem=strictkoosReadWritePaths,ProtectHomejaPrivateTmppiiravad kahju turvaaugu korral;systemd-analyze securityhindab unit'it.- Taimer on
.servicepluss.timerkoosOnCalendar;Persistent=trueteeb vahele jäänud käivitused järele. Lülita sisse taimer, mitte teenus. - cron töötab endiselt, kuid taimerid annavad paremad logid ega jäta käivitusi vahele.
Test (quiz)
Ülesanne
Ülesanne O6.3: Oma teenus koos taimeriga. Loo oma serverisse väike teenus koos taimeriga, näiteks skript, mis kirjutab igal ööl vaba kettaruumi ja systemctl --failed faili või journalisse. Kasuta eraldi kasutajat, Type=oneshot, vähemalt kahte turvavalikut ja Persistent=true. Testi käsuga systemctl start, vaata väljundit journalis ja pane kirja systemd-analyze security hinne. Kleebi oma .service ja .timer ning vasta kontrollnimekirja küsimustele.
Ülesanne O6.3: Oma teenus koos taimeriga
Selle ülesande teed ise, keegi ei kontrolli seda. Märgi ära, mida tegid, ja märgi ülesanne tehtuks.
Persistent=true korral käivitub ülesanne pärast käivitamist tagantjärele. Skoor alla 6 on esimese teenuse jaoks hea; kirjutusõigused ainult ReadWritePaths kaudu.
Su linnukesed ja märkmed jäävad ainult sellesse brauserisse, me ei saada neid kuhugi. Kui oled sisse loginud, salvestame Minu kursustes ainult info, et tegid ülesande ära.
Loe edasi
- DirectAdmin juhend 15.1: Cron Jobs: lase ülesannetel automaatselt käia
- Juhend
systemd.exec(5)(User=, ProtectSystem=, NoNewPrivileges=): https://manpages.debian.org/trixie/systemd/systemd.exec.5.en.html - Juhend
systemd.timer(5)(OnCalendar=, Persistent=): https://manpages.debian.org/trixie/systemd/systemd.timer.5.en.html - Juhend
systemd.time(7)(ajakavad): https://manpages.debian.org/trixie/systemd/systemd.time.7.en.html
