Modul 6 · 6.3
Egne tjenester og timere
Modul 6: Tjenester og logger · Lesetid: 11 minutter
Læringsmål: Etter denne leksjonen kan du kjøre ditt eget program som en systemd-tjeneste under en egen bruker, med noen sikkerhetsvalg, og planlegge oppgaver med en systemd-timer eller cron.
Nøkkelbegreper: unit-fil, [Unit], [Service], [Install], ExecStart, User=, WorkingDirectory, EnvironmentFile, Restart=, WantedBy, NoNewPrivileges, ProtectSystem, ProtectHome, PrivateTmp, systemd-analyze security, timer, OnCalendar, Persistent, crontab
Hvorfor ikke bare "nohup" eller "screen"?
Når du legger et eget program på en server (en liten webapplikasjon, en bot, et skript som gjør noe hver natt), starter du det ofte for hånd den første gangen: node server.js &, eller i en screen-økt. Det fungerer helt til du logger ut, serveren starter på nytt eller programmet krasjer. Da er det borte, og ingen merker det.
Et program som alltid skal kjøre, bør være en systemd-tjeneste. Da:
- starter det av seg selv ved oppstart;
- starter systemd det på nytt hvis det krasjer;
- havner utdataene i journalen (leksjon 6.2);
- kjører det under en bruker du velger, med de rettighetene du tillater.
En egen unit-fil
La oss si at du har en liten Node.js-applikasjon i /opt/factuurapp som lytter på 127.0.0.1:3000. nginx eller Caddy gjør den tilgjengelig utad senere (modul 7).
Trinn 1: en egen bruker uten skall (leksjon 3.2). Applikasjonen trenger ikke være root og trenger ikke logge inn:
anna@web1:~$ sudo adduser --system --group --home /opt/factuurapp --no-create-home factuurapp
anna@web1:~$ sudo chown -R factuurapp:factuurapp /opt/factuurapp/dataSelve koden kan fortsatt eies av root (applikasjonen trenger ikke endre seg selv); bare mappen den skriver i, eies av tjenestebrukeren.
Trinn 2: unit-filen. Egne units legger du i /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.targetDe tre blokkene:
- [Unit]: beskrivelse og rekkefølge.
After=network-online.targetsammen medWants=sørger for at tjenesten først starter når nettverket er oppe. - [Service]: hvordan programmet kjører.
ExecStartmed full sti (systemd bruker ikke en søkesti slik skallet ditt gjør).User=ogGroup=bestemmer hvem det kjører som.EnvironmentFileleser innstillinger som et databasepassord fra en egen fil, slik at de ikke står i unit-filen. - [Install]: hva
enablegjør.WantedBy=multi-user.targetbetyr: start sammen med en vanlig oppstart.
Trinn 3: hemmeligheter for seg, med strenge rettigheter.
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/envInnholdet er for eksempel DATABASE_URL=postgres://factuur:...@127.0.0.1/factuur. systemd leser filen som root før den bytter til tjenestebrukeren, så 600 eid av root er nok.
Trinn 4: last inn, start, kontroller.
anna@web1:~$ sudo systemctl daemon-reload
anna@web1:~$ sudo systemctl enable --now factuurapp
anna@web1:~$ systemctl status factuurapp
anna@web1:~$ journalctl -u factuurapp -fSikkerhetsvalg: liten innsats, stor forskjell
De fire linjene under RestartSec i eksempelet begrenser hva tjenesten kan gjøre, også hvis noen finner et sikkerhetshull i applikasjonen din:
| Valg | Effekt |
|---|---|
NoNewPrivileges=true | prosessen og barna dens kan aldri få flere rettigheter (heller ikke via sudo eller setuid-programmer) |
ProtectSystem=strict | hele filsystemet er skrivebeskyttet for tjenesten, unntatt det du tillater med ReadWritePaths= |
ProtectHome=true | /home, /root og /run/user er usynlige |
PrivateTmp=true | en egen, tom /tmp som andre programmer ikke ser |
systemd kan vurdere unit-filen din:
anna@web1:~$ systemd-analyze security factuurapp
...
→ Overall exposure level for factuurapp.service: 4.9 OK 🙂Jo lavere tall, jo bedre. En tjeneste uten valg får rundt 9 ("UNSAFE"). Du trenger ikke komme ned til null: hvert valg du legger til, kan ødelegge noe applikasjonen trenger. Legg dem til ett om gangen og test etter hvert trinn. Slutter noe å fungere, står det som regel i journalen ("Read-only file system", "Permission denied").
Planlegge oppgaver: timere
For noe som skal skje til faste tider (en sikkerhetskopi, et oppryddingsskript, en rapport) trenger du en timer. En systemd-timer består av to units med samme navn: en .service som sier hva som skal skje, og en .timer som sier når.
# /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 betyr: programmet kjører og er ferdig etterpå. OnCalendar er tidsplanen: hver dag klokken 03:15. Du kan også skrive daily, weekly eller Mon *-*-* 02:00; systemd-analyze calendar "Mon *-*-* 02:00" viser når det blir neste gang. Persistent=true er viktig: var serveren av klokken 03:15, kjører oppgaven likevel rett etter oppstart. RandomizedDelaySec sprer starttidspunktet litt.
Du slår det på med timeren, ikke med servicen:
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 # test nå én gang manuelt
anna@web1:~$ journalctl -u opruimen.serviceOg cron?
cron er det eldre, enklere verktøyet og fungerer fortsatt fint. En linje i crontab for en bruker (crontab -e):
15 3 * * * /usr/local/bin/opruimen.shDe fem feltene er minutt, time, dag i måneden, måned og ukedag. Fordeler og ulemper side om side:
| cron | systemd-timer | |
|---|---|---|
| Oppsett | én linje | to filer |
| Tapt kjøring (server av) | hoppes over | med Persistent=true likevel |
| Utdata og feil | per e-post, hvis serveren kan sende e-post; ellers borte | i journalen |
| Sikkerhetsvalg, bruker | via selve skriptet | alt fra systemd (avsnittene over) |
| Se når den kjørte | vanskelig | systemctl list-timers og journalen |
For en server du drifter seriøst, er timere det beste valget, særlig for sikkerhetskopier (leksjon 8.2): du vil vite sikkert at de kjørte og hva de sa. En cron-linje som feiler i stillhet, oppdager du først når du trenger sikkerhetskopien.
På AlmaLinux og Rocky Linux
Units og timere fungerer akkurat likt. Én forskjell: SELinux kan stoppe en egen tjeneste som leser eller skriver filer på et sted SELinux ikke forventer, eller som lytter på en uvanlig port. Meldingen står i /var/log/audit/audit.log. Ikke slå av SELinux for å løse det; finn riktig etikett eller regel (for eksempel med semanage).
Oppsummering
- Et program som alltid skal kjøre, bør være en systemd-tjeneste: starter av seg selv, startes på nytt etter krasj, logger i journalen.
- Egne units i
/etc/systemd/system/, medUser=en egen bruker uten skall, hemmeligheter i enEnvironmentFilemed rettigheter 600. NoNewPrivileges,ProtectSystem=strictmedReadWritePaths,ProtectHomeogPrivateTmpbegrenser skaden ved et sikkerhetshull;systemd-analyze securityvurderer unit-filen.- En timer er en
.servicepluss en.timermedOnCalendar;Persistent=truetar igjen tapte kjøringer. Slå på timeren, ikke servicen. - cron fungerer fortsatt, men timere gir bedre logger og går ikke glipp av kjøringer.
Quiz
Oppgave
Oppgave O6.3: En egen tjeneste med timer. Lag en liten egen tjeneste med timer på serveren din, for eksempel et skript som hver natt skriver ledig diskplass og systemctl --failed til en fil eller journalen. Bruk en egen bruker, Type=oneshot, minst to sikkerhetsvalg og Persistent=true. Test med systemctl start, se på utdataene i journalen, og noter poengsummen fra systemd-analyze security. Lim inn .service og .timer, og svar på spørsmålene i sjekklisten.
Oppgave O6.3: En egen tjeneste med timer
Denne oppgaven gjør du selv; ingen kontrollerer den. Kryss av det du har gjort, og merk oppgaven som fullført.
Med Persistent=true kjører oppgaven likevel etter oppstart. En poengsum under 6 er bra for en første tjeneste; skrivetilgang bare via ReadWritePaths.
Avkrysningene og notatene dine blir kun i denne nettleseren; vi sender dem ikke noe sted. Er du logget inn, lagrer vi kun i Mine kurs at du har gjort oppgaven.
Les mer
- DirectAdmin-veiledning 15.1: Cron Jobs: la oppgaver kjøre automatisk
- Manualside
systemd.exec(5)(User=, ProtectSystem=, NoNewPrivileges=): https://manpages.debian.org/trixie/systemd/systemd.exec.5.en.html - Manualside
systemd.timer(5)(OnCalendar=, Persistent=): https://manpages.debian.org/trixie/systemd/systemd.timer.5.en.html - Manualside
systemd.time(7)(tidsplaner): https://manpages.debian.org/trixie/systemd/systemd.time.7.en.html
