Server VPS unmanaged in emergenza con sviluppatore irreperibile: come ho recuperato un Hetzner AX41 lockato in 3 ore con la rescue mode e cosa fare nei primi 30 minuti di crisi

Server VPS unmanaged in emergenza con sviluppatore irreperibile: come ho recuperato un Hetzner AX41 lockato in 3 ore con la rescue mode e cosa fare nei primi 30 minuti di crisi

Il 14 aprile 2025 ho ricevuto un'email allarmata da una società di consulenza B2B romana del settore servizi tecnici per la pubblica amministrazione. Il loro sito istituzionale e il portale clienti erano entrambi giù da poco più di sei ore, e l'unica risorsa tecnica interna che avevano (un dipendente IT generalista, non sistemista) aveva esaurito le proprie opzioni dopo aver provato a riavviare il server dal pannello Hetzner Robot senza risultato. Il loro sviluppatore originale, un freelance di Bari che aveva costruito tutto lo stack quattro anni prima, non rispondeva al telefono né alle email da otto giorni. La situazione tecnica era questa: un Hetzner AX41 con Debian 11, Apache, MySQL 8 e PHP 7.4, su cui non avevano nessuna credenziale SSH valida (le chiavi del freelance non erano state mai duplicate o documentate), nessun accesso a phpMyAdmin (la URL era di root e protetta da basic auth con credenziali ignote), nessun backup recente verificato, e nessuna idea di cosa fosse andato storto. L'unico accesso che possedevano era il login al pannello Hetzner Robot, che il titolare aveva creato intestato a sé al momento dell'acquisto del server.

In tre ore di lavoro ho ricondotto il server a piena operatività, recuperando l'accesso SSH tramite la rescue mode di Hetzner, diagnosticando la causa root del crash (un disco riempito al 100% da log Apache mai ruotati), liberando spazio in modo conservativo, riavviando i servizi nell'ordine corretto, configurando logrotate, e producendo un runbook scritto per il cliente con tutte le credenziali e le procedure operative che il freelance non aveva mai documentato. Questo articolo descrive la sequenza esatta di interventi che applico in questi scenari, distillata da una decina di emergenze simili negli ultimi quattro anni, con i comandi precisi e gli strumenti del provider che fanno la differenza fra un recovery di tre ore e un'agonia di tre giorni. È un terreno operativo che si interseca strettamente con il protocollo di subentro su un progetto PHP quando lo sviluppatore originale è scomparso, su Hetzner, OVH o Aruba, ma con un focus specifico sull'uso degli strumenti del provider come ultima risorsa quando ogni altra strada è chiusa.

Perché il provider unmanaged non risolve il problema al posto tuo (e cosa invece ti dà davvero)?

Il primo malinteso che devo dissipare quasi sempre con i clienti in emergenza è la confusione fra "server unmanaged" e "server senza supporto". Sono due cose completamente diverse, e capirle è la chiave per usare correttamente le risorse che il provider mette a disposizione. Un server unmanaged significa che il provider è responsabile esclusivamente del livello hardware e di rete: ti consegna una macchina fisica funzionante, con accesso a internet, con un'installazione iniziale del sistema operativo che hai scelto, e con strumenti per intervenire quando il sistema non risponde più via SSH. Da quel momento in poi, qualunque cosa avvenga dentro l'OS - pacchetti aggiornati, configurazioni applicative, certificati SSL, log che riempiono il disco, processi che vanno in deadlock - è responsabilità del cliente o del consulente che il cliente ha incaricato. Hetzner non manda un sistemista di notte a riavviarti MySQL, e OVH non patcha il tuo Apache se hai una CVE critica.

