Salta al contenuto principale

systemctl: avviare, fermare e controllare i servizi

Inviato da tuxsa il

Un server web, un database, il servizio SSH, la rete: sono tutti servizi che girano in background. Con systemctl si controlla se funzionano, si avviano, si fermano, si riavviano e si decide se devono partire all'accensione del computer. È il comando che userai più spesso quando gestisci un server.

Cos'è

systemctl è lo strumento di controllo di systemd, il sistema che avvia il computer e gestisce i servizi in quasi tutte le distribuzioni moderne (Debian, Ubuntu, Fedora, Arch e molte altre). Il lavoro è organizzato in unità (unit), ciascuna descritta da un file di configurazione. Le più comuni sono i servizi (nginx.service) e i timer (backup.timer); esistono anche .socket, .mount e .target (gruppi di unità, come multi-user.target). Per i servizi l'estensione .service si può omettere: systemctl status nginx equivale a nginx.service.

Cosa fa

Mostra lo stato delle unità e le gestisce: le avvia e ferma subito, le abilita o disabilita all'avvio del sistema, chiede loro di rileggere la configurazione, elenca quelle attive o in errore. Quasi tutte le operazioni che modificano qualcosa richiedono i privilegi di amministratore, quindi si usa sudo; quelle che mostrano soltanto lo stato no.

Come si usa

$ systemctl [opzioni] comando [unità]

Gli esempi usano servizi comuni su Debian e Ubuntu (nginx, ssh, cron); i nomi dipendono da ciò che hai installato (per esempio, il servizio SSH è ssh su Debian e Ubuntu e sshd su Fedora, il database può chiamarsi mariadb o mysql).

Esempio 1: lo stato di un servizio

$ systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: enabled)
     Active: active (running) since Mon 2026-10-19 08:12:41 CEST; 2 days ago
       Docs: man:nginx(8)
    Process: 912 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
   Main PID: 925 (nginx)
      Tasks: 3 (limit: 4558)
     Memory: 8.2M
        CPU: 1.204s
     CGroup: /system.slice/nginx.service
             ├─925 "nginx: master process /usr/sbin/nginx -g daemon on; master_process on;"
             └─927 "nginx: worker process"

ott 21 04:57:01 server nginx[925]: ...

