Tech Insights

Troubleshooting Linux: 10 scenari reali da colloquio sistemista

Dieci casi pratici di troubleshooting Linux, dai file cancellati che occupano spazio all'OOM killer: cause, comandi diagnostici e soluzioni da conoscere per colloqui e lavoro quotidiano.

sysadmin interview

I colloqui per sistemisti Linux sono cambiati. Le domande di teoria, come "a cosa serve il comando X?", lasciano spazio a scenari concreti: un server che si comporta in modo anomalo e la richiesta di spiegare come si arriva alla causa. Tecmint ha raccolto dieci di questi casi. Sono utili per prepararsi a un colloquio, ma anche come checklist per chi gestisce server in produzione. Qui li riprendiamo con qualche nota di contesto.

1. File cancellato, ma il disco resta pieno

Un log da 6 GB viene eliminato con rm, ma df continua a segnalare il filesystem pieno.

Causa: rm rimuove la voce dalla directory, ma i blocchi dati restano allocati finché un processo tiene il file aperto. Un indizio è la differenza tra df -h /var e du -sh /var.

Diagnosi: sudo lsof +L1 elenca i file con link count zero (cancellati) ancora aperti da un processo.

Soluzione: riavviare il servizio, oppure azzerare il file tramite il suo file descriptor (identificativo numerico con cui un processo accede a un file aperto):

sudo truncate -s 0 /proc/<PID>/fd/<FD>

Prevenzione: sui log attivi usare truncate -s 0 invece di rm, e configurare logrotate con copytruncate o con il reload del servizio.

2. "No space left on device" con disco al 45%

Causa: esaurimento degli inode, le strutture che descrivono ogni file nel filesystem. Milioni di file piccolissimi, come sessioni PHP o cache, possono esaurirli prima dello spazio.

Diagnosi:

df -i /
sudo du --inodes -x -d 4 / 2>/dev/null | sort -rn | head

Soluzione: cancellare con find, che evita i limiti di espansione della shell:

sudo find /var/lib/php/sessions -type f -mtime +7 -delete

Nota: XFS, default su RHEL, alloca gli inode dinamicamente. ext4, default su Debian e Ubuntu, ne ha un numero fisso deciso alla creazione del filesystem.

3. Il servizio funziona a mano ma non al boot

Causa: il servizio non è abilitato oppure parte prima che la rete sia pronta.

Diagnosi: systemctl is-enabled myapp, journalctl -b -u myapp per i log del boot corrente e journalctl --list-boots per confrontarli con i boot precedenti.