Quello che invece il provider unmanaged ti , e che è oro durante un'emergenza, è una serie di strumenti di disaster recovery che permettono di reintervenire sulla macchina anche quando l'accesso normale non funziona più. La documentazione ufficiale del Rescue System di Hetzner sul portale Robot descrive il flusso completo per bootare la macchina su un'immagine Linux minimal, montare il filesystem originale, e intervenire dall'esterno sul sistema lockato. La documentazione equivalente di OVH per IPMI e KVM over IP sui server dedicati fornisce gli stessi strumenti via interfaccia diversa. Aruba Cloud, su cui ho clienti italiani con vincoli di sovranità dei dati, fornisce la console del server direttamente nell'interfaccia di gestione, come spiegato nella knowledge base ufficiale di Aruba Cloud sulla connessione console ai server cloud. Tutti e tre i provider, quindi, ti mettono in mano il martello - sei tu (o chi ti assiste) a dover sapere su quale chiodo battere. Sapere usare questi strumenti è la differenza fra "lo sviluppatore mi ha lasciato a piedi e sono finito" e "lo sviluppatore è sparito ma in tre ore sono di nuovo online". È la stessa differenza fra la dipendenza e la sovranità tecnologica che ho descritto nell'articolo sul tema del vendor lock-in nei progetti PHP delle PMI italiane.

I primi trenta minuti: la check-list di triage che applico in ogni emergenza

I primi trenta minuti di un'emergenza server determinano quasi sempre l'esito complessivo del recovery. Sul cliente romano del 14 aprile 2025, ho applicato la mia check-list di triage in undici punti, completata in 27 minuti, e già al termine di questa fase sapevo esattamente cosa era successo, cosa avrei dovuto fare per risolverlo, e quanto tempo mi avrebbe richiesto. Senza questa fase di diagnosi disciplinata, il rischio è di iniziare a "provare cose" e peggiorare la situazione esistente, distruggendo prove che servirebbero per il post-mortem.

I primi tre punti della check-list sono di natura organizzativa, prima ancora che tecnica. Punto 1: identificare la persona che ha autorità di decisione presso il cliente, perché ogni intervento successivo va concordato con qualcuno che possa autorizzare azioni potenzialmente irreversibili. Punto 2: ottenere l'accesso al pannello del provider (Hetzner Robot, OVH Manager, Aruba Cloud Console), perché senza questo nessuno strumento di rescue è disponibile. Punto 3: bloccare qualunque tentativo di "fare qualcosa di nuovo" finché la diagnosi non è completata, perché ogni riavvio non motivato distrugge la cache dei processi in memoria e i log volatili. Sul cliente romano, il dipendente IT aveva già riavviato il server tre volte prima di chiamarmi, perdendo informazioni preziose sui processi che stavano consumando memoria nel momento del crash.

I punti 4-7 sono tecnici di osservazione: tentare un ping ICMP all'IP del server (per capire se è almeno raggiungibile a livello rete), tentare una connessione SSH sulla porta standard (22) e su eventuali porte custom, controllare se il pannello del provider mostra il server come "online" o "offline" lato hypervisor, e verificare lo stato del traffico di rete sull'interfaccia del server tramite le metriche del provider (Hetzner mostra graphs di traffico in/out con risoluzione 5 minuti direttamente nel Robot, OVH idem nel Manager). Sul cliente romano, queste quattro verifiche hanno mostrato che il server era online lato hypervisor, ma non rispondeva né a ping né a SSH, e che il traffico di rete in uscita era a zero. La combinazione "server up + nessun traffico" puntava chiaramente verso un kernel deadlock o un sistema che aveva perso la connettività di rete a livello applicativo.

I punti 8-11 sono di azione iniziale: bootare il server in rescue mode dal pannello del provider, montare il filesystem principale in sola lettura, ispezionare i log di sistema (/var/log/syslog, /var/log/messages, /var/log/kern.log) per trovare l'ultimo evento utile prima del crash, e controllare lo spazio disco disponibile sui filesystem critici. Sul cliente romano, il punto 11 ha rivelato immediatamente la causa: la partizione / era al 100% di occupazione, con /var/log/apache2/access.log e /var/log/apache2/error.log cresciuti a 47GB e 23GB rispettivamente, perché logrotate non era mai stato configurato dal freelance originale. Apache aveva smesso di rispondere quando non aveva più potuto scrivere log, MySQL era andato in panic per impossibilità di scrivere il binlog, e il disco saturo aveva impedito al sistema di gestire qualunque scrittura, inclusi i tentativi di SSH session establishment.

Rescue mode di Hetzner: la sequenza esatta dei comandi per recuperare l'accesso

