Administración de Linux
Gestión de paquetes en Linux: apt, dpkg, dnf, rpm, repositorios y firmas
Principiante11 min de lecturaActualizado
Esta página se tradujo del inglés con ayuda de IA y se cotejó con el original. Leer la versión en inglés
Un gestor de paquetes marca la diferencia entre un servidor cuyo estado puedes entender y un montón de binarios copiados a mano. Esta guía explica qué es realmente un paquete, por qué las herramientas de Debian y de RHEL difieren en vocabulario pero no en la idea, cómo la firma de repositorios establece la confianza y cómo retener, revertir e inspeccionar paquetes. Termina con los casos en los que no existe ningún paquete y tienes que compilar o integrar el software por tu cuenta.
Lo que aprenderás
- Describir el contenido de un .deb o un .rpm y qué cambia en el disco al instalarlo
- Usar apt y dnf con soltura para buscar, instalar, actualizar, eliminar y limpiar
- Añadir un repositorio de terceros con una clave de firma verificada en lugar de un curl a ciegas hacia un shell
- Diagnosticar un conflicto de dependencias y retener, fijar o revertir un paquete de forma deliberada
- Elegir entre un paquete de la distribución, el gestor de paquetes del lenguaje y la compilación desde el código fuente
Un gestor de paquetes hace tres cosas que copiar archivos de un lado a otro no puede hacer: registra con exactitud qué archivos pertenecen a qué software, sabe qué necesita cada pieza para funcionar y puede verificar que lo que has descargado es lo que publicaron los mantenedores. Todo lo demás —los comandos, las cachés, los formatos de repositorio— existe para servir a esas tres propiedades.
Dominan dos familias de herramientas. Debian, Ubuntu y sus derivadas usan archivos .deb, con dpkg por debajo y apt por encima. Fedora, RHEL, Rocky Linux, AlmaLinux y SUSE usan archivos .rpm, con rpm por debajo y dnf (o zypper) por encima. Los vocabularios difieren, los conceptos no, así que esta guía las presenta en paralelo y señala dónde el comportamiento diverge de verdad.
Qué hay dentro de un paquete
Un paquete es un archivo comprimido más metadatos. El comprimido es el árbol de archivos que hay que desempaquetar, organizado según las convenciones descritas en la jerarquía del sistema de archivos: los binarios en /usr/bin, las bibliotecas en /usr/lib, la configuración en /etc, la documentación y las páginas de manual en /usr/share, los archivos de unidad en /usr/lib/systemd/system. Lo interesante son los metadatos:
- Identidad — nombre, versión, número de release, arquitectura (
amd64,arm64,noarch). - Dependencias — lo que debe estar presente para que funcione, normalmente expresado mediante capacidades virtuales como
libssl3ohttpd-mmnen lugar de nombres de paquete, para que distintas alternativas puedan satisfacerlas. - Conflicts, provides, replaces — cómo se relaciona con otros paquetes.
- Scripts del mantenedor — pequeños fragmentos de shell que se ejecutan antes y después de la instalación o la eliminación, y que crean cuentas de sistema, generan claves, recargan systemd o reinician un servicio.
- Lista de archivos de configuración — archivos que el gestor nunca debe sobrescribir en silencio, porque puede que los hayas editado.
- Sumas de verificación de cada archivo instalado.
Puedes ver el contenido sin instalar nada:
dpkg --info ./nginx_1.26.0-1_amd64.deb # metadata
dpkg --contents ./nginx_1.26.0-1_amd64.deb # file list
rpm -qip ./nginx-1.26.0-1.el9.x86_64.rpm # metadata
rpm -qlp ./nginx-1.26.0-1.el9.x86_64.rpm # file list
Esa lista de archivos de configuración explica un comportamiento que desconcierta a quien empieza. Cuando una actualización trae un valor por defecto distinto y tú has editado el archivo, Debian te pregunta si quieres conservarlo, sustituirlo o ver las diferencias, mientras que RPM instala la versión nueva junto a la tuya como *.rpmnew (o guarda la tuya como *.rpmsave). Después de cualquier actualización grande, merece la pena ejecutar find /etc -name '*.rpmnew' -o -name '*.dpkg-dist'.
Las mismas operaciones en dos dialectos
| Tarea | Debian / Ubuntu | Familia RHEL |
|---|---|---|
| Refrescar los metadatos | sudo apt update | automático; sudo dnf makecache para forzarlo |
| Instalar | sudo apt install nginx | sudo dnf install nginx |
| Eliminar conservando la configuración | sudo apt remove nginx | sudo dnf remove nginx |
| Eliminar también la configuración | sudo apt purge nginx | sin equivalente exacto |
| Actualizarlo todo | sudo apt upgrade / full-upgrade | sudo dnf upgrade |
| Buscar | apt search keyword | dnf search keyword |
| Ver detalles | apt show nginx | dnf info nginx |
| Qué paquete es dueño de un archivo | dpkg -S /usr/sbin/nginx | rpm -qf /usr/sbin/nginx |
| Listar los archivos de un paquete | dpkg -L nginx | rpm -ql nginx |
| Comprobar si está instalado | dpkg -l nginx | rpm -q nginx |
| Instalar un archivo local | sudo apt install ./pkg.deb | sudo dnf install ./pkg.rpm |
| Limpiar la caché | sudo apt clean | sudo dnf clean all |
| Eliminar dependencias sin uso | sudo apt autoremove | sudo dnf autoremove |
Hay tres puntos en los que la diferencia es real y no cosmética. Primero, apt update y apt upgrade son pasos separados, y olvidar el primero es con diferencia la causa más habitual del «package not found»; dnf refresca los metadatos según su propio calendario. Segundo, apt upgrade se niega a eliminar ningún paquete, así que retendrá cualquier actualización que lo requiera: apt full-upgrade (antes dist-upgrade) es la variante que sí puede eliminar cosas y la que necesitas para cambiar de versión de la distribución. Tercero, dnf history registra cada transacción y dnf history undo 42 deshace una, algo para lo que apt no tiene un equivalente directo.
$ dnf history list | head -4
ID | Command line | Date and time | Action(s) | Altered
------------------------------------------------------------------------------
42 | install nginx php-fpm | 2026-09-05 14:02 | Install | 31
41 | upgrade | 2026-09-01 03:11 | Upgrade | 118
Instalar siempre los archivos locales a través del front end (apt install ./pkg.deb) en lugar de con dpkg -i tiene su importancia: el front end descarga las dependencias, mientras que dpkg te deja con un paquete a medio configurar y un apt --fix-broken install pendiente.
Repositorios y la cadena de confianza
Un repositorio es un directorio HTTP que contiene paquetes y un índice. El índice está firmado con la clave de un mantenedor, y en él figura la suma de verificación de cada paquete. Tu máquina guarda las claves públicas correspondientes, así que la cadena funciona así: la clave de confianza verifica la firma del índice, el índice contiene la suma de verificación y la suma de verificación valida el paquete descargado. Si se rompe cualquier eslabón, el gestor de paquetes se niega a instalar.
En Debian y Ubuntu, las fuentes están en /etc/apt/sources.list.d/ y las claves en /etc/apt/keyrings/. El patrón actual y correcto vincula una clave a una fuente con signed-by, en lugar de añadir la clave a un conjunto global de confianza desde el que podría firmar cualquier cosa:
sudo install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://download.example.com/gpg.key \
| sudo gpg --dearmor -o /etc/apt/keyrings/example.gpg
sudo chmod 0644 /etc/apt/keyrings/example.gpg
echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/example.gpg] \
https://download.example.com/debian bookworm main" \
| sudo tee /etc/apt/sources.list.d/example.list
sudo apt update
El obsoleto apt-key add escribe en un anillo de claves global y ya no existe en las versiones actuales; si las instrucciones de un proveedor todavía te piden usarlo, están desactualizadas. Las versiones recientes también aceptan un único archivo .sources en formato deb822, más fácil de leer y que permite incluir la clave directamente.
El equivalente en la familia RHEL es un archivo .repo en /etc/yum.repos.d/:
[example]
name=Example packages
baseurl=https://download.example.com/el9/$basearch/
enabled=1
gpgcheck=1
gpgkey=https://download.example.com/RPM-GPG-KEY-example
La línea que importa es gpgcheck=1. Desactivarla para que una instalación salga adelante es justo el camino por el que un mirror comprometido o corrupto acaba en producción. Si una clave no está disponible de verdad, obtenla del proveedor por un canal de confianza e impórtala con rpm --import, en lugar de desactivar la comprobación.
Como los nombres de repositorio del tipo bookworm-updates y el9 están atados a una versión concreta de la distribución, mezclar repositorios de versiones distintas produce un sistema que ningún mantenedor ha probado nunca. Si necesitas un paquete más reciente, busca un repositorio oficial de backports (bookworm-backports) o un module stream (dnf module list postgresql) antes de añadir una fuente ajena.
La resolución de dependencias y el lío que puede montar
El trabajo del resolvedor es encontrar un conjunto de versiones de paquetes que satisfaga todos los requisitos declarados. Casi siempre es invisible. Se hace visible en unas pocas situaciones reconocibles.
Actualizaciones retenidas. apt upgrade informa de que «the following packages have been kept back» cuando la nueva versión necesita instalar un paquete adicional o eliminar uno existente. Ejecuta apt full-upgrade, o instala ese paquete concreto por su nombre y lee lo que propone.
Estado roto o a medio configurar. Suele ser el resultado de un dpkg -i sin dependencias o de una actualización interrumpida. Para recuperarte:
sudo apt --fix-broken install
sudo dpkg --configure -a
sudo apt install -f
Versiones en conflicto procedentes de dos repositorios. Comprueba de dónde viene una versión candidata antes de instalarla:
$ apt policy nginx
nginx:
Installed: 1.22.1-9
Candidate: 1.26.0-1
Version table:
1.26.0-1 500
500 https://download.example.com/debian bookworm/main amd64 Packages
*** 1.22.1-9 500
500 http://deb.debian.org/debian bookworm/main amd64 Packages
El 500 es una prioridad; apt-cache policy y dnf repoquery --qf '%{name} %{version} %{reponame}' son las herramientas para responder a «¿por qué me ha llegado esa versión?».
Simular antes de comprometerse. Ambos front ends pueden mostrar el plan sin ejecutarlo, algo que merece la pena en cualquier servidor que importe:
apt-get install --dry-run some-package
dnf install --assumeno some-package
apt list --upgradable
dnf check-update
Retener, fijar y revertir versiones
A veces necesitas una versión concreta: una base de datos que debe coincidir con una aplicación o un driver que ha sufrido una regresión en una versión más nueva.
sudo apt install nginx=1.26.0-1 # exact version
sudo apt-mark hold nginx # exclude from future upgrades
apt-mark showhold
sudo apt-mark unhold nginx
sudo dnf install nginx-1.26.0-1.el9
sudo dnf downgrade nginx
sudo dnf versionlock add nginx # needs the versionlock plugin
APT también permite un control más fino mediante archivos de pinning en /etc/apt/preferences.d/, que asignan un número de prioridad a un repositorio o a un patrón de paquetes para que, por ejemplo, un paquete venga de backports mientras todo lo demás sigue en stable:
Package: postgresql*
Pin: release n=bookworm-backports
Pin-Priority: 990
Cada retención y cada pin es deuda técnica con un coste en seguridad, porque excluye el paquete de las actualizaciones de seguridad. Anota el motivo y una fecha de caducidad en un comentario, y revísalos.
¿Qué ha puesto realmente ese paquete en mi sistema?
Las consultas inversas son la manera de entender un servidor heredado.
dpkg -S /usr/sbin/nginx # which package owns this file
dpkg -L nginx | grep '^/etc' # its configuration files
dpkg --verify nginx # report files that differ from the package
apt-mark showmanual # packages you asked for, not pulled in
zcat /var/log/apt/history.log*.gz | less # what was installed and when
rpm -qf /usr/sbin/nginx
rpm -ql nginx
rpm -V nginx # verification: size, mode, checksum, owner
rpm -q --changelog nginx | head -30
rpm -qa --last | head # recently installed
dpkg --verify y rpm -V comparan cada archivo instalado con las sumas de verificación registradas al instalarlo. Una línea de salida como S.5....T. c /etc/nginx/nginx.conf indica que el tamaño, la suma de verificación y la marca de tiempo han cambiado en un archivo marcado como configuración, lo cual es de esperar. Los mismos indicadores en un binario de /usr/sbin no son normales y merecen una investigación.
Mantener una máquina parcheada
Las actualizaciones de seguridad son el trabajo rutinario más valioso en cualquier servidor. Ambas familias pueden aplicarlas sin que haya una persona delante.
# Debian / Ubuntu
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
sudo unattended-upgrade --dry-run --debug
# RHEL family
sudo dnf install dnf-automatic
sudo systemctl enable --now dnf-automatic.timer
sudo dnf updateinfo list security
Configura la automatización para que aplique solo las actualizaciones de seguridad y registre lo que ha hecho. Los reinicios son lo que la gente olvida: un OpenSSL parcheado no sirve de nada a un proceso que sigue ejecutando la biblioteca antigua. needrestart en Debian y needs-restarting -r en RHEL indican qué servicios (o si la máquina entera) hay que reiniciar. Los reinicios automáticos deben seguir un calendario que tú controles, no ocurrir a las 03:00 por defecto.
Cuando no hay paquete
De vez en cuando, el software que necesitas no está empaquetado para tu distribución, o la versión empaquetada es demasiado antigua. Compilar desde el código fuente sigue un patrón muy conocido:
sudo apt install build-essential pkg-config libpcre2-dev libssl-dev zlib1g-dev
curl -fLO https://example.org/releases/widget-3.2.1.tar.gz
curl -fLO https://example.org/releases/widget-3.2.1.tar.gz.sha256
sha256sum -c widget-3.2.1.tar.gz.sha256
tar -xzf widget-3.2.1.tar.gz && cd widget-3.2.1
./configure --prefix=/usr/local
make -j"$(nproc)"
sudo make install
Instala en /usr/local (el --prefix por defecto precisamente por este motivo) o en /opt/widget-3.2.1, nunca encima del /usr de la distribución. Verifica la suma de verificación o la firma antes de desempaquetar, deja apuntadas en algún sitio las dependencias de compilación y recuerda que acabas de asumir la responsabilidad de seguir tú mismo los avisos de seguridad de ese proyecto: nadie te avisará. checkinstall puede envolver un make install en un .deb rudimentario para que, al menos, quede registrada la lista de archivos.
Snap, Flatpak y los ecosistemas de los lenguajes
Dos formatos más recientes empaquetan una aplicación junto con sus dependencias. Snap (Ubuntu) y Flatpak (multidistribución, orientado al escritorio) aíslan la aplicación de las bibliotecas del sistema, lo que resuelve los conflictos de versiones y añade sandboxing a costa de espacio en disco, un primer arranque más lento y un segundo mecanismo de actualización que vigilar. Son una opción razonable para aplicaciones de escritorio y una mala opción por defecto para componentes de servidor, donde el paquete de la distribución se integra mejor con systemd, el registro de logs y el resto de la máquina.
Los gestores de paquetes de los lenguajes —pip, npm, Maven, Cargo, los módulos de Go— pertenecen a tu aplicación, no al sistema operativo. La regla que evita la mayoría de los disgustos: nunca hagas sudo pip install en el Python del sistema, porque las propias herramientas de la distribución dependen de él. Usa un entorno virtual, un node_modules local al proyecto o una imagen de contenedor construida como se describe en los fundamentos de Docker. Las versiones recientes de Python ya lo imponen por sí mismas y se niegan a instalar en el intérprete del sistema sin un flag explícito para saltarse la protección.
Errores comunes
- Instalar con
dpkg -iy quedarse ahí. No se descargan las dependencias; usaapt install ./file.deb. - Desactivar
gpgcheckpara saltarse un error. Acabas de eliminar la única defensa contra un mirror manipulado. - Mezclar repositorios de distintas versiones de la distribución. Funciona hasta que la actualización de una biblioteca compartida rompe medio sistema.
- Dejar una retención para siempre. Las actualizaciones de seguridad dejan de llegar sin avisar. Pon fecha a cada retención.
- Ejecutar
apt upgradeen un equipo remoto sin comprobar qué se reinicia. El propio SSH, o la pila de red, pueden estar en la lista; usa un multiplexor de terminal para que una conexión caída no aborte la transacción. sudo pip installosudo npm install -gen un servidor. Las herramientas del sistema y tu aplicación pasan a compartir un único árbol de dependencias, y actualizar una rompe la otra.- Ignorar los archivos
*.dpkg-disty*.rpmnew. Tu configuración se aleja en silencio de lo que el paquete espera ahora.
Ideas clave
- Un paquete son archivos más metadatos: dependencias, scripts del mantenedor, una lista de archivos de configuración protegidos y sumas de verificación por archivo.
apt/dpkgydnf/rpmdifieren mucho más en vocabulario que en conceptos; el front end resuelve las dependencias y la herramienta de bajo nivel se ocupa de un solo archivo comprimido.- La confianza en un repositorio descansa en un índice firmado; añade las fuentes de terceros con una clave dedicada y
signed-by, y nunca desactivesgpgcheck. apt policy,dnf repoqueryydnf historyexplican de dónde salió una versión y te permiten deshacer una transacción.- Las retenciones y los pins son excepciones deliberadas, documentadas y con fecha: suprimen las actualizaciones de seguridad mientras existan.
dpkg -S,rpm -qf,dpkg --verifyyrpm -Vconvierten un servidor desconocido en algo que puedes auditar.- Prefiere los paquetes de la distribución para los componentes del sistema, las herramientas propias del proyecto para las bibliotecas de la aplicación, y
/usr/localu/optcuando tengas que compilarlo tú mismo.
Fuentes y lecturas recomendadas
Preguntas frecuentes
- ¿Qué diferencia hay entre apt, apt-get y dpkg?
- dpkg instala y elimina un único archivo .deb y no sabe nada de repositorios ni de dependencias. apt-get y su compañero apt-cache funcionan por encima de dpkg, descargan desde los repositorios y resuelven dependencias; su salida es estable y segura para scripts. apt es un front end más reciente sobre las mismas bibliotecas, con una salida más amigable, barras de progreso y color, pensado para el uso interactivo y no para la automatización.
- ¿Es seguro ejecutar apt upgrade en un servidor de producción?
- Es seguro en el sentido de que nunca elimina paquetes, pero puede reiniciar servicios y sustituir el kernel. Lee la lista antes de confirmar, aplica primero los cambios en un entorno de staging y ten en cuenta que un kernel nuevo solo entra en vigor tras reiniciar. Comprueba si hace falta reiniciar con el marcador /var/run/reboot-required en sistemas Debian o con needs-restarting -r en equipos de la familia RHEL.
- ¿Cómo evito que un paquete se actualice?
- En Debian y Ubuntu usa apt-mark hold nombredelpaquete, que lo excluye de todas las actualizaciones hasta que ejecutes apt-mark unhold. En sistemas de la familia RHEL añade exclude=nombredelpaquete a /etc/dnf/dnf.conf, o usa dnf versionlock, del paquete python3-dnf-plugin-versionlock. En ambos casos, deja constancia de por qué existe la retención, porque una retención olvidada bloquea en silencio las actualizaciones de seguridad durante años.
- ¿Debo instalar las bibliotecas del lenguaje con apt o con pip, npm y Maven?
- Usa el paquete de la distribución para todo aquello de lo que depende el propio sistema operativo, en particular el intérprete de Python y sus módulos de sistema. Usa la herramienta del lenguaje dentro de un entorno propio del proyecto —un virtualenv, node_modules, un repositorio de Maven— para las dependencias de la aplicación, de modo que actualizar la distribución nunca rompa tu aplicación e instalar tu aplicación nunca rompa la distribución.