SSD Nodes Learn Hosting plans →
Guide Matt ConnorDi Matt Connor · Aggiornato 2026-08-27

Come scegliere il kernel al prossimo avvio della VPS

GRUB_DEFAULT non basta su un'immagine cloud Ubuntu: leggi le voci reali di GRUB e fissa il prossimo kernel senza rischiare di perdere l'accesso SSH.

Cosa decide quale kernel avvierà la tua VPS

Il kernel che la tua VPS avvierà al prossimo avvio è determinato da un unico file generato, /boot/grub/grub.cfg. Non modificare mai direttamente questo file. Modifica i relativi input e rigeneralo. In un’immagine cloud Ubuntu, uno di questi input proviene dal fornitore dell’immagine e può rendere irrilevante la selezione dal menu. Per questo GRUB_DEFAULT=1 seguito da update-grub non cambia nulla su un server noleggiato, mentre gli stessi due passaggi funzionano su un’installazione su laptop.

Procedi in quest’ordine. Verifica che il kernel sia effettivamente selezionabile da te. Leggi ogni file di input, inclusi quelli aggiunti dal fornitore. Leggi l’output generato e conta le voci che contiene realmente. Solo dopo scegli un metodo per fissare il kernel. Se commetti un errore su una macchina raggiungibile soltanto tramite SSH, potresti dover ricorrere a una console di ripristino. Per questo, le risposte più sicure si trovano alla fine di questa pagina e spesso sono quelle corrette.

Verifica innanzitutto di poter selezionare il tuo kernel

uname -r
systemd-detect-virt
ls -1 /boot/vmlinuz-*

systemd-detect-virt che restituisce kvm, qemu o xen indica che usi un kernel gestito da te e che tutto ciò che segue è applicabile. lxc o openvz indica invece che il server condivide il kernel dell'host. In questo caso non hai un bootloader gestito da te e non c'è nulla da selezionare. uname -r mostra una versione che non compare affatto in /boot/vmlinuz-*, perché il kernel in esecuzione appartiene all'host e nessuna impostazione presente sul disco può modificarlo.

ls -1 /boot/vmlinuz-* contiene l'elenco effettivo dei kernel tra cui puoi scegliere. Se contiene una sola riga, il kernel precedente è già stato eliminato e nessuna impostazione del bootloader può ripristinarlo. Di solito accade durante un'operazione di autoremove. È utile comprenderne il funzionamento prima di eliminare i kernel obsoleti su Ubuntu da un server importante.

Il file che modifichi non è il file letto da GRUB

/etc/default/grub contiene semplici assegnazioni di variabili della shell. È un file di input. /boot/grub/grub.cfg è l’output e inizia con # DO NOT EDIT THIS FILE e la motivazione. Qualsiasi modifica apportata all’output viene persa alla successiva installazione o rimozione di un pacchetto del kernel, perché gli script del pacchetto lo rigenerano.

cat /usr/sbin/update-grub

update-grub è un wrapper. Esegue grub-mkconfig -o /boot/grub/grub.cfg, che legge le variabili, esegue ogni script in /etc/grub.d/ e scrive il risultato. Due comandi, una sola direzione: i dati di input entrano e grub.cfg viene prodotto.

Cosa sovrascrive la configurazione: /etc/default/grub.d

grep -rn '^[^#]' /etc/default/grub /etc/default/grub.d/

Il secondo percorso è quello che spesso viene trascurato. grub-mkconfig esegue prima il source di /etc/default/grub, quindi carica ogni file *.cfg presente in /etc/default/grub.d/ in ordine glob. Leggi il codice che esegue questa operazione:

grep -n 'default/grub' /usr/sbin/grub-mkconfig

Il caricamento dei file usa la normale sintassi della shell, quindi prevale l'ultima assegnazione. Le immagini cloud Ubuntu includono file in quella directory e impostano valori come il timeout e la riga di comando del kernel dopo che il tuo file è già stato letto. La tua assegnazione GRUB_TIMEOUT=10 in /etc/default/grub viene sovrascritta poco dopo da un file del fornitore che la imposta su 0. Il comando grep precedente stampa le assegnazioni esatte presenti nella tua immagine. Usa quindi quei valori invece di fare affidamento su questa spiegazione.

