Actualizar un servidor Linux con apt de forma segura
La diferencia entre upgrade, full-upgrade y dist-upgrade, los paquetes retenidos, las preguntas de configuración de dpkg, el reinicio de kernel con needrestart y el cambio de versión como categoría aparte.
En un servidor recién instalado, una actualización es un trámite: no hay nada que se pueda romper. En cuanto el servidor presta servicios, son los detalles los que deciden si la actualización pasa sin que nadie la note o si después queda un archivo de configuración sobrescrito, un servicio que sigue con la biblioteca antigua en memoria o un kernel en marcha distinto del que hay en el disco. Este artículo los repasa uno por uno. La versión corta para un sistema recién aprovisionado está en la lista de comprobación para un servidor root nuevo.
Todos los datos se refieren a Debian 13 (trixie), Debian 12 (bookworm), Ubuntu 24.04 LTS y Ubuntu 22.04 LTS. Los comandos están escritos para ejecutarse como root. Si trabajas como usuario normal, antepón sudo a cada comando.
Antes de lanzar el primer comando: la vía de vuelta
Una actualización puede salir cara de tres formas: una pregunta de configuración sobrescribe la configuración de SSH, un kernel nuevo no arranca, o la conexión se corta en mitad de una transacción de dpkg. Las tres se pueden controlar, pero solo si tomas precauciones antes.
Una sesión que sobrevive a un corte de conexión
Si la conexión SSH se corta mientras se descomprimen los paquetes, el proceso en marcha recibe un SIGHUP y dpkg termina en mitad de una transacción. El resultado es una base de datos de paquetes a medio configurar. Por eso conviene lanzar las actualizaciones largas en una sesión que siga viva en el servidor aunque tu terminal desaparezca:
apt install -y tmux
tmux new -s upgrade
Si se cae la conexión, vuelve a iniciar sesión y recupera la sesión con tmux attach -t upgrade. Mientras tanto, la operación ha seguido su curso.
Cómo entrar en el servidor cuando SSH ya no responde
En los servidores root KVM y en los servidores dedicados de KernelHost tienes la consola VNC en el área de cliente. No depende del stack de red del sistema invitado y sigue funcionando aunque ya no haya ningún servicio escuchando. Entra por ahí una vez antes de necesitarlo y asegúrate de que conoces la contraseña de root.
Por si un kernel no arranca, necesitas además un menú de arranque visible. En los servidores suele estar oculto:
grep -E '^GRUB_TIMEOUT|^GRUB_TIMEOUT_STYLE' /etc/default/grub
Si ahí aparece GRUB_TIMEOUT_STYLE=hidden o GRUB_TIMEOUT=0, pon GRUB_TIMEOUT_STYLE=menu y GRUB_TIMEOUT=5 y ejecuta update-grub. En caso de emergencia, elige en la consola VNC el kernel anterior dentro de "Advanced options".
Comprobar el estado y dejarlo registrado
Tres comprobaciones previas que encuentran algo más a menudo de lo que uno esperaría:
df -h / /boot /var
dpkg --audit
apt-get check
Control de resultado: dpkg --audit no imprime nada, apt-get check termina sin ninguna línea de error y en /boot quedan libres al menos 300 MB. Un /boot lleno es la causa más frecuente de una actualización de kernel abortada, tienes más sobre eso en Disco lleno en Linux. Si dpkg --audit informa de algo, repáralo primero con dpkg --configure -a.
Después, guarda el estado actual para poder compararlo más adelante:
dpkg --get-selections > /root/paquetes-antes-de-actualizar.txt
apt-mark showhold > /root/holds-antes-de-actualizar.txt
cp -a /etc/apt /root/apt-config-$(date +%F)
update, upgrade, full-upgrade y dist-upgrade
Estas cuatro palabras se confunden constantemente. La diferencia no es cosmética: decide si se instala un kernel nuevo y si pueden desaparecer paquetes.
| Comando | Paquetes nuevos | Elimina paquetes | Uso |
|---|---|---|---|
apt update | no | no | solo descarga las listas de paquetes, no cambia nada en el sistema |
apt-get upgrade | no | no | la variante más prudente, retiene las actualizaciones de kernel |
apt upgrade | sí, si una dependencia lo exige | no | el caso normal en sistemas en producción |
apt full-upgrade | sí | sí, si hace falta | cuando aceptas las eliminaciones a conciencia |
apt-get dist-upgrade | sí | sí, si hace falta | el nombre antiguo para lo mismo |
De ahí se derivan dos cosas. Primera: dist-upgrade no tiene nada que ver con pasar a una nueva versión de la distribución. El nombre es histórico, el comando se queda dentro de tu versión actual.
Segunda: la diferencia entre apt upgrade y apt-get upgrade es justo el motivo por el que algunos servidores se quedan sin kernel nuevo. Debian engancha el kernel a través del metapaquete linux-image-amd64, y Ubuntu a través de linux-image-generic o linux-image-virtual. En cada cambio de ABI, ese metapaquete apunta a un paquete nuevo que lleva el número de versión en el nombre. apt-get upgrade no instala paquetes nuevos por principio y por eso deja el kernel donde estaba, mientras que apt upgrade sí lo instala, porque una dependencia lo exige. Quien use apt-get upgrade en un script de mantenimiento necesita añadir ahí --with-new-pkgs.
Sobre la elección de herramienta: cuando se le llama desde un script, apt escribe la línea WARNING: apt does not have a stable CLI interface. Use with caution in scripts. No es un mensaje de error, pero sí un aviso con fundamento. En scripts y en roles de Ansible va apt-get; de forma interactiva, apt resulta más cómodo.
El procedimiento, con una comprobación después de cada paso
Paso 1: descargar las listas de paquetes.
apt update
Control de resultado: la salida no contiene ninguna línea que empiece por Err: o W:. Al final aparece o bien All packages are up to date. o bien un número seguido de packages can be upgraded. Cualquier línea de error aquí significa que seguirías trabajando con una imagen incompleta.
Paso 2: mirar qué es lo que va a pasar. Este paso falta en la mayoría de las guías y es el más importante de todo el procedimiento.
apt list --upgradable
apt full-upgrade -s
La opción -s simula y no cambia nada. Las líneas que aparecen bajo The following packages will be REMOVED: son las únicas que realmente tienes que revisar. Si ahí no hay nada, full-upgrade es tan inofensivo como upgrade. Si ahí aparece un paquete que necesitas, usa apt upgrade y aclara la causa por separado.
En Debian merece la pena además apt install apt-listchanges. El paquete muestra antes de instalar los changelogs y, lo que es más importante, los archivos NEWS de los mantenedores de paquetes. Ahí está justo lo que exige trabajo a mano.
Paso 3: aplicar la actualización.
apt upgrade
Quédate delante. La operación hace preguntas, y un -y solo responde a la pregunta propia de apt, no a las que tienen que ver con los archivos de configuración. Esas vienen de dpkg y esperan con paciencia a que alguien conteste.
Control de resultado:
apt list --upgradable
dpkg --audit
systemctl --failed
journalctl -p 3 -b --no-pager | tail -n 20
Lo que se espera: apt list --upgradable no imprime nada aparte de Listing..., dpkg --audit se queda callado y systemctl --failed informa de 0 loaded units listed. Lo que ha ocurrido de verdad queda registrado de forma permanente en /var/log/apt/history.log, y la salida completa de dpkg en /var/log/apt/term.log.
Paquetes retenidos: dos causas muy distintas
Cuando apt se salta paquetes, hay dos motivos radicalmente distintos que se confunden con regularidad.
El primero, un bloqueo real. Alguien ha fijado el paquete de forma expresa:
apt-mark showhold
Si el comando imprime algo, fue una decisión consciente, normalmente en bases de datos o en módulos del kernel. Lo levantas con apt-mark unhold NOMBRE_DEL_PAQUETE y lo pones con apt-mark hold NOMBRE_DEL_PAQUETE. Un bloqueo a nivel de dpkg lo ves con dpkg --get-selections | grep -w hold.
El segundo, el mensaje The following packages have been kept back:. Eso no es un bloqueo. Significa que, para esa actualización, apt tendría que instalar un paquete de más o eliminar otro, y el comando empleado no tiene permiso para hacerlo. La prueba, en una sola línea y sin cambiar nada:
apt full-upgrade -s | head -n 20
Si el paquete aparece ahí, ya tienes la explicación, y apt full-upgrade lo resuelve. En Debian 13, la generación más reciente de apt da otro formato a esa salida, pero el contenido no cambia.
El caso especial de Ubuntu. Ubuntu distribuye las actualizaciones de forma escalonada, no todos los servidores las reciben el mismo día. Un paquete puede quedarse retenido aunque no haya ningún bloqueo ni ninguna dependencia de por medio. El diagnóstico va por descarte: apt-mark showhold está vacío, apt full-upgrade -s no muestra ninguna eliminación y, aun así, apt-cache policy NOMBRE_DEL_PAQUETE nombra un candidato más reciente. En ese caso espera unos días o adelanta tú la actualización:
apt -o APT::Get::Always-Include-Phased-Updates=true upgrade
En Debian 13 y Debian 12 no existe la distribución escalonada, así que ahí esta causa queda descartada de entrada.
Cuando apt pregunta por un archivo de configuración
Esa pregunta aparece solo cuando se cumplen dos condiciones a la vez: el archivo se ha modificado localmente desde la instalación y el paquete trae una versión nueva. Tiene este aspecto:
Configuration file '/etc/ssh/sshd_config'
==> Modified (by you or by a script) since installation.
==> Package distributor has shipped an updated version.
What would you like to do about it ? Your options are:
Y or I : install the package maintainer's version
N or O : keep your currently-installed version
D : show the differences between the versions
Z : start a shell to examine the situation
The default action is to keep your current version.
*** sshd_config (Y/I/N/O/D/Z) [default=N] ?
El valor por defecto es N, es decir, conservar tu versión. Es la respuesta segura, pero no siempre la correcta.
| Situación | Respuesta |
|---|---|
| Ya no recuerdas qué se cambió | D, mirar la diferencia y decidir después |
| Tus cambios están puestos a conciencia y el paquete solo toca comentarios | N, y después comparar el .dpkg-dist |
| El archivo lo genera una herramienta como cloud-init o Ansible | N, y después volver a ejecutar la herramienta |
| Los valores nuevos son relevantes para la seguridad y tu cambio es prescindible | Y, y después volver a aplicar tus ajustes |
| Archivo crítico y no lo tienes claro | Z, copiar el archivo aparte, salir del shell y luego N |
Con /etc/ssh/sshd_config conviene extremar la precaución: una Y puede devolver PermitRootLogin y PasswordAuthentication al valor del paquete, y justo de eso depende tu acceso. Por eso los ajustes propios de SSH van en un archivo aparte dentro de /etc/ssh/sshd_config.d/, tal y como se describe en Asegurar SSH y configurar el acceso por clave. Un archivo que no existe en el paquete no provoca nunca una pregunta.
Respondas lo que respondas, dpkg no tira nada. Con N, la versión nueva se queda al lado como .dpkg-dist; con Y, la tuya antigua como .dpkg-old. Repasar esos archivos es el verdadero trabajo posterior:
find /etc -name '*.dpkg-dist' -o -name '*.dpkg-old' -o -name '*.dpkg-new' -o -name '*.ucf-dist'
diff -u /etc/ssh/sshd_config /etc/ssh/sshd_config.dpkg-dist
Para ejecuciones desatendidas, por ejemplo dentro de un script de mantenimiento, define el comportamiento de antemano. Esta combinación conserva tu versión y no pregunta nada:
DEBIAN_FRONTEND=noninteractive apt-get -y \
-o Dpkg::Options::="--force-confdef" \
-o Dpkg::Options::="--force-confold" \
upgrade
--force-confnew sería lo contrario y coge siempre la versión del paquete. En un servidor con configuración propia, eso rara vez es lo que quieres.
Las actualizaciones de kernel y la cuestión del reinicio
Al instalarse, un kernel nuevo va a parar a /boot y al menú de arranque. El kernel en marcha sigue igual en memoria hasta el reinicio. Un servidor puede estar, por tanto, al día y ser vulnerable al mismo tiempo. La prueba más sencilla es una comparación:
uname -r
ls -1 /boot/vmlinuz-*
Si en /boot hay una versión más alta que la que informa uname -r, toca reiniciar. En Ubuntu 24.04 y 22.04 existe además un archivo marcador que también tiene en cuenta las actualizaciones de bibliotecas:
test -f /var/run/reboot-required && cat /var/run/reboot-required.pkgs
El segundo archivo nombra los paquetes que han pedido el reinicio. En Debian 13 y Debian 12 ese marcador no se crea de forma fiable, así que ahí el camino correcto es needrestart.
needrestart: qué servicios siguen usando la biblioteca antigua
Una actualización de OpenSSL o de glibc sustituye el archivo en el disco. Todo proceso que ya lo tuviera cargado sigue trabajando con la versión antigua. needrestart encuentra exactamente esos procesos. En Ubuntu 24.04 y 22.04 viene preinstalado y aparece después de cada actualización con una pregunta a pantalla completa; en Debian lo instalas tú:
apt install -y needrestart
needrestart -b
El modo -b devuelve una salida legible por máquina. De ahí hay dos datos decisivos: NEEDRESTART-KSTA con el valor 1 significa que el kernel en marcha es el esperado, y cualquier otro valor significa que hay uno más reciente esperando. Cada línea NEEDRESTART-SVC nombra un servicio que debería reiniciarse.
El comportamiento se controla con la variable de entorno NEEDRESTART_MODE: a reinicia los servicios automáticamente, l solo los lista e i pregunta. De forma permanente, lo mismo se define en /etc/needrestart/needrestart.conf. Para scripts, la variable es la mejor opción porque no toca la configuración:
NEEDRESTART_MODE=a DEBIAN_FRONTEND=noninteractive apt-get -y upgrade
Hay un límite que conviene conocer: needrestart mira los procesos del sistema anfitrión. No renueva los servicios que corren dentro de contenedores, ahí necesitas imágenes nuevas.
El cambio de versión es una categoría aparte
Pasar de Debian 12 a Debian 13 o de Ubuntu 22.04 a 24.04 no es una actualización en el sentido anterior. Cambia las fuentes de paquetes y sustituye prácticamente todos los paquetes. Aquí valen siempre tres reglas: una versión por pasada, ninguna versión intermedia saltada y, antes de empezar, un backup con el que se pueda restaurar el servidor.
En Debian, lo primero es cambiar las fuentes. Debian 12 usa para ello /etc/apt/sources.list, y Debian 13 el archivo /etc/apt/sources.list.d/debian.sources en el formato más reciente. Después viene un procedimiento deliberadamente en dos fases, tal y como lo marcan las notas de publicación:
apt update
apt-get upgrade --without-new-pkgs
apt full-upgrade
El paso intermedio actualiza primero los paquetes que no necesitan reestructuración. Eso mantiene bajo el número de paquetes que se mueven a la vez y hace que una interrupción sea reparable. No te olvides del componente non-free-firmware: desde Debian 12 es independiente y falta en los archivos de fuentes antiguos. Si tu apt conoce el comando apt modernize-sources (lo compruebas con apt --version), él mismo convierte el archivo de fuentes antiguo al formato nuevo.
En Ubuntu hay una herramienta propia para esto, y deberías usar exclusivamente esa:
apt install -y ubuntu-release-upgrader-core
do-release-upgrade -c
do-release-upgrade
La opción -c solo comprueba y no cambia nada. Que se te ofrezca o no el cambio depende de Prompt en /etc/update-manager/release-upgrades: con lts aparece solo el salto a la siguiente versión LTS, y además solo después de su primera versión de mantenimiento. El camino de 20.04 a 24.04 pasa obligatoriamente por 22.04.
Un detalle que sorprende a mucha gente: si do-release-upgrade se ejecuta por SSH, levanta un servicio SSH adicional en el puerto 1022 como vía de reserva y avisa de que quizá tengas que abrir ese puerto en el firewall. Aprovéchalo, pero no te fíes solo de eso. La sesión de tmux y el acceso por la consola VNC son más fiables.
Limpiar después de la actualización
Después de una pasada grande quedan por ahí tres tipos de restos: archivos de paquete descargados, paquetes huérfanos y restos de configuración de paquetes ya eliminados.
apt autoremove --purge
apt autoclean
autoclean borra de /var/cache/apt/archives solo los archivos que de todas formas ya no se ofrecen. apt clean vacía la caché por completo, así que libera más espacio, pero a cambio convierte cualquier reinstalación en una descarga nueva.
Los restos de configuración los reconoces por el estado rc de dpkg, es decir, eliminado pero con la configuración todavía presente:
dpkg -l | awk '/^rc/ {print $2}'
Lo que aparece ahí lo eliminas definitivamente con apt purge NOMBRE_DEL_PAQUETE. Con los kernels antiguos hace falta más cuidado, porque una equivocación deja el servidor sin poder arrancar:
uname -r
dpkg -l 'linux-image-*' | awk '/^ii/ {print $2}'
No elimines nunca el kernel que nombra la primera línea, y guarda además uno anterior que funcione para que el menú de arranque tenga una vía de reserva. Normalmente apt autoremove --purge ya lo hace bien por sí solo.
Errores frecuentes y soluciones
E: Could not get lock /var/lib/dpkg/lock-frontend. It is held by process 1234 (unattended-upgr): ya hay otra operación de paquetes en marcha, casi siempre la actualización de seguridad automática. No la interrumpas, déjala terminar. El procedimiento completo, reparación incluida, está en Solucionar el error de apt "Could not get lock".
E: dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem.: una ejecución anterior se quedó a medias, normalmente por un corte de conexión. Ejecuta exactamente ese comando y repite después la actualización.
E: Unmet dependencies. Try 'apt --fix-broken install' with no packages (or specify a solution).: hay un paquete instalado al que le faltan sus dependencias. apt --fix-broken install las trae. Si el error vuelve, casi siempre se debe a una fuente externa que ofrece paquetes para otra versión de la distribución.
E: Release file for http://deb.debian.org/debian/dists/trixie/InRelease is not valid yet (invalid for another 5h 3min 2s).: el reloj del servidor va atrasado. Comprueba con timedatectl status si informa de System clock synchronized: yes, corrige la hora y repite apt update. El repositorio no tiene la culpa.
W: GPG error: ... The following signatures couldn't be verified because the public key is not available: NO_PUBKEY ..., seguido de E: The repository '...' is not signed.: falta la clave de firma de una fuente externa o la han cambiado. Hoy la clave va en /etc/apt/keyrings/ y se referencia en la definición de la fuente mediante signed-by o mediante el campo Signed-By:. apt-key está obsoleto y ya no debería usarse.
E: Repository '... InRelease' changed its 'Suite' value from 'stable' to 'oldstable': esto pasa con toda normalidad cuando sale una versión nueva de Debian y tus fuentes apuntan a stable en lugar de al nombre en clave. Confírmalo una vez con apt update --allow-releaseinfo-change y cambia después las fuentes al nombre en clave. Si no, un servidor que sigue a stable acabará cambiando de versión de distribución sin que nadie lo haya querido.
E: The repository 'http://... Release' does not have a Release file.: la fuente no ofrece nada para tu versión, casi siempre porque una fuente externa todavía no admite ese nombre en clave o porque la distribución ha llegado al final de su vida útil. Desactiva la línea afectada y revisa la fuente.
No space left on device en mitad de la descompresión: /boot o /var están llenos. Ordena con dpkg --configure -a, libera espacio y repite. Antes de cada actualización de kernel merece la pena echar un vistazo a df -h /boot.
debconf: unable to initialize frontend: Dialog: es solo un aviso, no un fallo. Aparece cuando no hay un terminal completo, por ejemplo dentro de un script. Con DEBIAN_FRONTEND=noninteractive desaparece.
Los cuatro sistemas comparados
| Tema | Debian 13 | Debian 12 | Ubuntu 24.04 | Ubuntu 22.04 |
|---|---|---|---|---|
| Archivo de fuentes | sources.list.d/debian.sources | sources.list | sources.list.d/ubuntu.sources | sources.list |
| needrestart | hay que instalarlo | hay que instalarlo | preinstalado | preinstalado |
| Marcador de reinicio | poco fiable, usa needrestart | poco fiable, usa needrestart | /var/run/reboot-required | /var/run/reboot-required |
| Distribución escalonada | no | no | sí | sí |
| Cambio de versión | cambiar las fuentes y después en dos fases | do-release-upgrade | ||
La comprobación final
Que un comando haya vuelto sin errores no significa que el sistema esté en orden. Estas seis comprobaciones sí dicen algo:
apt list --upgradableno imprime nada aparte deListing....apt-mark showholdcontiene solo lo que has bloqueado a conciencia.dpkg --auditse queda callado.needrestart -binforma deNEEDRESTART-KSTA: 1y de ningún servicio pendiente.systemctl --failedno lista nada.find /etc -name '*.dpkg-dist'ya no encuentra nada, porque has resuelto cada divergencia.
Si el punto cuatro pide un reinicio, planifícalo y llévalo a cabo. Un servidor que lleva meses esperando un reinicio pendiente va acumulando justo los agujeros contra los que en teoría has actualizado. Después comprueba una última vez uname -r y systemctl --failed. El reinicio es el momento en el que se ve si todo vuelve a levantarse.
Preguntas frecuentes
¿Cuál es la diferencia entre apt upgrade y apt full-upgrade?
¿dist-upgrade significa pasar a la siguiente versión de la distribución?
¿Por qué apt avisa de "The following packages have been kept back"?
apt me pregunta si debe sustituir un archivo de configuración. ¿Qué contesto?
¿Cómo sé que después de una actualización hace falta reiniciar?
¿Para qué necesito needrestart si de todas formas voy a reiniciar?
¿Cómo actualizo de forma desatendida sin que la ejecución se quede colgada en una pregunta?
¿Puede una actualización dejarme fuera del servidor?
2026 KernelHost GmbH. Todos los derechos reservados. Esta guía está protegida por derechos de autor. Su publicación en otros sitios web, aunque sea de forma parcial o modificada, no está permitida sin nuestro consentimiento por escrito. Las citas con indicación de la fuente y un enlace son muy bienvenidas.

