Hoppa till innehållet

Cookieinställningar

Välj vilka typer av cookies du tillåter. Du kan alltid ändra ditt val via Cookieinställningar längst ned på varje sida. Integritetspolicy

Nödvändiga

Alltid på

Behövs för att logga in, spara din varukorg och komma ihåg dina val. De är alltid på.

Vilka cookies?
  • weboke_sessie, weboke_klant, weboke_remember: din session och att du förblir inloggad
  • weboke_basket: din varukorg
  • wkBtwIncl: visa priser med eller utan moms
  • wok_cookies: ditt cookieval, 12 månader

Mäter vilken annons som leder till ett besök eller en beställning, så att vi inte betalar för annonser som inte ger något.

Vilka cookies?
  • Google Ads via Google Tag Manager (_gcl_au, _gcl_aw), upp till 90 dagar
  • OpenAI Ads, annonser i ChatGPT
  • wok_aff: via vilken partner du kom till oss (affiliateprogram), 60 dagar

4,6

Land och språk

Varje land har en egen webbplats med landets priser och moms.

Visa

Egna tjänster och timers

Modul 6: Tjänster och loggar · Lästid: 11 minuter

Lärandemål: Efter den här lektionen kan du köra ett eget program som en systemd-tjänst under en egen användare, med några säkerhetsalternativ, och schemalägga uppgifter med en systemd-timer eller cron.

Nyckelbegrepp: unit-fil, [Unit], [Service], [Install], ExecStart, User=, WorkingDirectory, EnvironmentFile, Restart=, WantedBy, NoNewPrivileges, ProtectSystem, ProtectHome, PrivateTmp, systemd-analyze security, timer, OnCalendar, Persistent, crontab

Varför inte bara "nohup" eller "screen"?

Den som lägger ett eget program på en server (en liten webbapplikation, en bot, ett skript som gör något varje natt) startar det ofta för hand första gången: node server.js &, eller i en screen-session. Det fungerar tills du loggar ut, servern startas om eller programmet kraschar. Då är det borta, och ingen märker det.

Ett program som alltid ska vara igång bör vara en systemd-tjänst. Då:

  • startar det automatiskt när servern startar;
  • startar systemd om det om det kraschar;
  • hamnar utdata i journalen (lektion 6.2);
  • körs det under en användare som du väljer, med de rättigheter som du tillåter.

En egen unit-fil

Säg att du har en liten Node.js-applikation i /opt/factuurapp som lyssnar på 127.0.0.1:3000. nginx eller Caddy gör den senare nåbar utifrån (modul 7).

Steg 1: en egen användare utan skal (lektion 3.2). Applikationen behöver inte vara root och behöver inte logga in:

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

Själva koden får fortsätta att ägas av root (applikationen behöver inte ändra sig själv); bara mappen som den skriver till ägs av tjänstanvändaren.

Steg 2: unit-filen. Egna units lägger 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 blocken:

  • [Unit]: beskrivning och ordning. After=network-online.target tillsammans med Wants= gör att tjänsten startar först när nätverket finns.
  • [Service]: hur programmet körs. ExecStart med hela sökvägen (systemd använder ingen sökväg som ditt skal gör). User= och Group= bestämmer under vem. EnvironmentFile läser inställningar som ett databaslösenord från en separat fil, så att de inte står i unit-filen.
  • [Install]: vad enable gör. WantedBy=multi-user.target betyder: starta med vid en vanlig uppstart.

Steg 3: hemligheter separat, med strikta rättigheter.

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

Innehållet kan till exempel vara DATABASE_URL=postgres://factuur:...@127.0.0.1/factuur. systemd läser filen som root innan den byter till tjänstanvändaren, så 600 ägd av root räcker.

Steg 4: läs in, starta, kontrollera.

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

Säkerhetsalternativ: liten insats, stor skillnad

De fyra raderna under RestartSec i exemplet begränsar vad tjänsten kan göra, även om någon hittar en sårbarhet i din applikation:

AlternativEffekt
NoNewPrivileges=trueprocessen och dess barnprocesser kan aldrig få fler rättigheter (inte heller via sudo eller setuid-program)
ProtectSystem=stricthela filsystemet är skrivskyddat för tjänsten, utom det du tillåter med ReadWritePaths=
ProtectHome=true/home, /root och /run/user är osynliga
PrivateTmp=trueen egen, tom /tmp som andra program inte ser

systemd kan bedöma din unit:

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