La regola pratica è la seguente: inserisci le tue impostazioni in un file che venga ordinato per ultimo, ad esempio /etc/default/grub.d/99-local.cfg, invece di modificare /etc/default/grub. In questo modo nessun file fornito con l'immagine può essere caricato dopo il tuo.

Perché GRUB_FORCE_PARTUUID rende irrilevante la selezione del menu

grep -rn GRUB_FORCE_PARTUUID /etc/default/grub /etc/default/grub.d/
grep -n GRUB_FORCE_PARTUUID /etc/grub.d/10_linux
sudo grep -n 'root=PARTUUID' /boot/grub/grub.cfg

GRUB_FORCE_PARTUUID indica al generatore di individuare il filesystem root tramite l’UUID della partizione, scritto direttamente sulla riga di comando del kernel come root=PARTUUID=..., invece di cercare un UUID del filesystem durante l’avvio. Il provider dell’immagine lo imposta perché consente a una singola immagine disco di avviarsi in modo affidabile su hardware diverso da quello usato per crearla. Il secondo comando grep mostra il codice che utilizza la variabile, in /etc/grub.d/10_linux. Lo script si trova sul tuo disco ed è la fonte autorevole per determinare il comportamento della tua immagine.

Qui conta la conseguenza: lungo questo percorso, il generatore scrive una voce di avvio diretta invece dell’elenco completo dei kernel installati. Conta quante voci sono state generate.

sudo grep -cE '^\s*(menuentry|submenu) ' /boot/grub/grub.cfg
sudo grep -nE '^\s*(menuentry|submenu) ' /boot/grub/grub.cfg

Se il conteggio è 1, non esiste una seconda voce da selezionare, quindi GRUB_DEFAULT=1 indica una voce inesistente. GRUB non riesce a risolverla e avvia la prima voce, cioè il nuovo kernel che stavi cercando di evitare. grub-set-default non risolve il problema, perché il valore predefinito non è l’elemento difettoso. Il menu da cui stai cercando di selezionare una voce non è mai stato generato.

Per ripristinare il menu completo, sposta temporaneamente il file del provider e visualizza un’anteprima del risultato prima di applicarlo. grub-mkconfig senza -o scrive sull’output standard e non modifica nulla sul disco.

sudo grub-mkconfig 2>/dev/null | grep -cE '^\s*(menuentry|submenu) '
sudo mkdir -p /root/grub-backup
sudo mv /etc/default/grub.d/<the file your grep named> /root/grub-backup/
sudo grub-mkconfig 2>/dev/null | grep -cE '^\s*(menuentry|submenu) '

Un conteggio che passa da 1 a diverse voci indica che le voci compaiono dopo aver rimosso il parametro forzato. Non è ancora stato scritto nulla. Ripristina il file se il secondo conteggio non è corretto, perché PARTUUID forzato permette all’immagine del provider di individuare il filesystem root; rimuovendolo, il sistema passa invece al percorso di ricerca. Crea uno snapshot prima di eseguire realmente update-grub.

Se l’unico obiettivo è superare un problema con un kernel, fermati qui e usa le opzioni più sicure riportate sotto. Ricostruire il menu di avvio su un server remoto per risolvere un singolo aggiornamento espone a rischi superiori all’importanza del problema.

Perché i numeri degli elementi non sono adatti per il pinning

GRUB_DEFAULT accetta un numero, un titolo o un identificatore. I numeri contano gli elementi di primo livello a partire da 0. Un elemento annidato usa > come separatore, quindi GRUB_DEFAULT="1>2" indica l'elemento all'indice 2 all'interno del sottomenu all'indice 1.

Gli indici cambiano. 10_linux elenca i kernel dal più recente al meno recente, quindi l'installazione di un kernel sposta in basso di una posizione ogni elemento precedente e la rimozione di un kernel li sposta nuovamente in alto. Il tuo 1>2 continua a essere accettato. Ora però identifica un kernel diverso. Non viene restituito alcun errore o avviso e te ne accorgi solo dopo un riavvio.

