Server Debian fermo a 14 mesi fa: come aggiorno un VPS in produzione con Laravel senza rompere nulla
A maggio 2025 ho fatto un audit infrastrutturale per una PMI piemontese che gestisce un portale di prenotazioni B2B nel settore turistico - circa 300 strutture ricettive partner e 12.000 prenotazioni al mese. L'applicazione Laravel 10 girava su un VPS OVH Value (4 vCPU, 8 GB RAM, 160 GB SSD) con Debian 11, PHP 8.1, MySQL 8.0 e Nginx 1.22. Il titolare mi aveva chiamato per un problema di performance, non di sicurezza. Ma il primo comando che eseguo su qualunque server che prendo in carico è sempre lo stesso:
apt list --upgradable 2>/dev/null | wc -lLa risposta: 248 righe. Meno una (l'header), faceva 247 pacchetti con aggiornamenti disponibili. L'ultimo apt upgrade era stato eseguito il 12 marzo 2024 - quattordici mesi prima. Per un anno e due mesi, il server aveva continuato a servire migliaia di richieste al giorno con OpenSSH vulnerabile a regreSSHion (CVE-2024-6387), PHP 8.1.12 con 7 CVE note nella versione installata, e il kernel Linux 5.10.0-20 quando il corrente era 5.10.0-30 con decine di fix di sicurezza accumulati. L'applicazione funzionava. Il business andava avanti. Nessuno sapeva di essere esposto.
Questo è lo scenario più comune che incontro sulle PMI italiane con VPS unmanaged: il server funziona, il sito risponde, nessuno si preoccupa degli aggiornamenti perché "non è rotto, perché aggiustarlo?" La risposta è che un server non aggiornato non è rotto - è aperto. E la differenza tra "funziona" e "è sicuro" è la stessa che c'è tra una porta chiusa e una porta chiusa a chiave.
Quanto è davvero rischioso non aggiornare un server Debian in produzione?
Molto più di quanto la maggior parte dei titolari di PMI pensi. Il portale ufficiale Debian Security pubblica advisory per ogni vulnerabilità corretta nei pacchetti della distribuzione stabile. Nel solo 2024-2025, Debian ha emesso oltre 200 DSA (Debian Security Advisory) che coprivano CVE in pacchetti comunemente installati sui server di produzione: OpenSSL, OpenSSH, curl, systemd, PHP, MySQL, Nginx. Ogni advisory non applicato è una porta che qualcuno, da qualche parte, sa come aprire.
Sul VPS del cliente piemontese, i 247 pacchetti arretrati si distribuivano così: 38 erano patch di sicurezza pure (provenienti dal repository debian-security), 142 erano aggiornamenti di bugfix della distribuzione stabile, 67 erano aggiornamenti di pacchetti PHP dal repository Sury (il PPA standard per PHP su Debian). I 38 security patch erano il rischio immediato. Tra questi, il più critico era OpenSSH 8.4p1 - la versione installata era vulnerabile a regreSSHion (CVE-2024-6387), una race condition nel signal handler di sshd che potenzialmente permetteva esecuzione remota di codice pre-autenticazione. La patch era disponibile da luglio 2024. Era stata ignorata per 10 mesi.
Sul server del cliente piemontese, i rischi concreti erano tre. Il primo era OpenSSH con regreSSHion: un attaccante poteva potenzialmente ottenere una root shell sul server senza autenticazione, sfruttando una race condition nel signal handler. Il secondo era PHP 8.1.12, che aveva CVE note per buffer overflow nella gestione dei file PHAR e per information disclosure nell'estensione LDAP - vulnerabilità meno spettacolari di una RCE, ma che in combinazione con altri vettori potevano facilitare un'escalation. Il terzo era il kernel Linux 5.10.0-20, che era esposto a multiple local privilege escalation - il tipo di vulnerabilità che un attaccante usa dopo aver ottenuto un primo accesso a basso privilegio per diventare root.
Il punto che ripeto a ogni titolare è questo: nessuna di queste vulnerabilità ha un exploit "facile" che un ragazzino può lanciare da un portatile. Ma gli attaccanti professionisti - quelli che prendono di mira le PMI per i dati dei clienti o per usare il server come punto di appoggio per attacchi ad altri target - hanno strumenti automatizzati che scansionano internet alla ricerca di server con versioni vulnerabili note. Un server con 14 mesi di arretrato è un bersaglio con un cartello "APERTO" attaccato alla porta.
Stai cercando un Consulente Informatico esperto per un audit di sicurezza della tua infrastruttura VPS? Nel mio profilo professionale trovi l'esperienza concreta su hardening, aggiornamenti di sicurezza e gestione di server Debian in produzione per PMI.
Il protocollo: aggiornare senza rompere nulla
La paura di aggiornare è comprensibile. Un apt upgrade su un server di produzione è un'operazione che può modificare decine di pacchetti simultaneamente, e se qualcosa va storto - un conflitto di dipendenze, un servizio che non riparte, una configurazione sovrascritta - il business si ferma. Ma la soluzione non è non aggiornare: è aggiornare con metodo. Il protocollo che applico si divide in cinque passaggi, nell'ordine.
Passaggio 1: snapshot del server
Prima di qualunque modifica, creo un'immagine del server che possa essere ripristinata in caso di disastro. Su OVH, Hetzner e Contabo questo si fa dalla console del provider (snapshot VPS) in 5-10 minuti. Su provider che non offrono snapshot, faccio un backup completo del filesystem con rsync su uno storage esterno. Per le strategie di backup avanzate che applico prima di operazioni rischiose su VPS, ho scritto una guida dedicata al backup di VPS unmanaged su Hetzner, OVH, Contabo, Digital Ocean e Aruba.
Passaggio 2: dry run e analisi dei pacchetti
Prima di eseguire il vero upgrade, analizzo cosa verrà installato:
# Simulazione: mostra cosa verrebbe aggiornato senza installare nulla
apt-get upgrade --dry-run
# Separare security updates dal resto
apt-get upgrade -s 2>/dev/null | grep -i security
# Verificare se ci sono pacchetti che richiedono rimozione (dist-upgrade)
apt-get dist-upgrade --dry-runIl dry run è il momento in cui scopri i problemi prima che diventino emergenze. Sul server del cliente piemontese, il dry run ha rivelato che il pacchetto libapache2-mod-php8.1 sarebbe stato rimosso perché il server usava Nginx con PHP-FPM, non Apache - ma il pacchetto era rimasto installato come dipendenza residua. Un non-problema in questo caso, ma su un server con Apache sarebbe stato un downtime immediato.
Passaggio 3: aggiornamento in due fasi
La regola che non derogo mai: prima i security patch, poi il resto. Questo minimizza il rischio: se i security patch causano un problema, hai aggiornato solo 38 pacchetti su 247, il blast radius è contenuto. Se tutto funziona, procedi con il resto.
# Fase 1: solo security updates
apt-get upgrade -y -o Dir::Etc::SourceList=/etc/apt/sources.list.d/debian-security.list
# Verifica che i servizi critici siano ancora attivi
systemctl is-active nginx php8.1-fpm mysql
# Fase 2: il resto degli aggiornamenti
apt-get upgrade -y
# Se ci sono pacchetti held back (trattenuti), valutare dist-upgrade
apt-get dist-upgrade --dry-runPassaggio 4: needrestart e riavvio servizi
Dopo un aggiornamento, molti servizi continuano a eseguire in memoria il codice della versione precedente - il nuovo binario è su disco ma il processo in esecuzione usa ancora quello vecchio. needrestart è lo strumento che risolve questo problema: identifica i servizi che necessitano un riavvio e può riavviarli automaticamente:
# Installare needrestart se non presente
apt-get install needrestart
# Mostrare quali servizi necessitano restart
needrestart -l
# Riavviare i servizi automaticamente
needrestart -raSul server del cliente piemontese, dopo l'upgrade, needrestart ha identificato 6 servizi da riavviare: sshd, PHP-FPM, MySQL, Nginx, cron e systemd-resolved. Il riavvio di ciascuno è stato sequenziale e controllato - prima MySQL (il più critico, verifica con mysqladmin ping), poi PHP-FPM, poi Nginx, infine gli altri. Il downtime totale percepito dagli utenti: zero secondi, perché PHP-FPM e Nginx si riavviano in meno di un secondo con il graceful restart di systemd.
Se il kernel è stato aggiornato - e dopo 14 mesi di arretrato lo era sicuramente - il file /var/run/reboot-required te lo segnala. Il reboot del server è l'unica operazione che richiede un downtime reale (30-90 secondi), e va pianificata in una finestra di basso traffico. Sul cliente piemontese l'ho schedulata per le 3 di notte, con un cron job che faceva shutdown -r now e un monitoring esterno che verificava il ritorno online entro 5 minuti.
Cosa fare quando l'upgrade rompe qualcosa
Sul server del cliente piemontese l'aggiornamento è andato liscio. Ma non sempre è così, e preparare il piano B è parte del protocollo. I problemi più comuni che ho incontrato su server Debian con stack LEMP:
- PHP-FPM non riparte dopo l'upgrade: solitamente un conflitto di estensioni. Verificare con
php -mche tutte le estensioni richieste da Laravel siano caricate, confrontando con ilcomposer check-platform-reqsdel progetto. Se manca un'estensione,apt install php8.1-NOMEla reinstalla. - MySQL non riparte: quasi sempre un cambio nei parametri di configurazione tra minor version. Controllare
journalctl -u mysql -n 50per l'errore specifico. Nella mia esperienza, il colpevole più frequente è un parametro deprecato nelmy.cnf- su MySQL 8.0 capita spesso conquery_cache_typeoinnodb_file_formatche sono stati rimossi. - Nginx rifiuta la configurazione: raro su security update, ma possibile se vengono aggiornati moduli.
nginx -tprima del restart mostra l'errore esatto.
In tutti i casi, lo snapshot creato al passaggio 1 è la rete di sicurezza: un ripristino completo del VPS dallo snapshot richiede 5-10 minuti sulla console del provider, e riporta il server esattamente allo stato pre-upgrade. È il motivo per cui lo snapshot è il primo passaggio, non un optional.
Passaggio 5: verifica applicativa
Dopo l'aggiornamento, non mi fido del "sembra funzionare". Verifico in modo sistematico:
# PHP-FPM risponde
php -v && curl -s -o /dev/null -w "%{http_code}" http://localhost/health
# MySQL è operativo
mysqladmin ping && mysql -e "SELECT VERSION();"
# Laravel risponde senza errori
cd /var/www/app && php artisan --version
php artisan migrate:status | tail -5
# Nessun errore nei log dopo l'upgrade
tail -20 /var/www/app/storage/logs/laravel.log
journalctl -u php8.1-fpm --since "1 hour ago" --no-pager | tail -20Mai più: unattended-upgrades per i security patch automatici
Dopo aver riportato il server in ordine, il passo finale è fare in modo che la situazione non si ripresenti. L'installazione di unattended-upgrades su Debian automatizza l'applicazione dei security patch - e solo quelli, non gli aggiornamenti generici che potrebbero cambiare comportamento. La configurazione che applico su ogni server che gestisco per PMI è conservativa ma efficace:
# Installare e abilitare
apt-get install -y unattended-upgrades apt-listchanges
dpkg-reconfigure -plow unattended-upgrades// /etc/apt/apt.conf.d/50unattended-upgrades
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
};
// NON aggiornare automaticamente pacchetti critici
Unattended-Upgrade::Package-Blacklist {
"mysql-server";
"nginx";
};
// Upgrade interrompibile (minimizza il rischio di stato inconsistente)
Unattended-Upgrade::MinimalSteps "true";
// Notifica via email solo se qualcosa cambia
Unattended-Upgrade::Mail "[email protected]";
Unattended-Upgrade::MailReport "on-change";
// NON riavviare automaticamente (preferisco farlo in finestra controllata)
Unattended-Upgrade::Automatic-Reboot "false";La configurazione di apt-listchanges è il complemento: ogni volta che unattended-upgrades applica un aggiornamento, ricevi via email il changelog del pacchetto aggiornato - così sai esattamente cosa è stato modificato senza dover controllare manualmente. Sui server dei clienti PMI configuro anche un check di Prometheus che monitora il file /var/run/reboot-required: se esiste, significa che un aggiornamento del kernel è stato installato ma il server non è stato ancora riavviato - e finché non lo riavvii, stai eseguendo il kernel vecchio con le vulnerabilità vecchie, anche se il pacchetto nuovo è su disco. L'alert che ho descritto nel mio articolo sul monitoring proattivo con Prometheus e Grafana per Laravel su VPS include esattamente questo scenario.
La blacklist di MySQL e Nginx è intenzionale: gli aggiornamenti di database e web server possono avere effetti collaterali su configurazioni custom (parametri di tuning, moduli caricati, formati di log) e preferisco applicarli manualmente dopo un dry run. I security patch del kernel, di OpenSSH, di OpenSSL e delle librerie di sistema vengono invece applicati automaticamente ogni notte - perché il rischio di lasciarli scoperti è sempre maggiore del rischio di applicarli.
Per chi gestisce server Debian con applicazioni PHP e vuole completare l'hardening oltre gli aggiornamenti di sicurezza, ho scritto una guida dedicata all'hardening di server Debian e Ubuntu per applicativi PHP delle PMI che copre PHP-FPM, permessi, security header e configurazione del web server.
Se il tuo VPS non vede un apt upgrade da più di tre mesi, hai un debito di sicurezza che si accumula silenziosamente. Ogni settimana che passa senza applicare i security patch aumenta la superficie di attacco del tuo server - e il paradosso è che più aspetti, più l'aggiornamento diventa rischioso perché il delta tra il tuo stato e lo stato corrente cresce. La regola che do a ogni cliente PMI è semplice: i security patch si applicano automaticamente con unattended-upgrades, gli aggiornamenti generici dei pacchetti si pianificano mensilmente in una finestra di manutenzione concordata, il kernel si aggiorna trimestralmente con reboot programmato in orario notturno. Il costo di questa disciplina è vicino allo zero - mezza giornata iniziale per il setup, poi il sistema si mantiene da solo. Contattami se hai bisogno di un audit dello stato di aggiornamento dei tuoi server: in mezza giornata verifico lo stato dei pacchetti, le CVE esposte e lo stato di unattended-upgrades, e ti consegno un piano di remediation con priorità e tempistiche.