- El empaquetado con RPM se basa en archivos .spec bien estructurados, dependencias claras y uso correcto de macros de compilación.
- Herramientas como rpmbuild, mock y rpmlint permiten construir paquetes limpios, reproducibles y validados para distintas distribuciones y arquitecturas.
- La firma GPG de paquetes y metadatos, junto con createrepo, es esencial para crear repositorios propios confiables y fáciles de consumir.

Si trabajas con distribuciones basadas en RPM, tarde o temprano vas a necesitar aprender a crear, firmar y distribuir paquetes .rpm de forma seria. No solo para empaquetar tu propio software, sino también para mantener entornos corporativos donde controlar qué se instala y desde dónde es prácticamente obligatorio.
En este artículo vamos a ver, con bastante profundidad, cómo construir paquetes RPM, firmarlos con GPG y publicarlos en un repositorio propio, además de repasar el uso del comando rpm y de los gestores de alto nivel (yum, dnf y zypper). El objetivo es que salgas con una visión completa: desde la teoría del archivo .spec hasta el flujo de trabajo profesional con herramientas como mock y createrepo.
Qué es un paquete RPM y por qué sigue siendo tan importante
Un paquete RPM es mucho más que un simple fichero .rpm: es un contenedor con binarios, archivos de configuración, metadatos y scripts de instalación que el gestor RPM sabe interpretar. Nació como Red Hat Package Manager, pero hoy en día es un proyecto independiente bajo licencia GPL, utilizado en RHEL, Fedora, AlmaLinux, Rocky Linux, openSUSE, ALDOS y hasta en otros sistemas como AIX.
Este formato permite instalar, actualizar, verificar y desinstalar software de forma consistente. Incluye información sobre dependencias, licencias, arquitectura, archivos instalados, scripts de pre/post instalación y verificación de integridad mediante firmas GPG.
La pieza central del empaquetado es el archivo de especificación .spec, que actúa como receta para rpmbuild: define cómo desempaquetar las fuentes, aplicar parches, compilar, instalar en un árbol temporal y finalmente generar los paquetes binarios y fuente.
Comando rpm: la base de la gestión de paquetes
Aunque hoy casi siempre usamos yum, dnf o zypper, el comando rpm sigue siendo la herramienta de bajo nivel para gestionar paquetes en sistemas basados en Red Hat y derivados. Trabaja directamente con ficheros .rpm e información local instalada en la base de datos de paquetes.
Antes de usarlo, debes tener instalado el sistema RPM; además, en distribuciones Debian conviene no mezclar rpm con dpkg/apt en el mismo entorno, porque pueden aparecer conflictos de dependencias difíciles de resolver.
La estructura básica de uso es muy sencilla: rpm paquete.rpm. Sobre esta forma general se apoyan un buen número de banderas que indican si quieres instalar, borrar, consultar o verificar paquetes.
Entre las opciones más habituales del comando rpm destacan: -i/–install para instalar, -e/–erase para eliminar, -U/–upgrade para actualizar, -q/–query para consultar y -V/–verify para comprobar integridad. Todas ellas se pueden combinar con modificadores como -v (salida detallada) o -h (barra de progreso).
Operaciones básicas con rpm: instalar, consultar y verificar
Para instalar un paquete manualmente bastaría con ejecutar rpm -ivh nombre-paquete.rpm, donde -i instala, -v muestra más información y -h dibuja una barra de progreso. Esta instalación no resuelve automáticamente dependencias: si faltan paquetes, rpm lo indicará y tendrás que instalarlos tú mismo.
Si ya tienes una versión anterior, puedes actualizarla con rpm -Uvh paquete.rpm. Esta opción instala la nueva versión y elimina la antigua. En cambio, rpm -F solo actualizará el paquete si ya está instalado; si no existe en el sistema, no lo añadirá.
La desinstalación se hace con rpm -e nombre-paquete. Si algún otro paquete depende de ese software, rpm te avisará y tendrás que resolverlo manualmente, ya sea eliminando los paquetes dependientes o dejando el paquete instalado.
Para inspeccionar qué hay en tu sistema, se usa rpm -qa para listar todos los paquetes instalados. Comandos como rpm -qi nombre-paquete muestran información detallada (versión, arquitectura, fecha de instalación, resumen, empaquetador), mientras que rpm -ql nombre-paquete indica la lista de ficheros que instala un paquete concreto.
También es posible consultar paquetes que aún no se han instalado: rpm -qip archivo.rpm muestra la información del paquete y rpm -qlp archivo.rpm lista el contenido del fichero .rpm sin necesidad de instalarlo.
Si quieres averiguar qué paquete es el propietario de un archivo concreto del sistema, usas rpm -qf /ruta/al/fichero. Esto es muy útil cuando ves un fichero en /usr/bin o /etc y necesitas saber de qué paquete proviene.
Yum, dnf y zypper: gestores de alto nivel para RPM
Trabajar solo con rpm es viable, pero para el día a día es muchísimo más cómodo usar gestores de paquetes que resuelvan dependencias de forma automática. En el ecosistema RPM tenemos principalmente yum, dnf y zypper.
yum (Yellowdog Updater Modified) fue durante años la herramienta de referencia en Red Hat, CentOS y derivados. Permite buscar paquetes, instalarlos, actualizarlos, desinstalarlos y hacer operaciones con repositorios de forma más amigable que rpm.
Con yum puedes buscar software con yum search PATRON, instalar con yum install nombre-paquete, actualizar con yum update nombre-paquete (o todo el sistema si no pones nombre), y eliminar con yum remove nombre-paquete.
Para resolver dependencias, yum dispone de yum whatprovides archivo, que te dice qué paquete incluye un determinado fichero o biblioteca. Es perfecto cuando rpm te avisa de que falta libgimpui-2.0.so.0 y no tienes ni idea de qué paquete instalar.
La configuración de los repositorios de yum se encuentra en /etc/yum.repos.d/, donde cada fichero .repo describe un repositorio. Puedes listar los repos activos con yum repolist all y modificarlos con la herramienta yum-config-manager para habilitar, deshabilitar o añadir nuevas fuentes de software.
dnf es el sucesor moderno de yum en Fedora y distribuciones recientes. Mantiene una sintaxis muy similar (dnf install, dnf search, dnf upgrade, dnf remove) pero con un motor más eficiente y mejor manejo de dependencias. Además incluye comandos útiles como dnf repoquery -l paquete para listar archivos de un paquete, o dnf provides fichero para saber quién ofrece un archivo concreto.
Los repositorios de dnf también usan ficheros .repo en /etc/yum.repos.d/, y se gestionan con dnf config-manager para añadir, habilitar o deshabilitar repos con comodidad. La sintaxis es muy parecida a la de yum, lo que facilita migrar de una herramienta a otra.
zypper es la herramienta equivalente en SUSE y openSUSE. Permite actualizar índices de paquetes con zypper refresh, buscar con zypper search, instalar con zypper install y actualizar con zypper update, igual que en otros gestores.
Una ventaja de zypper es que puede instalar .rpm locales directamente (zypper in /ruta/archivo.rpm) y resolver las dependencias tirando de los repos configurados. Además, comandos como zypper se -i muestran solo paquetes instalados, y zypper info paquete detalla metadatos, estado, repositorio de origen y descripción.
Para la gestión de repositorios, se usa zypper repos para listar, y zypper modifyrepo con -e o -d para activar o desactivar cada repo, controlando también si quieres que refresquen automáticamente con -f o -F. La estructura interna de los .repo es muy parecida a la de yum/dnf.
Preparar el entorno de construcción de paquetes RPM
Antes de construir tu primer .rpm necesitas un entorno ordenado y unas cuantas herramientas preinstaladas. Es clave tener rpm-build, rpm-sign, compilador y macros de la distribución adecuadamente configurados.
En sistemas como ALDOS que usan yum, puedes instalar todo lo básico con yum -y install rpm-build rpm-sign gnupg2 gcc make aldos-rpm-macros. En Fedora, RHEL, AlmaLinux o Rocky Linux, harás algo similar usando dnf para instalar rpm-build, rpm-sign, gnupg2, gcc, make y redhat-rpm-macros.
Para una experiencia más completa, conviene añadir paquetes como cmake-rpm-macros, python-srpm-macros, meson, cmake, rpmlint, desktop-file-utils y rpmdevtools. En particular, rpmlint te ayuda mucho a detectar errores típicos en archivos .spec y paquetes generados.
La estructura estándar de trabajo la crea la utilidad rpmdev-setuptree (incluida en rpmdevtools), que monta el árbol ~/rpmbuild con subdirectorios BUILD, BUILDROOT, RPMS, SOURCES, SPECS y SRPMS. Si usas Debian, deberás generar esa estructura manualmente con mkdir -p ~/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}.
Lo recomendable es colocar siempre las fuentes, parches y recursos en SOURCES/ y los archivos .spec en SPECS/. Los paquetes binarios acabados aparecerán en RPMS/ y los .src.rpm en SRPMS/ al terminar la construcción.
Anatomía de un archivo .spec moderno
El fichero .spec es un guion declarativo con varias secciones que rpmbuild ejecuta en orden. La parte inicial es la cabecera, donde defines los metadatos básicos del paquete: Name, Version, Release y Summary, además de licencias y fuentes.
Por ejemplo, una cabecera típica incluiría campos como License con identificadores SPDX, URL del proyecto y Source0 apuntando al tarball oficial del código fuente. Conviene usar macros como %{name} y %{version} para facilitar el mantenimiento cuando cambies de versión.
Otra parte importante es la gestión de arquitecturas. Si tu software solo es soportado en x86_64 y arm64, puedes limitarlo con ExclusiveArch: x86_64 arm64 o bien excluir arquitecturas de 32 bits con directivas como ExcludeArch: %{ix86}.
Los parches se declaran con directivas Patch0, Patch1, etc., apuntando a ficheros ubicados en SOURCES/. Estos parches se aplicarán posteriormente en la sección %prep, donde hoy en día se suele usar %autosetup -p1 para desempaquetar las fuentes y aplicar parches automáticamente.
En la parte de dependencias, BuildRequires lista todos los paquetes necesarios para compilar el proyecto: compiladores, bibliotecas de desarrollo, macros específicas, herramientas de construcción como Meson o CMake, y utilidades de validación. Omitir algo aquí hará que la construcción falle.
Las dependencias de ejecución se indican con Requires, Recommends y Suggests. Requires marca lo estrictamente necesario para que el paquete funcione, mientras que Recommends/Suggests son más blandas y requieren RPM 4.12 o superior. Si necesitas compatibilidad con sistemas más antiguos como ALDOS (RPM 4.11.3), tendrás que usar condicionales en el .spec para no romper la construcción.
También puedes definir relaciones entre paquetes con Conflicts, Obsoletes y Provides. Conflicts impide instalar dos paquetes incompatibles a la vez; Obsoletes indica que uno sustituye a otro (útil en cambios de nombre); Provides permite declarar capacidades virtuales para que otros paquetes puedan depender de una funcionalidad genérica, no de un nombre concreto.
La sección %description alberga una descripción extendida del paquete, donde se recomienda mantener líneas razonablemente cortas para verse bien en terminales. Es posible definir descripciones en varios idiomas usando %description -l es para español, por ejemplo.
Sistemas de construcción: Meson, Autotools y CMake
En los .spec modernos es frecuente apoyarse en macros específicas para integrar Meson, Autotools o CMake sin tener que escribir a mano comandos de compilación largos. Esto simplifica muchísimo las secciones %build, %install y %check.
Con Meson, que es el sistema recomendado para proyectos nuevos, puedes usar %meson para configurar, %meson_build para compilar y %meson_install para instalar en el BUILDROOT. Las opciones se pasan directamente a Meson (por ejemplo -Dopcion=true, -Ddocs=enabled/disabled).
Para proyectos antiguos basados en Autotools, se emplean macros como %configure (que lanza el script configure con rutas correctas) y %make_build / %make_install, que se encargan de compilar e instalar respetando el entorno de construcción de rpmbuild.
Con CMake, muy popular en C++ y proyectos de escritorio, se usan macros equivalentes: %cmake, %cmake_build y %cmake_install. De esta forma, el .spec permanece limpio y legible, y no necesitas reescribir comandos largos en cada paquete.
Adicionalmente, hay macros de ayuda como %bcond_with/%bcond_without para definir opciones opcionales de compilación (por ejemplo, documentación) que se activan o desactivan en tiempo de construcción con flags como –with docs.
Subpaquetes, lista de ficheros y macros útiles
En muchos casos interesa dividir un proyecto grande en varios paquetes: bibliotecas, cabeceras de desarrollo, documentación, utilidades de línea de comandos, etc. Esto se hace con la directiva %package, que define subpaquetes con su propio nombre, resumen y descripción.
Cada subpaquete necesita su propia sección %description y, sobre todo, su propia sección %files, donde enumeras exactamente los archivos que forma parte de ese subpaquete. Lo que no esté listado en %files no se incluirá en el paquete RPM final.
Dentro de %files se usan macros especiales como %license para marcar archivos de licencia, %doc para documentación, %config(noreplace) para ficheros de configuración, %dir para incluir directorios vacíos, %ghost para archivos creados en tiempo de ejecución y %attr para definir permisos, propietario y grupo.
Siguiendo este esquema, puedes tener un paquete principal con ejecutables y archivos de escritorio, un subpaquete libproyecto con la biblioteca compartida y otro libproyecto-devel con cabeceras y archivos .pc de pkg-config. Así permites que el usuario instale solo lo que realmente necesita.
Scripts de mantenimiento como %post, %postun o %posttrans permiten ejecutar comandos tras la instalación o desinstalación, por ejemplo actualizar cachés de iconos con gtk-update-icon-cache o refrescar la tabla de bibliotecas con ldconfig. En sistemas modernos algunos de estos pasos son automáticos, por lo que a menudo se incluyen bajo condicionales para no duplicar tareas.
Flujo de construcción con rpmbuild y mock
Cuando ya tienes el .spec y las fuentes en su sitio, el flujo básico con rpmbuild es sencillo: rpmbuild -ba fichero.spec construye el paquete fuente y los binarios en un solo paso. Pero también puedes ejecutar fases parciales.
Por ejemplo, rpmbuild -bp fichero.spec ejecuta la preparación (%prep) y deja las fuentes desempaquetadas y parcheadas en BUILD/, útil para depurar problemas de parches. rpmbuild -bi compila e instala en BUILDROOT sin crear los .rpm, ideal para verificar la fase de instalación.
Para generar solo el paquete fuente .src.rpm se utiliza rpmbuild -bs fichero.spec, mientras que -ba es la opción que la mayoría de empaquetadores usa en CI o scripts, ya que produce todo de una sola vez.
Sin embargo, compilar en tu propio sistema tiene un peligro claro: puedes introducir dependencias ocultas porque tu máquina tiene paquetes extra que no se declararon en BuildRequires. Para evitar esto se usa mock, una herramienta que crea entornos de construcción limpios dentro de chroots.
Con mock defines perfiles para cada distribución/arquitectura (por ejemplo aldos-14-x86_64) y ejecutas comandos como mock -r perfil –rebuild paquete.src.rpm. Esto genera los RPM dentro de /var/lib/mock/perfil/result/, garantizando que solo se usan los paquetes declarados en el .spec.
En flujos de trabajo avanzados se suelen escribir scripts bash que limpian la caché de mock, construyen para varias arquitecturas, eliminan debuginfo innecesarios, mueven los paquetes a un repositorio local y regeneran los metadatos con createrepo. La clave es no dejar nunca los paquetes valiosos dentro de /var/lib/mock/*/result, porque este directorio se limpia en ejecuciones posteriores.
Crear y firmar tu propio repositorio RPM
Cuando acumulas varios paquetes propios, lo más cómodo es levantar un repositorio RPM accesible por HTTP/HTTPS y consumirlo desde tus máquinas mediante yum o dnf, igual que cualquier repo oficial.
Una forma práctica de hacerlo es organizar en tu máquina de trabajo una estructura de directorios que se parezca a la de las grandes distribuciones, por ejemplo /home/usuario/devel/repo/Fedora/15/{i386,x86_64}/{os,debug} y Fedora/15/source/SRPMS. Copias en cada carpeta los paquetes binarios y los src.rpm donde corresponda.
El siguiente paso es generar una clave GPG específica para firmar los paquetes y los metadatos del repositorio. Con gpg –gen-key creas una clave RSA de 4096 bits, le das un nombre reconocible para tu repo y después exportas la clave pública al fichero RPM-GPG-KEY-myrepo dentro del propio repositorio.
En tu usuario añades a ~/.rpmmacros las líneas %_signature gpg y %_gpg_name nombre-de-la-clave para que rpm sepa qué clave usar al firmar. A partir de aquí, puedes firmar todos los .rpm localizados en tu árbol con un find combinado con rpm –resign.
Para generar la información del repositorio se usa createrepo o createrepo_c. Lo habitual es automatizarlo con un script que recorra todas las arquitecturas, ejecute createrepo -v . en cada una y luego busque todos los repomd.xml resultantes para firmarlos con gpg –armor –detach-sign, de modo que la integridad de los metadatos también quede garantizada.
Una vez generados los metadatos, replicas el contenido al servidor web (un VPS o el servidor interno de la empresa) con rsync -avz –delete sobre SSH, y opcionalmente programas una tarea cron para mantener todo sincronizado cada cierto tiempo con la máquina de construcción.
En los clientes solo hay que crear un archivo /etc/yum.repos.d/myrepo.repo con las secciones , y , apuntando a las URLs base donde sirves los paquetes y la clave GPG pública. Con enabled y gpgcheck controlas si el repo está activo y si se exige verificación de firma.
Ejemplo práctico: un RPM sencillo (tipografías)
Para asentar conceptos, un ejemplo simple es empaquetar una colección de fuentes open source como Vremena en un .rpm ultra básico, apto para distribuciones Red Hat y derivados, aunque construido incluso desde Debian.
En Debian instalarías las herramientas mínimas con apt -y install rpm rpm2cpio y crearías el árbol ~/rpmbuild a mano; si trabajas con paquetes .deb, consulta crear y firmar paquetes .deb. En Red Hat, además, instalarías rpmdevtools y ejecutarías rpmdev-setuptree para que te genere la estructura.
Después crearías un archivo .spec llamado vremena-font.spec, ya sea desde cero en Debian o usando rpmdev-newspec rpmbuild/SPECS/vremena-font.spec en Red Hat para generar una plantilla. En ese spec defines Name, Version, Release, Summary, License y una sección %description que cuente qué fuentes incluye el paquete.
En %install crearías el directorio de destino dentro de %{buildroot}, por ejemplo mkdir -p %{buildroot}/usr/share/fonts/vremena-serif/, y copiarías allí los .otf. Es importante usar rutas relativas a %{buildroot} porque rpmbuild trabaja en un entorno simulado (chroot) antes de empaquetar.
La sección %post ejecutaría fc-cache /usr/share/fonts/ para que el sistema regenere la caché de fuentes y las nuevas tipografías queden disponibles al instante. En %files enumeras los .otf instalados, y en %changelog documentas la creación de la primera versión del paquete.
Con todo listo, rpmbuild -ba rpmbuild/SPECS/vremena-font.spec creará el .rpm en RPMS/x86_64 o la arquitectura que corresponda. En un sistema Red Hat bastaría con instalarlo con rpm -i vremena-font-0.1-1.x86_64.rpm para tener las fuentes operativas.
Firma de paquetes con GnuPG y verificación
En entornos profesionales es imprescindible que los paquetes estén firmados criptográficamente con GPG para asegurar que no han sido manipulados y que provienen de la fuente esperada. Además, muchos repositorios se configuran con gpgcheck=1 para rechazar paquetes sin firma válida.
Tras tener tu clave GPG lista y configurada en ~/.rpmmacros, puedes firmar todos los .rpm que generas con rpm –addsign ~/rpmbuild/RPMS/*/*.rpm ~/rpmbuild/SRPMS/*.rpm. Esto añade la firma a cada paquete aprovechando la clave privada.
Los clientes pueden comprobar la autenticidad con rpm -K paquete.rpm, que mostrará si la firma es correcta y si la integridad del fichero se mantiene. Si la clave pública no está importada en el sistema, habrá que añadirla primero con gpg –import o el mecanismo equivalente específico de la distribución.
En flujos donde se publica un repositorio propio, suele distribuirse la clave pública como un fichero RPM-GPG-KEY accesible vía HTTP y referenciado en los .repo para que los clientes puedan importar la clave fácilmente antes de consumir el repositorio.
En definitiva, dominar la creación de paquetes RPM, su firma GPG, la construcción aislada con mock y el montaje de repositorios propios te da un control enorme sobre cómo se instala y actualiza el software en tus sistemas Linux, y convierte lo que antes era un caos de binarios sueltos en un flujo ordenado, reproducible y seguro.
Redactor apasionado del mundo de los bytes y la tecnología en general. Me encanta compartir mis conocimientos a través de la escritura, y eso es lo que haré en este blog, mostrarte todo lo más interesante sobre gadgets, software, hardware, tendencias tecnológicas, y más. Mi objetivo es ayudarte a navegar por el mundo digital de forma sencilla y entretenida.
