È uscito il Corso Java Completo
Torna al blog

Cos'è systemd e come gestire i servizi Linux

Come funziona systemd, i comandi di systemctl che servono davvero, come scrivere un servizio per la tua app e come leggere i log con journalctl.

Edoardo Midali

Edoardo Midali

Developer · Content Creator

7 min di lettura

Metti online la tua applicazione su un server, la avvii dal terminale, funziona. Poi chiudi la connessione SSH e il sito è offline. Oppure il server si riavvia di notte e nessuno lo sa fino alla mattina. La soluzione a entrambi i problemi si chiama systemd, ed è il componente che su Linux decide cosa parte, quando riparte e cosa succede quando qualcosa muore.

Cos'è

systemd è il primo processo che parte all'avvio di Linux e il responsabile di far partire, fermare e sorvegliare tutti i servizi del sistema.

È il processo con identificativo 1: tutto il resto discende da lui. Gestisce l'ordine di avvio, le dipendenze tra servizi, il riavvio automatico di ciò che si blocca e la raccolta centralizzata dei log.

È lo standard su Debian, Ubuntu, Fedora, Arch e sulla maggior parte delle distribuzioni che incontrerai. Se stai valutando quale usare, il quadro è in cos'è una distro Linux.

Perché ti riguarda concretamente: è la differenza tra un'applicazione che gira finché tieni aperto il terminale e una che si comporta come un servizio vero — parte al boot, riparte se cade, scrive log consultabili.

I comandi che userai

Tutto passa da systemctl:

systemctl status nginx     # come sta
systemctl start nginx      # avvia adesso
systemctl stop nginx       # ferma adesso
systemctl restart nginx    # ferma e riavvia
systemctl reload nginx     # ricarica la configurazione senza interrompere

La distinzione tra start e enable è quella che confonde di più:

systemctl start nginx      # parte ORA (non al prossimo riavvio)
systemctl enable nginx     # parte AL BOOT (non adesso)
systemctl enable --now nginx   # entrambe le cose

Un servizio avviato con start ma senza enable sparisce al primo riavvio del server. È un classico: tutto funziona, poi c'è un riavvio dopo un aggiornamento e il servizio non torna. Usa enable --now e il problema non esiste.

Per capire cosa c'è sul sistema:

systemctl list-units --type=service              # servizi attivi
systemctl list-units --type=service --all        # tutti
systemctl --failed                               # solo quelli in errore
systemctl is-enabled nginx                       # parte al boot?

systemctl --failed è il primo comando da dare quando un server si comporta in modo strano: mostra in una riga cosa non è partito.

Leggere i log

I log di systemd si consultano con journalctl, e questo sostituisce l'andare a cercare file sparsi in /var/log:

journalctl -u nginx              # log di un servizio
journalctl -u nginx -f           # in tempo reale
journalctl -u nginx -n 50        # ultime 50 righe
journalctl -u nginx --since today
journalctl -u nginx --since "1 hour ago"
journalctl -p err -b             # solo errori, da questo avvio

journalctl -u servizio -n 50 --no-pager è la combinazione da ricordare: quando un servizio non parte, la ragione è quasi sempre nelle ultime righe.

Attenzione allo spazio occupato: i log crescono. Per controllarli e limitarli:

journalctl --disk-usage
sudo journalctl --vacuum-time=30d    # tieni 30 giorni

Creare un servizio per la tua applicazione

Questo è il caso d'uso pratico che ti serve davvero. Supponiamo di avere un'applicazione Node.js da tenere online.

Crea /etc/systemd/system/miaapp.service:

[Unit]
Description=La mia applicazione
After=network.target

[Service]
Type=simple
User=deploy
WorkingDirectory=/var/www/miaapp
ExecStart=/usr/bin/node server.js
Restart=always
RestartSec=5
Environment=NODE_ENV=production
Environment=PORT=3000

[Install]
WantedBy=multi-user.target

Poi:

sudo systemctl daemon-reload      # rileggi i file cambiati
sudo systemctl enable --now miaapp
systemctl status miaapp