Gli identificatori non cambiano, perché ognuno contiene la versione del kernel. Leggi il tuo:

sudo awk -F"'" '/menuentry_id_option/ {print $2, "==>", $4}' /boot/grub/grub.cfg

Ignora le prime righe dell'output: contengono la variabile definita nell'intestazione. Nelle righe successive, il lato sinistro contiene il titolo visualizzato dall'utente e il lato destro l'identificatore da passare agli strumenti. Per un elemento all'interno di un sottomenu, concatena l'identificatore del sottomenu e quello dell'elemento usando >, in quest'ordine, esattamente come nella forma numerica.

Avviare una volta il kernel precedente con grub-reboot

Su un server remoto, una selezione valida per un solo avvio è la scelta corretta perché si annulla automaticamente. grub-reboot scrive next_entry in /boot/grub/grubenv. GRUB legge questa variabile, la azzera e salva il valore azzerato prima di avviare qualsiasi elemento. In questo modo, se il kernel va in panic, non viene ritentato all'avvio successivo. Il sistema esegue un solo tentativo e poi torna automaticamente all'impostazione predefinita.

Prima verificare che la configurazione generata legga effettivamente questa variabile:

sudo grep -n -B2 -A5 'next_entry' /boot/grub/grub.cfg

È necessario trovare una riga load_env e un blocco che imposti default a partire da next_entry. Se grep non restituisce nulla, l'immagine non legge grubenv durante l'avvio. Di conseguenza, grub-reboot viene accettato nella shell e poi ignorato dal bootloader. È lo stesso percorso di avvio diretto forzato della sezione precedente, che si manifesta in un secondo punto.

sudo grub-reboot '<the identifier you copied>'
sudo grub-editenv list

grub-editenv list dovrebbe ora restituire una riga next_entry= contenente esattamente il valore specificato. Aprire la console del provider in una scheda del browser, quindi riavviare e verificare il risultato.

sudo reboot
uname -r

Se uname -r restituisce la versione precedente, il blocco ha funzionato. Se restituisce la nuova versione, significa che l'identificatore non è stato risolto oppure che grubenv non viene letto. In entrambi i casi il sistema è avviato, che è lo scopo dell'utilizzo della modalità valida per un solo avvio.

Rendere persistente la scelta con GRUB_DEFAULT=saved

GRUB_DEFAULT=saved fa derivare il valore predefinito da saved_entry in grubenv, e si imposta quel valore con grub-set-default. La configurazione resta valida dopo l’installazione dei kernel, perché update-grub riscrive grub.cfg e non modifica mai grubenv.

echo 'GRUB_DEFAULT=saved' | sudo tee /etc/default/grub.d/99-local.cfg
sudo update-grub
sudo grub-set-default '<the identifier you copied>'
sudo grub-editenv list
sudo grep -n 'set default' /boot/grub/grub.cfg

L’ultimo comando deve stampare set default="${saved_entry}". Se stampa set default="0", significa che qualcosa ha eseguito il source dopo il tuo file e ha reimpostato GRUB_DEFAULT su un valore letterale. Elenca quindi di nuovo /etc/default/grub.d/ e verifica che 99-local.cfg venga ordinato effettivamente per ultimo.

GRUB_SAVEDEFAULT=true è un’impostazione diversa e può essere confusa facilmente con questa. Salva come nuovo valore predefinito la voce appena utilizzata per l’avvio, quindi il valore predefinito segue l’ultimo avvio riuscito. Su un server, un riavvio non presidiato può quindi modificare silenziosamente il kernel fissato. Lascialo disattivato, salvo che sia esattamente il comportamento desiderato.

Un pin basato sull’identificatore può comunque fallire in un caso. Se rimuovi il kernel indicato, l’identificatore non viene più risolto e il sistema torna alla prima voce. Mantieni quindi anche il pacchetto oppure escludi quel kernel da autoremove.

Visualizzare il menu nella console del provider

La selezione interattiva richiede che il menu sia visualizzato, ma le immagini cloud lo nascondono. Inserire queste righe nel file che viene elaborato per ultimo, quindi eseguire sudo update-grub.