La rescue mode è uno strumento che ti permette di bootare la macchina in un ambiente Linux minimal fornito dal provider, completamente separato dal sistema operativo installato sul disco. Da quell'ambiente puoi montare il filesystem originale come device esterno e operare su di esso come se fosse un disco USB. Su Hetzner, l'attivazione avviene dal pannello Robot, sezione "Rescue", scegliendo l'architettura (linux64), inserendo opzionalmente la propria chiave SSH pubblica, e cliccando "Activate rescue system". Subito dopo si forza un riavvio dal pannello (oppure tramite IPMI se non si fida del riavvio software), e il server bootta in pochi secondi nell'ambiente di rescue. A quel punto puoi connetterti via SSH come root con la password fornita dal pannello (o con la tua chiave) e operare. La sequenza esatta che ho eseguito sul cliente romano del 14 aprile 2025, una volta dentro l'ambiente di rescue, è stata questa:

fdisk -l
mkdir /mnt/rescue
mount /dev/nvme0n1p3 /mnt/rescue
df -h /mnt/rescue

du -sh /mnt/rescue/var/log/apache2/* | sort -h | tail -10

cd /mnt/rescue/var/log/apache2
tail -1000 access.log > /root/last-access.log
tail -1000 error.log  > /root/last-error.log

truncate -s 0 access.log
truncate -s 0 error.log
truncate -s 0 access.log.1
truncate -s 0 error.log.1

df -h /mnt/rescue

sync
umount /mnt/rescue
reboot

Le quattro operazioni critiche sono: montare il filesystem originale (la partizione / di Debian su un AX41 è tipicamente /dev/nvme0n1p3 con uno schema GPT classico, ma fdisk -l te lo conferma), salvare gli ultimi 1000 record di ciascun log in una directory esterna a /mnt/rescue per averli a disposizione anche dopo il reboot, troncare i file di log a dimensione zero senza cancellarli (importante: Apache mantiene aperto il file descriptor anche dopo un truncate, quindi truncate -s 0 libera lo spazio senza richiedere un restart immediato del demone), e infine smontare pulitamente prima del reboot. Sul cliente romano, dopo il truncate dei file di log, lo spazio occupato è passato da 100% a 31%, e dopo il reboot in modalità normale il sistema è tornato online in 47 secondi con SSH funzionante, Apache che rispondeva sul vhost del cliente, e MySQL operativo. Questo è il momento esatto in cui un'emergenza smette di essere un'emergenza e diventa un'attività di consolidamento, identica nel principio operativo a quella descritta nel mio articolo sulla difesa proattiva da bot e DDoS su PHP/Laravel Hetzner e OVH: risolvere la causa immediata, e poi mettere in piedi le contromisure perché non si ripeta.

Configurare logrotate per evitare la prossima esplosione del disco

Aver liberato spazio non serve a nulla se la causa root resta in piedi. Sul cliente romano, dopo il riavvio, ho immediatamente configurato logrotate in modo che Apache, MySQL, Nginx e tutti i log applicativi venissero ruotati con cadenza giornaliera, compressi, e cancellati dopo 14 giorni. La pagina man di logrotate(8) sul progetto Linux Die documenta tutte le direttive disponibili, ma per la maggior parte dei casi PMI bastano cinque righe di configurazione per file di log. La configurazione minima che ho lasciato sul cliente romano per Apache è stata questa:

/var/log/apache2/*.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    create 640 root adm
    sharedscripts
    postrotate
        if /etc/init.d/apache2 status > /dev/null ; then \
            /etc/init.d/apache2 reload > /dev/null; \
        fi;
    endscript
}

Questa configurazione fa girare il logrotate ogni giorno, mantiene 14 file di log compressi (rappresentando 14 giorni di storia accessibile), compatta i log con gzip salvo l'ultimo per evitare problemi di lettura concorrente, ricrea il file di log con permessi corretti dopo la rotazione, e fa il reload di Apache solo se il demone è attivo (importante per evitare che logrotate stesso fallisca su sistemi in stato anomalo). In aggiunta alla configurazione, ho aggiunto un alert su disco al sistema di monitoring del cliente con soglia all'80% di occupazione, in modo che la prossima volta che un filesystem si avvicinasse al limite ricevessero una notifica con 48 ore di anticipo invece di scoprirlo a sito offline. La gestione dei log è una di quelle attività che vanno strutturate fin dal primo giorno di vita di un server, ed è esattamente uno dei capitoli del piano di consolidamento del debito tecnico nei 90 giorni post-subentro su server Linux Hetzner e OVH: senza log ruotati, ogni server è una bomba a orologeria.

Il complemento operativo della rotazione è la disciplina di consultare i log durante il funzionamento normale, non solo in emergenza. Una pratica che applico con tutti i clienti dopo un incidente come questo è programmare un controllo settimanale automatizzato degli ultimi 1000 errori Apache e degli ultimi 1000 errori PHP, con un report inviato via email al titolare e a me. È una contromisura economica ma efficace, perché trasforma il monitoraggio dei log da attività reattiva (qualcosa è andato storto, vado a vedere i log) ad attività proattiva (vado a vedere i log perché è giovedì mattina e potrebbero esserci segnali di qualcosa che andrà storto la settimana prossima). Il principio è lo stesso descritto nell'articolo sulla gestione strategica dei log Laravel su server dedicati Hetzner e OVH, applicato qui in scala da PMI senza budget di osservabilità.

Knowledge transfer inverso: ricostruire la documentazione che lo sviluppatore non ha mai prodotto

Una volta superata la crisi tecnica, il problema più importante da risolvere è quello informativo. Sul cliente romano del 14 aprile 2025, una volta riavviato il server, non avevamo nessuna delle informazioni che servono per gestire correttamente quella macchina nei prossimi mesi: non c'era un inventario dei vhost configurati, non c'era una lista degli utenti MySQL, non c'erano le credenziali di accesso al backoffice del CMS, non c'era uno schema della base dati, non c'era una mappa dei cron job in esecuzione. La fase di knowledge transfer inverso consiste esattamente nel ricostruire tutte queste informazioni dal sistema in produzione, perché sono necessarie per qualunque intervento futuro. Il processo che applico richiede tipicamente uno o due giorni di lavoro, e produce una serie di documenti che diventano la base operativa del cliente.

Lo eseguo in cinque fasi: estrazione dell'inventario applicativo (vhost Apache configurati, applicazioni PHP/Laravel/Symfony installate, framework e versioni), estrazione della mappa dei servizi (systemctl list-units --type=service --state=running), estrazione dell'inventario degli utenti SSH e MySQL (con le rispettive autorizzazioni), estrazione della lista dei cron job di sistema e per-utente (cat /etc/crontab, crontab -l per ogni utente), e mappatura delle integrazioni esterne (ricerca di API key, webhook, credenziali SMTP, chiavi SSH per repository Git in ~/.ssh/config). Ogni elemento estratto viene documentato in italiano in un runbook condiviso col cliente in formato Markdown su un repository Git di sua proprietà, perché è esattamente il tipo di documentazione che gli serve per non trovarsi mai più nella situazione di partenza. Il principio sotto sta nello stesso ragionamento che ho descritto nell'articolo sull'importanza del versionamento del codice come prerequisito non negoziabile per la sopravvivenza tecnica di una PMI: senza repository Git e senza documentazione versionata, qualunque ottimizzazione futura è costruita sulla sabbia.

Se la tua azienda gestisce un server VPS unmanaged su Hetzner, OVH, Aruba o Contabo per applicazioni critiche al business, e non hai mai messo alla prova la tua capacità di intervento in scenario di emergenza con il sistemista originale irreperibile, scopri come lavoro con i clienti sui temi di subentro tecnico e gestione dell'emergenza infrastrutturale: in dieci anni di consulenza ho visto che il fattore decisivo nel recovery non è la potenza del server, ma la qualità della documentazione e degli accessi disponibili nel momento esatto del bisogno. Se invece sei già nella situazione descritta - sito offline, sviluppatore irreperibile, nessun accesso SSH valido, server che non risponde - e ti serve un intervento immediato per ricondurre il sistema in operatività con un piano di consolidamento successivo, contattami per una consulenza: in poche ore tipicamente ottengo l'accesso alla rescue mode del provider, diagnostico la causa root del crash, ripristino i servizi nell'ordine corretto, configuro le contromisure perché il problema non si ripeta, e ti consegno un runbook operativo che il tuo team può usare in autonomia da subito.

Ultima modifica: