SSD Nodes Learn Hosting plans →
Guías Matt ConnorPor Matt Connor

Por qué unattended-upgrades no funciona en Debian

Debian instala unattended-upgrades desactivado. Actívalo, revisa Origins-Pattern y los temporizadores apt-daily para confirmar que aplica actualizaciones automáticamente.

Por qué unattended-upgrades no hace nada en una instalación nueva de Debian

En Debian, unattended-upgrades puede estar instalado y no ejecutar nunca ninguna actualización, porque instalar el paquete y habilitarlo son dos pasos distintos. El paquete formula una pregunta de debconf antes de configurarse, y el instalador de Debian guarda la respuesta false para esa pregunta. Ubuntu responde a la misma pregunta de otra forma. Por eso el mismo paquete parece funcionar allí y parece estar averiado aquí.

El sistema no informa de este problema. No aparece ningún error durante el arranque ni ninguna advertencia al iniciar sesión. Tampoco hay ningún archivo de registro que revisar, porque el código que escribiría ese registro nunca se ejecuta. Activarlo requiere un solo comando. El resto de esta guía cubre los cuatro aspectos que todavía pueden impedir su ejecución: desde qué repositorios puede actualizar, cuándo se activan realmente los temporizadores de systemd, cómo saber si una ejecución ha fallado y si el equipo tiene permitido reiniciarse automáticamente.

Muestra lo que el sistema cree antes de cambiar nada

dpkg -l unattended-upgrades | tail -n 1
sudo apt install -y debconf-utils
sudo debconf-show unattended-upgrades
cat /etc/apt/apt.conf.d/20auto-upgrades
apt-config dump APT::Periodic

debconf-show muestra la respuesta almacenada para unattended-upgrades/enable_auto_updates. Un * al principio de esa línea indica que algo estableció el valor en lugar de dejar el valor predeterminado del paquete. En un equipo instalado con el instalador de Debian, ese algo es el instalador.

cat puede mostrar cat: /etc/apt/apt.conf.d/20auto-upgrades: No such file or directory. Eso explica por sí solo la ausencia de actividad: sin ningún archivo no hay ejecuciones periódicas y, por tanto, nunca se programa nada.

apt-config dump es el comando importante. APT lee los archivos de /etc/apt/apt.conf.d/ en orden alfabético por nombre y los combina, de modo que un valor sencillo establecido en 99local sobrescribe el mismo valor en 20auto-upgrades. Sólo se tienen en cuenta los nombres sin extensión o con una extensión .conf, por lo que se omite un archivo como 99local.bak. Leer un archivo indica lo que contiene ese archivo. apt-config dump indica lo que APT hará realmente.

Dos claves determinan si se ejecuta algo:

  • APT::Periodic::Update-Package-Lists actualiza las listas de paquetes. Esa es la tarea que apt update ejecuta manualmente.
  • APT::Periodic::Unattended-Upgrade ejecuta la actualización propiamente dicha.

Sus valores no son verdadero y falso. Son intervalos en días. "1" significa «ejecutar si no se ha hecho durante el último día», "7" significa una vez por semana y "0" significa nunca. APT::Periodic::Unattended-Upgrade "0"; es una configuración válida que no ejecuta nada, indefinidamente y sin mostrar ningún error. Si el volcado muestra 0 para esa clave, o no muestra la clave, ya ha encontrado el motivo.

Activarlo: dpkg-reconfigure o escribir las claves manualmente

sudo apt update
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades

La pregunta tiene prioridad baja, por eso una instalación normal nunca la muestra. dpkg-reconfigure muestra las preguntas de prioridad baja independientemente de la prioridad de debconf configurada, así que --priority=low sólo hace explícito lo que ya realiza. La única opción que debe evitar es --default-priority, porque desactiva ese comportamiento y vuelve a ocultar la pregunta. Responda «sí» en el diálogo. A continuación, el script postinst del paquete escribe /etc/apt/apt.conf.d/20auto-upgrades a partir de su respuesta.

En una máquina que se construye mediante un script no hay ningún diálogo que responder, así que establezca primero la respuesta:

echo 'unattended-upgrades unattended-upgrades/enable_auto_updates boolean true' \
  | sudo debconf-set-selections
sudo dpkg-reconfigure -f noninteractive unattended-upgrades
apt-config dump APT::Periodic

También puede escribir directamente las dos claves:

printf 'APT::Periodic::Update-Package-Lists "1";\nAPT::Periodic::Unattended-Upgrade "1";\n' \
  | sudo tee /etc/apt/apt.conf.d/20auto-upgrades
apt-config dump APT::Periodic

Esto funciona de inmediato, pero deja una trampa. La respuesta de debconf sigue indicando el valor antiguo, por lo que el siguiente dpkg-reconfigure, o una reinstalación del paquete, vuelve a escribir el archivo a partir de debconf y deshace la modificación sin mostrar ningún mensaje. Establezca ambas cosas o configure debconf y deje que postinst sea el propietario del archivo.

Esta es la única diferencia real respecto al otro miembro de la familia. Allí, el instalador activa el mismo paquete por usted, por lo que la configuración de Ubuntu unattended-upgrades parte de un sistema que ya aplica actualizaciones automáticamente y se centra en el ajuste. Todo lo que sigue se aplica a ambos.

¿Qué actualizaciones instala realmente Debian?

Habilitar el temporizador no equivale a aceptar la instalación de todo. Cada fuente de paquetes incluye metadatos de publicación: un origen, una etiqueta, una suite, un nombre en clave y un sitio. unattended-upgrades examina la versión candidata de cada paquete actualizable, lee los metadatos de la fuente de la que procedería y sólo lo instala si esa fuente coincide con una entrada de Unattended-Upgrade::Origins-Pattern o de la lista antigua Unattended-Upgrade::Allowed-Origins. Si no hay coincidencia, no actualiza el paquete. Esto es intencionado.

Muestre sus patrones y, después, los metadatos con los que se comparan:

