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.
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".
| systemd | Docker | |
|---|---|---|
| Già presente | Sì | Da installare |
| Isolamento | Limitato | Buono |
| Dipendenze impacchettate | No | Sì |
| Complessità | Bassa | Media |
| Adatto a | Un server, poche app | Più 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.