GRUB_TIMEOUT=10
GRUB_TIMEOUT_STYLE=menu
GRUB_RECORDFAIL_TIMEOUT=10

GRUB_TIMEOUT_STYLE=hidden insieme a GRUB_TIMEOUT=0 non visualizza nulla. Chi osserva la console vede quindi comparire immediatamente i messaggi del kernel e conclude che il bootloader sia stato ignorato. GRUB_RECORDFAIL_TIMEOUT è il timeout separato utilizzato dopo un avvio non completato. Anche questo valore è impostato su 0 nelle immagini cloud. Per questo motivo, un server il cui avvio è appena fallito non si arresta comunque in attesa di un intervento.

Se il provider offre una console seriale invece di una console grafica e non viene visualizzato nulla, GRUB sta scrivendo su un terminale che non è possibile vedere. Aggiungere entrambe le righe, perché la prima seleziona gli output e la seconda configura la porta:

GRUB_TERMINAL="console serial"
GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1"

Da questo momento, ogni avvio avrà dieci secondi di attesa aggiuntiva. Al termine, riportare il timeout a 0.

Opzioni più sicure della modifica del bootloader

Modificare l'input del bootloader su una macchina raggiungibile solo tramite SSH è l'opzione più rischiosa descritta in questa pagina. Esistono alternative meno costose in termini di rischio e, di solito, risolvono il problema reale.

Bloccare i pacchetti del kernel. Se l'obiettivo è "non installare un kernel più recente", comunicalo al gestore dei pacchetti invece di intervenire sul bootloader.

apt list --installed 2>/dev/null | grep -E '^linux-(image|headers|generic|virtual|kvm|aws|azure|gcp|oracle)'
sudo apt-mark hold linux-image-virtual linux-headers-virtual
apt-mark showhold

Usa i nomi stampati dal primo comando, perché le immagini cloud installano spesso la variante virtual o kvm invece di generic. Se il kernel più recente è comparso durante l'aggiornamento di un'immagine e sospetti che la release sia cambiata automaticamente, non è così: una point release contiene gli aggiornamenti già integrati nei nuovi supporti di installazione e non propone a un server già aggiornato nulla che non fosse già disponibile da settimane. Un pacchetto bloccato viene ignorato da apt upgrade, che lo segnala con The following packages have been kept back:, e viene ignorato anche dagli aggiornamenti automatici su Ubuntu. Il costo è concreto: un kernel bloccato non riceve più gli aggiornamenti di sicurezza. Consideralo quindi una sospensione temporanea con una scadenza e sbloccalo con sudo apt-mark unhold. Se eviti gli aggiornamenti del kernel perché i riavvii causano downtime, e non perché un kernel specifico presenta problemi, il live kernel patching su un VPS è la soluzione più adatta.

Crea uno snapshot prima dell'aggiornamento. Uno snapshot consente il ripristino in pochi minuti, senza digitare comandi nella console e senza rischiare una modifica parziale del bootloader. Crea lo snapshot, aggiorna, riavvia e verifica. Se il nuovo kernel presenta problemi, esegui il rollback: il percorso di avvio tornerà esattamente allo stato precedente.

Usa la console o un'immagine di ripristino per una macchina che è già fuori servizio. Quando il server non si avvia più, la configurazione del bootloader non è il punto in cui risolvere il problema. Il ripristino richiede una procedura dedicata: cosa fare quando un VPS non si avvia dopo un aggiornamento del kernel.

Cosa si rompe e quale messaggio verrà visualizzato

La modifica a /boot/grub/grub.cfg è scomparsa. È stato installato o rimosso un pacchetto del kernel, il relativo script del maintainer è stato eseguito update-grub e il file è stato rigenerato a partire dagli input. L'header # DO NOT EDIT THIS FILE indica le due posizioni di input. Modifica quelle.

grub-editenv: error: environment block too small. /boot/grub/grubenv manca o è troncato. Ricrealo con sudo grub-editenv /boot/grub/grubenv create, quindi imposta nuovamente il valore e verificalo con sudo grub-editenv list.

