Modul 6 · 6.3
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/dataSjä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.targetDe tre blocken:
- [Unit]: beskrivning och ordning.
After=network-online.targettillsammans medWants=gör att tjänsten startar först när nätverket finns. - [Service]: hur programmet körs.
ExecStartmed hela sökvägen (systemd använder ingen sökväg som ditt skal gör).User=ochGroup=bestämmer under vem.EnvironmentFileläser inställningar som ett databaslösenord från en separat fil, så att de inte står i unit-filen. - [Install]: vad
enablegör.WantedBy=multi-user.targetbetyder: 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/envInnehå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 -fSä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:
| Alternativ | Effekt |
|---|---|
NoNewPrivileges=true | processen och dess barnprocesser kan aldrig få fler rättigheter (inte heller via sudo eller setuid-program) |
ProtectSystem=strict | hela filsystemet är skrivskyddat för tjänsten, utom det du tillåter med ReadWritePaths= |
ProtectHome=true | /home, /root och /run/user är osynliga |
PrivateTmp=true | en 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.targetType=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.serviceOch 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.shDe fem fälten är minut, timme, dag i månaden, månad och veckodag. För- och nackdelar sida vid sida:
| cron | systemd-timer | |
|---|---|---|
| Konfigurera | en rad | två filer |
| Missad körning (servern avstängd) | hoppas över | med Persistent=true körs den ändå |
| Utdata och fel | via e-post, om servern kan skicka e-post; annars borta | i journalen |
| Säkerhetsalternativ, användare | via själva skriptet | allt från systemd (se ovan) |
| Se när den kördes | besvärligt | systemctl 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/, medUser=en egen användare utan skal, hemligheter i enEnvironmentFilemed rättigheterna 600. NoNewPrivileges,ProtectSystem=strictmedReadWritePaths,ProtectHomeochPrivateTmpbegränsar skadan vid en sårbarhet;systemd-analyze securitybedömer din unit.- En timer är en
.serviceplus en.timermedOnCalendar;Persistent=truetar igen missade körningar. Aktivera timern, inte tjänsten. - cron fungerar fortfarande, men timers ger bättre loggar och missar inga körningar.
Quiz
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.
Med Persistent=true körs uppgiften ändå efter uppstart. Ett betyg under 6 är bra för en första tjänst; skrivrättigheter bara via ReadWritePaths.
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
- DirectAdmin-guide 15.1: Cron-jobb: låt uppgifter köras automatiskt
- Manualsidan
systemd.exec(5)(User=, ProtectSystem=, NoNewPrivileges=): https://manpages.debian.org/trixie/systemd/systemd.exec.5.en.html - Manualsidan
systemd.timer(5)(OnCalendar=, Persistent=): https://manpages.debian.org/trixie/systemd/systemd.timer.5.en.html - Manualsidan
systemd.time(7)(tidsscheman): https://manpages.debian.org/trixie/systemd/systemd.time.7.en.html