apt-config dump Unattended-Upgrade::Origins-Pattern
grep -H -E '^(Origin|Label|Suite|Codename|Components):' /var/lib/apt/lists/*Release
apt-cache policy

grep -H conserva el nombre del archivo en cada línea, para que pueda ver a qué fuente pertenece cada bloque de metadatos. Esos valores de campo son los lados derechos de sus patrones. Dentro de un patrón, ${distro_codename} se sustituye en tiempo de ejecución por el nombre en clave de la versión que está usando, por lo que un mismo archivo sigue funcionando después de actualizar a otra versión.

Lea sus propios patrones junto a esos metadatos. La respuesta a «¿recibo sólo correcciones de seguridad o también actualizaciones de punto?» está escrita en esas dos listas y en ningún otro lugar:

  • Un patrón que nombre label=Debian-Security coincide con el archivo de seguridad. Ahí se publican los avisos de seguridad de Debian.
  • Un patrón que nombre la suite -updates coincide con stable-updates, que contiene lo que Debian publica entre versiones de punto, como los datos de zonas horarias.
  • Un patrón que nombre la suite de la versión sin más componentes incorpora los cambios de las versiones de punto cuando se publican. Esto implica más cambios y más trabajo de pruebas por su parte.
  • Un repositorio que haya añadido usted no coincide con nada hasta que escriba un patrón para él.

Este último caso sorprende a muchas personas. Un repositorio de terceros tiene su propio origen y su propia etiqueta. Por eso, unattended-upgrades ve el paquete candidato, comprueba que la fuente no coincide con nada y continúa. Añadir un patrón para ese repositorio es una decisión que conviene tomar con calma. Un repositorio del proveedor puede publicar una versión principal nueva dentro de la misma suite. En ese caso, habrá aceptado actualizaciones principales desatendidas de ese software durante la noche.

unattended-upgrades tampoco cambia nunca de una versión de Debian a otra. Actualiza los paquetes dentro de la versión que está usando. Pasar de una versión estable a la siguiente sigue siendo una tarea manual que debe programar usted.

Cuando cambie la lista, recuerde que las listas de APT se añaden. Un segundo bloque Origins-Pattern en otro archivo se suma a la lista proporcionada por el paquete en lugar de reemplazarla. Si quiere reemplazarla, debe vaciarla primero:

#clear Unattended-Upgrade::Origins-Pattern;
Unattended-Upgrade::Origins-Pattern {
  "origin=Debian,codename=${distro_codename},label=Debian-Security";
  "origin=Debian,codename=${distro_codename}-security,label=Debian-Security";
};

Guarde los cambios locales en un archivo nuevo que se ordene después del archivo proporcionado por el paquete, por ejemplo /etc/apt/apt.conf.d/52unattended-upgrades-local. 50unattended-upgrades es un archivo de configuración administrado por el paquete. Después de editarlo, cualquier actualización posterior que incluya una versión modificada del archivo se detendrá y le preguntará qué hacer con su versión. Un archivo separado nunca entra en conflicto.

También conviene mostrar otras dos claves. Unattended-Upgrade::Allowed-Origins es la forma antigua de la misma idea, escrita como pares origin:archive, y todavía se lee. Por eso, una configuración copiada de un tutorial puede acabar teniendo ambas listas, sin una respuesta clara sobre cuál produjo la coincidencia. Unattended-Upgrade::Package-Blacklist contiene expresiones regulares que se comparan con los nombres de los paquetes. Una expresión demasiado amplia puede bloquear mucho más de lo previsto. La simulación siguiente muestra qué configuración se aplicó realmente.

¿Por qué no se ejecutó nada a la hora prevista?

Dos temporizadores de systemd controlan este proceso y realizan tareas diferentes. apt-daily.timer inicia apt-daily.service, que actualiza las listas de paquetes y descarga paquetes. apt-daily-upgrade.timer inicia apt-daily-upgrade.service, que es el que llama a unattended-upgrade. Ambos ejecutan /usr/lib/apt/apt.systemd.daily con argumentos diferentes. Si el segundo temporizador está deshabilitado o enmascarado, ambas claves periódicas pueden mostrar 1 y aun así no se instalará nada.

systemctl list-timers 'apt-daily*' --all
systemctl is-enabled apt-daily.timer apt-daily-upgrade.timer
systemctl cat apt-daily-upgrade.timer

list-timers muestra NEXT, LEFT, LAST y PASSED para cada unidad. Un temporizador sin NEXT no se ejecutará. Que is-enabled muestre masked significa que alguien lo deshabilitó de forma forzada, y nada de lo que escriba en apt.conf.d cambiará esa situación.

Ahora lea la sección [Timer] que mostró systemctl cat. OnCalendar es el momento más temprano en que puede activarse el temporizador. RandomizedDelaySec añade una espera aleatoria a partir de ese momento, para que una flota de máquinas Debian no acceda a los mismos mirrors en el mismo segundo. Por eso la columna NEXT muestra una hora que no coincide con OnCalendar y por eso la ejecución de ayer se produjo en un minuto diferente. Es el comportamiento previsto. Persistent=true hace que una máquina apagada a la hora programada ejecute el trabajo poco después del siguiente arranque, en lugar de omitirlo ese día.

Para cambiar la ventana, cree una sobreescritura de la unidad en lugar de editarla:

sudo systemctl edit apt-daily-upgrade.timer
[Timer]
OnCalendar=
OnCalendar=03:30
RandomizedDelaySec=30m

La línea OnCalendar= vacía es necesaria porque la configuración de las unidades basada en listas se acumula: si la omite, conservará el calendario incluido con el paquete y añadirá un segundo calendario. systemctl edit vuelve a cargar systemd, así que confirme el resultado con systemctl list-timers 'apt-daily*' y compruebe el nuevo NEXT.

No es necesario esperar a que se active un temporizador para probar todo esto:

sudo systemctl start apt-daily-upgrade.service
journalctl -u apt-daily-upgrade.service --since -1h

Hay algo que confunde a quienes buscan en /etc/cron.daily: APT todavía incluye /etc/cron.daily/apt-compat para los sistemas sin systemd. Léalo con cat. En un sistema con systemd termina pronto, por lo que el trabajo no se realiza dos veces.

Demuestre que funciona: unattended-upgrade --dry-run --debug

sudo unattended-upgrade --dry-run --debug

El comando está en singular y el nombre del paquete, en plural. Debian 12 y 13 también incluyen un /usr/bin/unattended-upgrades, por lo que allí el plural ya no termina en command not found, pero el comando documentado, y el que se usa en toda esta guía, es el singular unattended-upgrade.

Este comando responde a casi todas las preguntas sobre por qué se omitió un paquete, porque muestra sus propios motivos. Cerca del principio muestra los orígenes que calculó a partir de sus patrones:

Allowed origins are: ...

Después muestra una línea por cada paquete candidato, con el registro de origen de la versión que instalaría:

Checking: curl ([<Origin component:'main' archive:'stable' origin:'Debian' label:'Debian' site:'deb.debian.org' isTrusted:True>])

A continuación muestra la lista sobre la que actuaría o, si no hay nada que hacer:

No packages found that can be upgraded unattended and no pending auto-removals

Combine la primera y la segunda salida para obtener un diagnóstico directo. Busque la línea Checking: correspondiente al paquete que esperaba ver actualizado. Compare campo por campo su registro de origen con los orígenes permitidos mostrados arriba. Un campo que no coincida, normalmente label o archive, es la razón completa por la que se omitió.

--dry-run marca los paquetes en memoria y no instala nada, por lo que puede ejecutarlo tantas veces como quiera. Aun así, añade entradas a /var/log/unattended-upgrades/unattended-upgrades.log.

Si los orígenes coinciden y un paquete sigue retenido, revise estos puntos:

  • apt-mark showhold muestra los paquetes fijados por usted o por alguna herramienta. unattended-upgrades no actualizará un paquete retenido.
  • La actualización tendría que eliminar o añadir otro paquete. unattended-upgrades evita hacerlo salvo que las claves correspondientes lo permitan. Compare con sudo apt-get -s upgrade, que muestra la misma decisión sin esas reglas de seguridad.
  • dpkg quedó parcialmente configurado después de una ejecución interrumpida. Corríjalo con sudo dpkg --configure -a y vuelva a comprobarlo.
  • /var no tiene espacio libre, por lo que no se descarga ni desempaqueta nada. Compruébelo con df -h /var.
  • /boot está lleno de kernels antiguos, lo que impide la siguiente actualización del kernel. Compruébelo con df -h /boot y muestre apt-config dump Unattended-Upgrade::Remove-Unused-Kernel-Packages para verificar si la limpieza está activada.

Si ejecuta apt manualmente mientras el temporizador está activo, verá Could not get lock /var/lib/dpkg/lock-frontend. Ese mensaje significa que unattended-upgrades está funcionando correctamente. Espere a que termine.

¿Cómo se comprueba cuándo falla una ejecución?

Empiece por los registros, porque existen tanto si configura otras opciones como si no:

sudo tail -n 40 /var/log/unattended-upgrades/unattended-upgrades.log
sudo tail -n 40 /var/log/unattended-upgrades/unattended-upgrades-dpkg.log
journalctl -u apt-daily-upgrade.service --since -7d

El primer archivo es el registro de decisiones: qué se comprobó, qué se eligió y qué se instaló. El segundo contiene la salida sin procesar de dpkg. Ahí se muestra si falla el script postinst de un paquete. Si las actualizaciones se ejecutan mientras la máquina se apaga, aparece un registro de apagado independiente.

El correo es el método habitual de notificación:

Unattended-Upgrade::Mail "you@example.com";
Unattended-Upgrade::MailReport "on-change";

MailReport acepta always, on-change y only-on-error. only-on-error parece la opción más rigurosa, pero normalmente es la elección incorrecta en un servidor en el que nadie inicia sesión. Una máquina que ha dejado de actualizarse por completo tampoco envía errores. En ese caso, el silencio oculta por igual un sistema en buen estado y uno detenido. on-change envía un mensaje cada vez que se instala algo, por lo que el correo también demuestra que el temporizador sigue activo.

El correo sólo sale de la máquina si esta puede enviarlo. unattended-upgrades entrega el mensaje al sistema de correo local, por lo que necesita un MTA (agente de transferencia de correo), como postfix, o un cliente de retransmisión compatible con sendmail, como msmtp. Compruébelo con command -v sendmail y command -v mail. Si no hay ninguno de los dos, el informe no llega a ninguna parte, la actualización se completa y todo el fallo queda oculto. Tenga en cuenta también que la dirección IP nueva de un VPS no tiene reputación de envío. Por eso, el correo enviado directamente a un buzón público suele clasificarse como spam. Es más fiable retransmitirlo mediante un proveedor de correo que ya utilice que ejecutar su propio servidor para este fin.

Si prefiere no ejecutar ningún servicio de correo, supervise la marca de tiempo del registro mediante la herramienta de monitorización que utilice:

stat -c '%y %n' /var/log/unattended-upgrades/unattended-upgrades.log

Una marca de tiempo que no cambia durante una semana indica que el temporizador se detuvo, independientemente de lo que indique la configuración. Incluya esta comprobación junto con el resto de comprobaciones rutinarias de mantenimiento del servidor Linux.

¿Debe reiniciarse el servidor automáticamente?

Unattended-Upgrade::Automatic-Reboot "false";
Unattended-Upgrade::Automatic-Reboot-WithUsers "true";
Unattended-Upgrade::Automatic-Reboot-Time "02:00";

Con Automatic-Reboot establecido en true, unattended-upgrades reinicia el sistema sin confirmación, pero sólo cuando el archivo /var/run/reboot-required existe después de finalizar la ejecución. En Debian 12 y 13, el paquete unattended-upgrades crea ese marcador mediante un hook del kernel, /etc/kernel/postinst.d/unattended-upgrades, que se ejecuta cuando se instala un paquete del kernel. Una actualización de una biblioteca no lo activa. No dé por hecho que el archivo existe. Compruébelo después de la próxima actualización del kernel:

ls -l /var/run/reboot-required /var/run/reboot-required.pkgs
uname -r
dpkg -l 'linux-image-*' | grep '^ii'

Si el archivo nunca aparece en el equipo, Automatic-Reboot "true" nunca se ejecuta. Puede pasar meses creyendo que reinicia el sistema para aplicar actualizaciones del kernel mientras sigue ejecutando el kernel antiguo. Ejecute uname -r contra el paquete linux-image instalado más recientemente para confirmarlo.

Automatic-Reboot-Time programa el reinicio para esa hora, en lugar de hacerlo inmediatamente. Si Automatic-Reboot-WithUsers se establece en false, el reinicio se omite mientras haya alguien conectado. En un servidor que siempre tiene una sesión abierta, esto significa que nunca se reinicia.

La decisión se refiere a lo que ocurre al volver a arrancar, no al reinicio en sí. Un servicio iniciado manualmente no vuelve a iniciarse. Un volumen cifrado que requiere una contraseña durante el arranque no se monta. Dos equipos que dependen uno del otro pueden arrancar en el orden incorrecto. Active el reinicio automático en un servidor web sin estado cuya interrupción durante un minuto a las 02:00 sea aceptable. Déjelo desactivado cuando se necesite la intervención de una persona y configure alertas para el archivo marcador, de modo que alguien elija el momento. Entre ambas opciones está needrestart, que reinicia los servicios que todavía usan una biblioteca actualizada y, por tanto, cubre todos los casos excepto el kernel. Su modo predeterminado solicita confirmación antes de reiniciar. Lea /etc/needrestart/needrestart.conf antes de usarlo en una ejecución desatendida.

¿Funciona igual en testing y unstable?

Todo lo anterior describe Debian stable, donde las correcciones de seguridad llegan desde un archivo independiente con su propia etiqueta. Esa estructura es la que permite expresar una configuración de «solo actualizaciones de seguridad». Las otras suites están construidas de otra forma, por lo que una configuración copiada de un servidor stable coincide menos de lo que espera su autor. Además, las actualizaciones automáticas en una suite de desarrollo implican cambios importantes de versión sin intervención. Aceptar eso es una decisión diferente. Si está valorando esa opción, usar Debian stable, testing o unstable en un servidor explica qué ofrece cada una. En el entorno de Red Hat, la misma tarea utiliza otra herramienta y otra terminología, y dnf-automatic en Rocky Linux y AlmaLinux la realiza con su propio temporizador y archivo de configuración.

Las actualizaciones automáticas reducen el intervalo entre la publicación de una corrección y su instalación. No indican qué sigue expuesto, por lo que debe combinarlas con una comprobación de CVE conocidas en el servidor. CVE significa common vulnerabilities and exposures y es el identificador público con el que se registra una corrección.

La comprobación de cinco minutos

  1. apt-config dump APT::Periodic muestra ambas claves con un valor distinto de cero.
  2. systemctl list-timers 'apt-daily*' muestra una hora de NEXT para ambos temporizadores.
  3. sudo unattended-upgrade --dry-run --debug muestra orígenes permitidos que incluyen el archivo de seguridad correspondiente a su nombre en clave.
  4. sudo systemctl start apt-daily-upgrade.service termina y la marca de tiempo de /var/log/unattended-upgrades/unattended-upgrades.log se actualiza.
  5. Una semana después, ese mismo registro incluye los paquetes que instaló.

Superar las cuatro primeras comprobaciones significa que la máquina está configurada. Superar la quinta significa que funciona.

FAQ

¿Por qué Debian instala unattended-upgrades, pero lo deja desactivado?

El paquete formula una pregunta de debconf, unattended-upgrades/enable_auto_updates, y escribe /etc/apt/apt.conf.d/20auto-upgrades a partir de la respuesta. El instalador de Debian almacena false para esa pregunta, por lo que, cuando el paquete llega como parte de una tarea o como dependencia, queda configurado para no hacer nada. Ejecute sudo debconf-show unattended-upgrades para ver la respuesta almacenada y, después, sudo dpkg-reconfigure --priority=low unattended-upgrades para cambiarla. La pregunta tiene prioridad baja, por lo que una instalación normal nunca la muestra. Sin embargo, dpkg-reconfigure muestra de forma predeterminada las preguntas de prioridad baja, así que aparece aquí incluso sin la opción.

¿Cómo pruebo unattended-upgrades sin esperar al temporizador?

Ejecute sudo unattended-upgrade --dry-run --debug. Muestra los orígenes que aceptará, una línea Checking: por cada paquete actualizable con el registro de origen de ese paquete adjunto, y la lista que instalaría, sin instalar nada. Para probar el flujo real, ejecute sudo systemctl start apt-daily-upgrade.service y, después, consulte journalctl -u apt-daily-upgrade.service --since -1h junto con /var/log/unattended-upgrades/unattended-upgrades.log.

¿unattended-upgrades instala también las actualizaciones normales además de las correcciones de seguridad?

Sólo si un patrón lo indica. Una actualización de paquete se instala cuando el origen del que procede coincide con una entrada de Unattended-Upgrade::Origins-Pattern o del antiguo Unattended-Upgrade::Allowed-Origins. El archivo de seguridad, la suite stable-updates y cualquier repositorio que haya añadido usted mismo son entradas independientes. Muestre apt-config dump Unattended-Upgrade::Origins-Pattern y apt-config dump Unattended-Upgrade::Allowed-Origins en su propio equipo y compárelos con grep -H -E '^(Origin|Label|Suite|Codename):' /var/lib/apt/lists/*Release. Además, nunca cambia el sistema de una versión de Debian a otra.

¿Por qué la actualización no se ejecuta a la hora establecida en el temporizador?

apt-daily-upgrade.timer establece RandomizedDelaySec sobre OnCalendar, por lo que systemd elige un momento aleatorio dentro de esa ventana en lugar de ejecutarse a la hora del calendario. Esto distribuye la carga entre todos los equipos Debian que apuntan a los mismos mirrors. systemctl list-timers 'apt-daily*' muestra el momento que eligió realmente. Para cambiar la ventana, ejecute sudo systemctl edit apt-daily-upgrade.timer y proporcione una línea OnCalendar= vacía seguida de su propio valor.

¿Debo activar el reinicio automático para las actualizaciones de seguridad?

Sólo cuando sea seguro reiniciar sin planificación. Unattended-Upgrade::Automatic-Reboot "true" reinicia sin pedir confirmación siempre que exista /var/run/reboot-required después de una ejecución. En Debian 12 y 13, ese marcador lo crea un hook del kernel incluido en el paquete unattended-upgrades, por lo que aparece después de actualizar el kernel, pero no después de actualizar bibliotecas. Confirme que el archivo aparece en su equipo después de actualizar el kernel antes de confiar en esta configuración. En un equipo que necesita una contraseña al arrancar o que ejecuta servicios iniciados manualmente por alguien, déjelo en false y genere una alerta cuando aparezca el archivo marcador para que una persona elija el momento.