Ju lägre siffra, desto bättre. En tjänst utan alternativ får runt 9 ("UNSAFE"). Du behöver inte komma ner till noll: varje alternativ du lägger till kan förstöra något som applikationen behöver. Lägg till dem ett i taget och testa efter varje steg. Slutar något att fungera står det oftast i journalen ("Read-only file system", "Permission denied").

Schemalägga uppgifter: timers

För något som ska hända på fasta tider (en säkerhetskopia, ett städskript, en rapport) behöver du en timer. En systemd-timer består av två units med samma namn: en .service som säger vad som ska hända, och en .timer som säger 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 betyder: programmet körs och är sedan klart. OnCalendar är tidsschemat: varje dag kl. 03:15. Du kan också skriva daily, weekly eller Mon *-*-* 02:00; systemd-analyze calendar "Mon *-*-* 02:00" visar när det blir nästa gång. Persistent=true är viktigt: var servern avstängd kl. 03:15 körs uppgiften direkt efter uppstarten i stället. RandomizedDelaySec sprider ut starttiden lite.

Du aktiverar timern, inte tjänsten:

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    # testa nu en gång manuellt
anna@web1:~$ journalctl -u opruimen.service

Och cron?

cron är det äldre, enklare verktyget och fungerar fortfarande bra. En rad i en användares crontab (crontab -e):

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

De fem fälten är minut, timme, dag i månaden, månad och veckodag. För- och nackdelar sida vid sida:

cronsystemd-timer
Konfigureraen radtvå filer
Missad körning (servern avstängd)hoppas övermed Persistent=true körs den ändå
Utdata och felvia e-post, om servern kan skicka e-post; annars bortai journalen
Säkerhetsalternativ, användarevia själva skriptetallt från systemd (se ovan)
Se när den kördesbesvärligtsystemctl list-timers och journalen

För en server som du förvaltar på allvar är timers det bättre valet, särskilt för säkerhetskopior (lektion 8.2): du vill veta säkert att de kördes och vad de sa. En cronrad som tyst misslyckas märker du först när du behöver säkerhetskopian.

På AlmaLinux och Rocky Linux

Units och timers fungerar exakt likadant. En skillnad: SELinux kan stoppa en egen tjänst som läser eller skriver filer på en plats som SELinux inte förväntar sig, eller som lyssnar på en ovanlig port. Meddelandet finns i /var/log/audit/audit.log. Stäng inte av SELinux för att lösa det; leta upp rätt etikett eller regel (till exempel med semanage).

Sammanfattning

  • Ett program som alltid ska vara igång bör vara en systemd-tjänst: startar automatiskt, startas om vid en krasch, loggar i journalen.
  • Egna units i /etc/systemd/system/, med User= en egen användare utan skal, hemligheter i en EnvironmentFile med rättigheterna 600.
  • NoNewPrivileges, ProtectSystem=strict med ReadWritePaths, ProtectHome och PrivateTmp begränsar skadan vid en sårbarhet; systemd-analyze security bedömer din unit.
  • En timer är en .service plus en .timer med OnCalendar; Persistent=true tar igen missade körningar. Aktivera timern, inte tjänsten.
  • cron fungerar fortfarande, men timers ger bättre loggar och missar inga körningar.

Quiz

1. Din applikation körs som tjänst med User=root. Varför är en egen användare bättre?



2. Du har skapat en .service och en .timer. Vad aktiverar du med enable --now?



3. Vad gör Persistent=true i en timer?



4. Du lägger till ProtectSystem=strict och därefter ger din applikation "Read-only file system" när uppladdningar sparas. Vilken är rätt lösning?



5. Var lägger du databaslösenordet för din egen tjänst?



Uppgift

Uppgift O6.3: En egen tjänst med timer. Skapa en liten egen tjänst med en timer på din server, till exempel ett skript som varje natt skriver det lediga diskutrymmet och systemctl --failed till en fil eller till journalen. Använd en egen användare, Type=oneshot, minst två säkerhetsalternativ och Persistent=true. Testa med systemctl start, titta på utdata i journalen och anteckna poängen från systemd-analyze security. Klistra in din .service och .timer och besvara frågorna i checklistan.

Uppgift O6.3: En egen tjänst med timer

Den här uppgiften gör du själv; ingen kontrollerar den. Bocka av vad du har gjort och markera uppgiften som klar.




Dina bockar och anteckningar sparas bara i den här webbläsaren; vi skickar dem ingenstans. Är du inloggad sparar vi i Mina kurser bara att du har gjort uppgiften.

Läs mer

Ett ögonblick…

Ställ in dina domäner

Ställ in namnservrar, koppling till ditt webbhotell och vem som blir innehavare för varje domän.

Hämtar dina domäner…