È il comando più utile. Le righe da leggere sono: Loaded (il file di configurazione e se parte all'avvio: enabled o disabled), Active (lo stato: active (running) funziona; inactive (dead) è fermo; failed è terminato con un errore) e in fondo le ultime righe di registro del servizio, spesso sufficienti a capire cosa non va. Si esce con q.

Esempio 2: avviare, fermare, riavviare

$ sudo systemctl start nginx
$ sudo systemctl stop nginx
$ sudo systemctl restart nginx
$ sudo systemctl reload nginx

I comandi non stampano nulla se tutto va bene. restart ferma e riavvia il servizio (con una breve interruzione); reload gli chiede di rileggere la configurazione senza fermarsi, se il programma lo supporta (nginx, apache, sshd e molti altri): è preferibile in produzione perché non interrompe le connessioni attive. Esiste anche try-restart e reload-or-restart, che fa il reload se possibile e altrimenti il restart.

Esempio 3: avviare all'accensione con enable

$ sudo systemctl enable nginx
Created symlink /etc/systemd/system/multi-user.target.wants/nginx.service → /usr/lib/systemd/system/nginx.service.
$ sudo systemctl disable nginx
Removed "/etc/systemd/system/multi-user.target.wants/nginx.service".
$ sudo systemctl enable --now nginx
$ sudo systemctl disable --now nginx

start e enable sono cose diverse. start avvia il servizio adesso, ma non dice nulla sul prossimo avvio del computer. enable lo fa partire a ogni accensione, ma non lo avvia adesso (crea un collegamento simbolico, come si vede nel messaggio). Con --now si fanno le due cose insieme: enable --now abilita e avvia, disable --now disabilita e ferma.

Esempio 4: sapere se un servizio è attivo (nel terminale e negli script)

$ systemctl is-active nginx
active
$ systemctl is-enabled nginx
enabled
$ systemctl is-failed nginx
active
$ systemctl is-active --quiet nginx && echo "nginx è in funzione"
nginx è in funzione

I comandi is-active, is-enabled e is-failed stampano una sola parola (active, inactive, failed, enabled, disabled…) e hanno un codice di uscita pensato per gli script: 0 se la condizione è vera. Con --quiet non stampano nulla.

Esempio 5: elencare i servizi

$ systemctl list-units --type=service
  UNIT                     LOAD   ACTIVE SUB     DESCRIPTION
  cron.service             loaded active running Regular background program processing daemon
  nginx.service            loaded active running A high performance web server
  ssh.service              loaded active running OpenBSD Secure Shell server
  ...
$ systemctl list-units --type=service --state=running
$ systemctl list-unit-files --type=service | grep enabled
$ systemctl --failed
  UNIT              LOAD   ACTIVE SUB    DESCRIPTION
● mariadb.service   loaded failed failed MariaDB database server

list-units mostra le unità attualmente in memoria; con --type=service solo i servizi e con --state=running solo quelli in esecuzione. list-unit-files elenca tutti i file installati con il loro stato di abilitazione. systemctl --failed mostra solo ciò che è in errore, ed è un buon primo controllo dopo l'avvio di un server. Il pallino ● segnala un'unità con un problema.

Esempio 6: leggere i registri con journalctl

$ journalctl -u nginx
$ journalctl -u nginx -n 50 --no-pager
$ journalctl -u nginx -f
$ journalctl -u nginx --since "1 hour ago"
$ journalctl -p err -b

I messaggi dei servizi finiscono nel journal di systemd, che si legge con journalctl, il compagno inseparabile di systemctl. Con -u unità si filtra per servizio, -n 50 mostra le ultime 50 righe, -f segue i messaggi man mano che arrivano (come tail -f; si esce con Ctrl+C), --since limita nel tempo e -p err -b mostra gli errori dall'ultimo avvio. Con --no-pager l'output non passa per less, utile se lo si invia a un altro comando.

Esempio 7: dopo una modifica alla configurazione

$ sudo nano /etc/nginx/sites-available/miosito
$ sudo nginx -t
nginx: configuration file /etc/nginx/nginx.conf test is successful
$ sudo systemctl reload nginx
$ systemctl status nginx --no-pager | head -n 4

Un flusso di lavoro tipico: si modifica il file, si verifica la sintassi con lo strumento del programma (qui nginx -t) e solo dopo si applica la modifica con reload. Così un errore di battitura non butta giù il sito. Infine si controlla lo stato.

Esempio 8: un servizio che non parte

$ sudo systemctl start mariadb
Job for mariadb.service failed because the control process exited with error code.
See "systemctl status mariadb.service" and "journalctl -xeu mariadb.service" for details.
$ systemctl status mariadb --no-pager
× mariadb.service - MariaDB 10.11.6 database server
     Active: failed (Result: exit-code) since ...
$ journalctl -xeu mariadb.service --no-pager | tail -n 20

Quando un servizio non parte, il messaggio d'errore indica già i due comandi da usare: systemctl status per lo stato e le ultime righe, journalctl -xeu unità per i dettagli (-x aggiunge spiegazioni, -e salta alla fine, -u filtra per unità). Il motivo più frequente è nelle ultime righe: file mancante, porta già occupata, errore di configurazione, permessi sbagliati.

Esempio 9: leggere o modificare un'unità

$ systemctl cat nginx
# /usr/lib/systemd/system/nginx.service
[Unit]
Description=A high performance web server and a reverse proxy server
After=network.target
[Service]
ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;'
...
$ sudo systemctl edit nginx
$ sudo systemctl daemon-reload

systemctl cat mostra il file dell'unità. Non conviene modificare i file in /usr/lib/systemd/system/, perché un aggiornamento del pacchetto li sovrascrive: sudo systemctl edit nome apre un editor per creare un file di modifiche (un drop-in, salvato in /etc/systemd/system/nome.service.d/override.conf) che si applica sopra l'originale. Dopo aver modificato a mano un file di unità si esegue sudo systemctl daemon-reload, per fare rileggere a systemd tutti i file; systemctl edit lo fa automaticamente. Per applicare le modifiche al servizio serve poi un restart.

Esempio 10: creare un proprio servizio

$ sudo nano /etc/systemd/system/mio-script.service
[Unit]
Description=Il mio script
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=enzo
WorkingDirectory=/home/enzo/progetto
ExecStart=/usr/bin/python3 /home/enzo/progetto/app.py
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
$ sudo systemctl daemon-reload
$ sudo systemctl enable --now mio-script
$ systemctl status mio-script --no-pager

Per far girare un proprio programma come servizio basta un piccolo file in /etc/systemd/system/. Le sezioni sono tre: [Unit] (descrizione e ordine di avvio), [Service] (utente, cartella, comando da eseguire con percorsi assoluti, riavvio automatico con Restart=on-failure) e [Install] (in quale target inserirlo quando lo si abilita). Dopo daemon-reload, enable --now lo attiva subito e a ogni avvio. Rispetto a cron e a nohup, systemd tiene il programma sotto controllo, lo riavvia se cade e ne conserva i registri.

Esempio 11: i timer, l'alternativa moderna a cron

$ systemctl list-timers
NEXT                        LEFT          LAST                        PASSED   UNIT                         ACTIVATES
Thu 2026-10-22 00:00:00 CEST 19h left     Wed 2026-10-21 00:00:01 CEST 4h ago   dpkg-db-backup.timer         dpkg-db-backup.service
Thu 2026-10-22 06:12:33 CEST 1h 15min left Wed 2026-10-21 06:09:11 CEST ...      apt-daily-upgrade.timer      apt-daily-upgrade.service

Un timer è un'unità che avvia un servizio a una certa ora o a intervalli. Rispetto a cron recupera i lavori saltati a computer spento (con Persistent=true) e salva i registri nel journal. list-timers mostra quelli attivi con il prossimo e l'ultimo avvio. Nella tabella di cron si scrive una riga; con un timer servono due file (.service e .timer), ma si ottiene più controllo.

Esempio 12: riavviare o spegnere il computer, e il livello di avvio

$ sudo systemctl reboot
$ sudo systemctl poweroff
$ systemctl get-default
graphical.target
$ sudo systemctl set-default multi-user.target

reboot e poweroff riavviano e spengono il computer. get-default mostra in quale modalità il sistema si avvia: graphical.target con ambiente grafico, multi-user.target solo testuale (la scelta tipica di un server). Questo comando è sensibile: cambiarlo su un computer da scrivania significa ritrovarsi senza desktop al prossimo avvio.

Esempio 13: mascherare, e controllare i servizi dell'utente

$ sudo systemctl mask apache2
Created symlink /etc/systemd/system/apache2.service → /dev/null.
$ sudo systemctl unmask apache2
$ systemctl --user status pipewire
$ systemctl --user list-units --type=service

Con mask un servizio viene reso impossibile da avviare, anche manualmente o come dipendenza di altri servizi (diverso da disable, che toglie solo l'avvio automatico); si annulla con unmask. Con --user si gestiscono i servizi dell'utente corrente, senza sudo: sono quelli della sessione, come l'audio con PipeWire.

Opzioni utili

  • status: stato e ultime righe di registro; is-active, is-enabled, is-failed: una sola parola, adatte agli script.
  • start / stop / restart / reload / reload-or-restart: gestione immediata.
  • enable / disable: partenza all'avvio del sistema; --now: fa anche l'operazione immediata.
  • mask / unmask: blocca completamente un'unità / annulla.
  • list-units, list-unit-files, list-timers, --failed: elenchi.
  • --type=service, --state=running, -a: filtri per list-units.
  • cat / edit / daemon-reload: leggere, modificare e ricaricare i file delle unità.
  • show nome -p Proprietà: valori delle proprietà di un'unità, adatti agli script.
  • --user: servizi dell'utente corrente; --no-pager: niente less.
  • reboot, poweroff, get-default, set-default: riavvio, spegnimento e modalità di avvio.

Attenzione a

  • start non è enable: un servizio avviato a mano non ripartirà al prossimo avvio, e uno abilitato non è per forza in funzione adesso. Per entrambe le cose, enable --now.
  • reload o restart? restart interrompe il servizio, anche se per poco; reload rilegge la configurazione senza fermarlo, ma non tutti i servizi lo supportano (in tal caso dà errore). Dopo un reload controlla comunque lo stato.
  • Verifica la configurazione prima di applicarla: strumenti come nginx -t o apachectl configtest evitano di fermare un sito per un errore di battitura. Fermare un servizio con una configurazione sbagliata e provare a riavviarlo è il modo più rapido di restare senza sito.
  • Non fermare ciò da cui dipendi: fermare ssh mentre sei collegato via SSH può chiuderti fuori (la sessione già aperta in genere resta, ma una nuova connessione può non essere più possibile, a seconda di come è configurato il servizio). Lo stesso vale per i servizi di rete. Su un server remoto, prima di stop, restart o disable di servizi come ssh o la rete, tieni aperta una seconda sessione di riserva.
  • Dopo aver modificato un file di unità, daemon-reload: senza, systemd usa ancora la vecchia versione e avvisa con "The unit file changed on disk".
  • Non modificare i file in /usr/lib/systemd/system/: gli aggiornamenti li sovrascrivono. Usa systemctl edit o i file in /etc/systemd/system/.
  • Percorsi assoluti nelle unità: in ExecStart il programma va indicato con il percorso completo (/usr/bin/python3), e l'ambiente del servizio è minimo, come in cron. Reindirizzamenti, pipe e variabili della shell non funzionano direttamente: per usarli si lancia /bin/bash -c '...'.
  • Servizi che si riavviano all'infinito: con Restart=always un programma che si chiude subito viene rilanciato di continuo (systemd si ferma dopo troppi tentativi ravvicinati, con lo stato failed, ma consumando risorse). Controlla sempre il registro.
  • Modalità di arresto brusche: systemctl poweroff e reboot spengono subito il computer; su un server remoto verifica di essere sul computer giusto prima di digitarli.
  • I nomi dei servizi variano: ssh o sshd, apache2 o httpd, mysql o mariadb. Con systemctl list-unit-files | grep nome o la funzione di completamento con Tab trovi quello giusto.
  • Non tutto usa systemd: alcune distribuzioni (Alpine, Void, Devuan, Gentoo con OpenRC) e i container Docker normalmente non lo usano: in quel caso systemctl non funziona e servono altri strumenti (rc-service, sv, service). Dentro un container si usa il comando del contenitore (docker restart, docker compose), non systemctl.
  • I servizi non sono processi qualsiasi: un programma avviato a mano (per esempio nginx dal terminale) non è conosciuto da systemd, che mostrerà il servizio come fermo anche se il programma è in esecuzione. Se vuoi che systemd lo gestisca, avvialo solo con systemctl.
  • Il vecchio comando service: sudo service nginx restart funziona ancora (chiama systemctl) ed è molto diffuso in guide e tutorial; la sintassi è semplicemente service nome comando, con l'ordine diverso.

Riepilogo

ComandoCosa fa
systemctl status nomeStato del servizio e ultime righe di registro
sudo systemctl start nomeAvvia ora
sudo systemctl stop nomeFerma ora
sudo systemctl restart nomeFerma e riavvia
sudo systemctl reload nomeRilegge la configurazione senza fermarsi
sudo systemctl enable --now nomeAbilita all'avvio e avvia subito
sudo systemctl disable --now nomeDisabilita e ferma
systemctl is-active nomeStampa active / inactive / failed
systemctl --failedElenca le unità in errore
systemctl list-units --type=serviceElenca i servizi caricati
systemctl list-timersElenca i timer
journalctl -u nome -fSegue i registri del servizio
journalctl -xeu nomeRegistri con dettagli per capire un errore
systemctl cat nome / sudo systemctl edit nomeLegge / modifica la configurazione di un'unità
sudo systemctl daemon-reloadRilegge i file delle unità
sudo systemctl mask nomeImpedisce del tutto l'avvio
systemctl --user ...Gestisce i servizi dell'utente corrente