daemon-reload va dato ogni volta che modifichi un file .service. Dimenticarlo significa vedere systemd usare ancora la versione precedente, ed è una fonte di confusione ricorrente: modifichi, riavvii, e nulla cambia.

Cosa significano le righe che contano

After=network.target — non partire prima che la rete sia pronta. Per un'applicazione che ascolta su una porta è quasi sempre necessario.

User=deploy — esegui come utente non privilegiato. Non far girare la tua applicazione come root: è la regola di sicurezza più elementare e più ignorata. Se l'applicazione viene compromessa, l'attaccante eredita i suoi permessi.

Restart=always con RestartSec=5 — se il processo termina, riavvialo dopo 5 secondi. Questa è la riga che rende il servizio resistente ai crash.

Environment= — variabili d'ambiente. Per i valori riservati come le chiavi API, meglio un file separato con permessi ristretti:

EnvironmentFile=/etc/miaapp/env

Così le credenziali non finiscono in un file leggibile da tutti.

WantedBy=multi-user.target — è la riga che rende effettivo enable, cioè l'avvio automatico al boot.

Timer: l'alternativa moderna a cron

systemd può anche eseguire cose a orari stabiliti, con un vantaggio rispetto a cron: i log finiscono nel journal come per qualsiasi altro servizio, invece di sparire o richiedere una redirezione manuale.

Servono due file. /etc/systemd/system/backup.service:

[Unit]
Description=Backup giornaliero

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh

E /etc/systemd/system/backup.timer:

[Unit]
Description=Esegui il backup ogni giorno

[Timer]
OnCalendar=daily
Persistent=true

[Install]
WantedBy=timers.target

Poi:

sudo systemctl enable --now backup.timer
systemctl list-timers            # cosa è programmato e quando

Persistent=true è il vantaggio pratico più concreto: se il server era spento all'orario previsto, l'attività viene eseguita al successivo avvio. Cron, semplicemente, salta l'esecuzione.

Diagnosticare un servizio che non parte

La sequenza da seguire, in ordine:

systemctl status miaapp          # 1. stato ed errore riassuntivo
journalctl -u miaapp -n 50       # 2. cosa dicono i log
systemd-analyze verify /etc/systemd/system/miaapp.service   # 3. il file è valido?

Le cause più frequenti, nella mia esperienza:

Percorso non assoluto in ExecStart. systemd non usa il tuo PATH: node server.js non funziona, serve /usr/bin/node server.js. È la causa numero uno.

Permessi. L'utente indicato non può leggere la cartella di lavoro o scrivere dove serve.

Variabili d'ambiente mancanti. L'applicazione funziona nel tuo terminale perché il tuo profilo carica variabili che systemd non conosce.

daemon-reload dimenticato dopo una modifica.

Il processo va in background da solo. Con Type=simple systemd si aspetta che il programma resti in primo piano. Se il programma si stacca, systemd lo considera terminato. In quel caso serve Type=forking.

systemd o Docker?

Domanda legittima, visto che entrambi risolvono "tieni in piedi il mio processo".

systemdDocker
Già presenteDa installare
IsolamentoLimitatoBuono
Dipendenze impacchettateNo
ComplessitàBassaMedia
Adatto aUn server, poche appPiù app, più ambienti

Per una singola applicazione su un VPS, systemd basta e avanza ed è una cosa in meno da gestire. Docker inizia a ripagare quando hai più servizi, o quando ti serve che l'ambiente sia identico ovunque — vedi cos'è Docker.

Nota che le due cose convivono benissimo: Docker stesso, sul server, è avviato da systemd.

In sintesi

systemd è il gestore dei servizi di Linux: decide cosa parte all'avvio, riavvia ciò che cade e centralizza i log.

Le due cose da ricordare: enable --now per avviare adesso e anche al boot, e journalctl -u nome -n 50 quando qualcosa non va.

Per la tua applicazione, un file .service di quindici righe con Restart=always e un utente dedicato la trasforma da processo che vive quanto la tua sessione SSH a servizio che si riprende da solo.

Se stai mettendo in piedi un server adesso, il percorso completo è in come configurare un VPS da zero. Se vuoi che l'applicazione sia raggiungibile via dominio e HTTPS, il pezzo mancante è cos'è un reverse proxy.