Un kernel bloccato causa un panic con VFS: Unable to mount root fs on unknown-block(0,0). La voce bloccata punta a un kernel o a un initrd che non si trova più sul disco, in genere perché il pacchetto è stato rimosso mentre l'identificatore è rimasto in grubenv. Per il ripristino, avvia dalla console una voce funzionante, quindi cancella il valore obsoleto.

uname -r non cambia dopo un riavvio che avrebbe dovuto modificarlo. Controlla tre elementi, in quest'ordine: grub-editenv list mostra ancora il tuo valore oppure è stato consumato; l'identificatore impostato compare nell'grub.cfg corrente; grub.cfg contiene una riga set default che legge la variabile impostata. Ogni volta, una di queste tre verifiche spiega il problema.

Il menu è comparso autonomamente dopo un crash. GRUB registra un avvio non riuscito in grubenv come recordfail=1 e, di conseguenza, forza la visualizzazione del menu all'avvio successivo per consentire l'intervento manuale. Quando la macchina funziona correttamente, cancella il valore con sudo grub-editenv /boot/grub/grubenv unset recordfail.


L'unica frase da ricordare è questa: il file che modifichi non è il file letto da GRUB e, in un'immagine cloud, il punto di divergenza tra i due è all'origine della confusione. Leggi prima la configurazione generata. Ogni decisione in questa pagina deriva da ciò che indica effettivamente.

FAQ

Perché GRUB_DEFAULT=1 non cambia il kernel con cui si avvia la mia VPS?

Perché in un'immagine cloud Ubuntu il file /boot/grub/grub.cfg generato contiene spesso una sola voce di avvio. L'indice 1 non identifica quindi alcuna voce e GRUB usa la prima. Verificalo con sudo grep -cE '^\s*(menuentry|submenu) ' /boot/grub/grub.cfg. Il risultato 1 è quello atteso. La causa è GRUB_FORCE_PARTUUID, impostato dal fornitore dell'immagine in un file sotto /etc/default/grub.d/. Questa impostazione indirizza il generatore verso un avvio diretto invece di creare un elenco completo dei kernel installati. Individua il file con grep -rn GRUB_FORCE_PARTUUID /etc/default/grub /etc/default/grub.d/.

Come posso avviare una sola volta il kernel precedente?

Esegui sudo grub-reboot '<identifier>' usando un identificatore copiato dal tuo grub.cfg, quindi riavvia con la console del provider già aperta. GRUB cancella next_entry prima dell'avvio. La scelta si applica quindi a un solo tentativo e un kernel che va in panic non viene riprovato. Verifica che il valore sia stato scritto con sudo grub-editenv list. Prima di farvi affidamento, esegui sudo grep -n next_entry /boot/grub/grub.cfg. Un'immagine la cui configurazione non carica mai grubenv ignorerà il comando senza segnalare errori.

È meglio fissare la scelta in base al numero della voce o all'identificatore?

In base all'identificatore. I numeri delle voci sono posizioni in un elenco che 10_linux ricrea dal kernel più recente al più vecchio. L'installazione o la rimozione di un kernel qualsiasi può quindi spostare le posizioni. Un 1>2 obsoleto può inoltre puntare a una voce reale ma diversa, senza alcun messaggio di avviso. Gli identificatori contengono la versione del kernel. Corrispondono quindi al kernel previsto oppure non vengono risolti. Elencali con sudo grep -n menuentry_id_option /boot/grub/grub.cfg e copia la stringa tra virgolette che segue ogni riga delle voci.

È più sicuro mantenere il pacchetto del kernel invece di modificare il bootloader?

Per l'obiettivo abituale, sì. sudo apt-mark hold linux-image-virtual linux-headers-virtual impedisce del tutto l'installazione di un kernel più recente. Il percorso di avvio non cambia e non c'è nulla che possa essere configurato in modo errato tramite una console che potrebbe non essere disponibile. Controlla prima i nomi delle varianti installate sul sistema con apt list --installed e verifica il blocco con apt-mark showhold. Lo svantaggio è che un kernel mantenuto non riceve correzioni di sicurezza. Decidi quindi quando eseguire sudo apt-mark unhold prima di applicare il blocco.