Gå til innholdet

Cookie-innstillinger

Velg hvilke typer cookies du tillater. Du kan når som helst endre valget via Cookie-innstillinger nederst på hver side. Personvernerklæring

Nødvendige

Alltid på

Trengs for å logge inn, beholde handlekurven og huske valgene dine. Disse er alltid på.

Hvilke cookies?
  • weboke_sessie, weboke_klant, weboke_remember: økten din og at du forblir innlogget
  • weboke_basket: handlekurven din
  • wkBtwIncl: visning av priser med eller uten mva.
  • wok_cookies: cookievalget ditt, 12 måneder

Måler hvilken annonse som fører til et besøk eller en bestilling, slik at vi ikke betaler for annonser som ikke gir noe.

Hvilke cookies?
  • Google Ads via Google Tag Manager (_gcl_au, _gcl_aw), opptil 90 dager
  • OpenAI Ads, annonser i ChatGPT
  • wok_aff: hvilken partner som henviste deg til oss (partnerprogram), 60 dager

4,6

Land og språk

Hvert land har sin egen nettside, med priser og mva. for det landet.

Vis

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

Selve 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.target

De tre blokkene:

  • [Unit]: beskrivelse og rekkefølge. After=network-online.target sammen med Wants= sørger for at tjenesten først starter når nettverket er oppe.
  • [Service]: hvordan programmet kjører. ExecStart med full sti (systemd bruker ikke en søkesti slik skallet ditt gjør). User= og Group= bestemmer hvem det kjører som. EnvironmentFile leser innstillinger som et databasepassord fra en egen fil, slik at de ikke står i unit-filen.
  • [Install]: hva enable gjør. WantedBy=multi-user.target betyr: 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/env

Innholdet 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 -f

Sikkerhetsvalg: 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:

ValgEffekt
NoNewPrivileges=trueprosessen og barna dens kan aldri få flere rettigheter (heller ikke via sudo eller setuid-programmer)
ProtectSystem=stricthele filsystemet er skrivebeskyttet for tjenesten, unntatt det du tillater med ReadWritePaths=
ProtectHome=true/home, /root og /run/user er usynlige
PrivateTmp=trueen 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.target

Type=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.service

Og 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.sh

De fem feltene er minutt, time, dag i måneden, måned og ukedag. Fordeler og ulemper side om side:

cronsystemd-timer
Oppsettén linjeto filer
Tapt kjøring (server av)hoppes overmed Persistent=true likevel
Utdata og feilper e-post, hvis serveren kan sende e-post; ellers bortei journalen
Sikkerhetsvalg, brukervia selve skriptetalt fra systemd (avsnittene over)
Se når den kjørtevanskeligsystemctl 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/, med User= en egen bruker uten skall, hemmeligheter i en EnvironmentFile med rettigheter 600.
  • NoNewPrivileges, ProtectSystem=strict med ReadWritePaths, ProtectHome og PrivateTmp begrenser skaden ved et sikkerhetshull; systemd-analyze security vurderer unit-filen.
  • En timer er en .service pluss en .timer med OnCalendar; Persistent=true tar 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

1. Applikasjonen din kjører som tjeneste med User=root. Hvorfor er en egen bruker bedre?



2. Du har laget en .service og en .timer. Hva slår du på med enable --now?



3. Hva gjør Persistent=true i en timer?



4. Du legger til ProtectSystem=strict, og etterpå gir applikasjonen "Read-only file system" når den lagrer opplastinger. Hva er riktig løsning?



5. Hvor legger du databasepassordet for din egen tjeneste?



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.




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

Et øyeblikk …

Sett opp domenene dine

Ordne for hvert domene navnetjenerne, koblingen til hostingen din og hvem som blir innehaver.

Laster inn domenene dine…