Soluzione: un drop-in systemd (file che sovrascrive parti di una unit senza modificare l'originale) in /etc/systemd/system/myapp.service.d/override.conf:

[Unit]
Wants=network-online.target
After=network-online.target

Poi sudo systemctl daemon-reload && sudo systemctl enable --now myapp.

4. Il ping all'IP funziona, quello al nome no

Se ping 8.8.8.8 risponde e ping google.com no, la rete funziona ma il DNS è rotto.

Diagnosi: controllare /etc/resolv.conf su RHEL, oppure resolvectl status <interfaccia> su Ubuntu con systemd-resolved, e interrogare direttamente il server DNS con dig @192.168.122.1 google.com +short.

Soluzione su RHEL con NetworkManager:

sudo nmcli connection modify enp1s0 ipv4.dns "192.168.122.1" ipv4.ignore-auto-dns yes
sudo nmcli connection up enp1s0

Modificare a mano /etc/resolv.conf è inutile se il file è gestito da NetworkManager o systemd-resolved: verrà sovrascritto.

5. Il web server risponde solo su localhost

Causa: il servizio è in ascolto su 127.0.0.1 invece che su tutte le interfacce, oppure il firewall blocca la porta.

Diagnosi: sudo ss -tlnp | grep ':80' mostra l'indirizzo e il processo in ascolto.

Soluzione: correggere la direttiva in listen 80;, verificare con sudo nginx -t e ricaricare. Su RHEL aprire il firewall:

sudo firewall-cmd --permanent --add-service=http && sudo firewall-cmd --reload

6. Login SSH lento di 20-30 secondi

Causa: tentativi di autenticazione GSSAPI (meccanismo usato soprattutto con Kerberos) o reverse DNS lookup lato server che vanno in timeout.

Diagnosi: ssh -v utente@host mostra dove si blocca la connessione. ssh -o GSSAPIAuthentication=no conferma il sospetto e sudo sshd -T | grep -i usedns mostra la configurazione effettiva.

Soluzione: un file in /etc/ssh/sshd_config.d/ con:

UseDNS no
GSSAPIAuthentication no

Verificare con sudo sshd -t prima di riavviare il servizio (sshd su RHEL, ssh su Ubuntu). È un'abitudine che evita di chiudersi fuori da un server remoto.

7. Load average alto, CPU ferme

Load 12 su un server a 4 core, ma la CPU è quasi inattiva.

Causa: su Linux il load average conta anche i processi in stato D (uninterruptible sleep), bloccati in attesa di I/O su disco o rete. Il collo di bottiglia è lo storage, non la CPU.

Diagnosi:

uptime; nproc
vmstat 1 5        # colonne b (processi bloccati) e wa (I/O wait)
ps -eo state,pid,user,comm | awk '$1 == "D"'
iostat -x 2 3     # dal pacchetto sysstat

Un dispositivo con %util vicino al 100% e valori alti di r_await/w_await è il colpevole. Su cloud, spesso significa che si è superato il limite di IOPS del volume.

8. "Permission denied (publickey)"

La chiave pubblica è in authorized_keys, ma SSH rifiuta l'accesso.

Causa: permessi troppo aperti, chiave spezzata su più righe o contesto SELinux errato.

Diagnosi: ssh -v -i ~/.ssh/id_ed25519 utente@host lato client e journalctl -u sshd -n 20 (o -u ssh) lato server, dove di solito il motivo è scritto chiaramente.

Soluzione:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod go-w ~
restorecon -Rv ~/.ssh   # su sistemi con SELinux

9. Nginx restituisce 403 nonostante i permessi corretti

Il sito viene spostato in /srv/www, proprietario e permessi sono corretti, ma Nginx risponde 403 Forbidden.

Causa (RHEL e derivate): SELinux, il sistema di controllo degli accessi obbligatorio del kernel, impedisce al web server di leggere file con un contesto non adatto.

Diagnosi: getenforce, ls -Z /srv/www/index.html e sudo ausearch -m AVC -ts recent per vedere i dinieghi registrati.

Soluzione:

sudo semanage fcontext -a -t httpd_sys_content_t "/srv/www(/.*)?"
sudo restorecon -Rv /srv/www

La tentazione di disabilitare SELinux è comune, ma è la risposta sbagliata, sia al colloquio sia in produzione.

10. Il processo muore senza lasciare log

L'applicazione si chiude ogni pochi giorni, nessuno l'ha riavviata e i log applicativi sono vuoti.

Causa: l'OOM killer, il meccanismo del kernel che termina i processi quando la memoria si esaurisce.

Diagnosi: systemctl status myapp mostra code=killed, status=9, poi:

sudo dmesg -T | grep -iE "out of memory|oom-kill"
sudo journalctl -k | grep -i "out of memory"

Soluzione: limitare la memoria del servizio e gestirne il riavvio con un drop-in:

[Service]
MemoryMax=2G
Restart=on-failure
RestartSec=5

Il limite basato sui cgroup fa sì che sia il servizio a essere terminato e riavviato in modo controllato, invece di mettere in crisi l'intero sistema. Verifica con systemctl show myapp -p MemoryMax.

Il metodo conta più dei comandi

Il filo comune dei dieci scenari è un metodo, non una lista di comandi da memorizzare: confrontare due misure che dovrebbero coincidere (df e du, load e CPU), leggere i log del momento giusto (boot, kernel, audit), verificare cosa è in ascolto e dove, e chiedersi sempre chi ha fatto cosa a un processo.

Molti di questi problemi si ripresentano identici anche su Kubernetes. Un container terminato con OOMKilled è lo scenario 10 visto attraverso i cgroup del Pod. Un Pod che risolve gli IP ma non i nomi è lo scenario 4 applicato a CoreDNS. Un servizio raggiungibile solo dall'interno del Pod è lo scenario 5. Chi conosce bene Linux parte avvantaggiato anche nel troubleshooting dei cluster.