Compilar tu propio kernel te permite usar una versión más reciente que la de tu distribución, activar opciones que Ubuntu no incluye o reducir el kernel a los controladores que realmente usa tu hardware. En este tutorial descargarás el código fuente oficial desde kernel.org, verificarás su firma, partirás de la configuración del kernel de Ubuntu, compilarás paquetes .deb con make bindeb-pkg y los instalarás en Ubuntu 24.04 de forma que puedas volver al kernel anterior en cualquier momento.

Requisitos previos

Para seguir esta guía necesitas:

  • Un servidor con Ubuntu 24.04 LTS (x86_64), por ejemplo un VPS de CubePath.
  • Un usuario no root con privilegios sudo.
  • Al menos 4 vCPU y 8 GB de RAM para que la compilación termine en un tiempo razonable (con 2 vCPU también funciona, pero puede tardar más de una hora).
  • Unos 40 GB libres en disco: la configuración de Ubuntu activa la información de depuración y el árbol compilado ocupa mucho.
  • Acceso a la consola del servidor (por ejemplo, la consola VNC del panel de CubePath) por si el nuevo kernel no arrancara y necesitaras elegir el anterior en GRUB.

Paso 1: Instalar las herramientas de compilación

El kernel necesita un compilador, las herramientas flex y bison para los analizadores de configuración, las cabeceras de OpenSSL y libelf, y dwarves (que aporta pahole) para generar la información BTF que usan las herramientas eBPF. Para empaquetar el resultado en .deb hacen falta además debhelper y rsync:

sudo apt update
sudo apt install build-essential bc bison flex libssl-dev libelf-dev libncurses-dev dwarves rsync cpio zstd debhelper fakeroot gnupg wget

Comprueba la versión de GCC instalada:

gcc --version | head -n1
gcc (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0

Anota también el kernel que estás usando ahora, porque te servirá para comparar y para volver atrás:

uname -r
6.8.0-79-generic

Paso 2: Descargar y verificar el código fuente

Consulta en kernel.org qué versión quieres compilar. Para un servidor lo razonable es la última versión de una rama longterm o la última stable. En esta guía se usa 6.12.50 como ejemplo; sustitúyela por la versión exacta que aparezca en kernel.org.

Crea un directorio de trabajo y guarda la versión en una variable para reutilizarla:

mkdir -p ~/kernel && cd ~/kernel
KVER=6.12.50

Descarga el archivo comprimido y su firma:

wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-${KVER}.tar.xz
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-${KVER}.tar.sign

La firma se calcula sobre el archivo .tar sin comprimir, así que primero descomprime el .xz:

unxz linux-${KVER}.tar.xz

Importa las claves de Linus Torvalds y Greg Kroah-Hartman, que firman las versiones publicadas, y verifica el archivo:

gpg --locate-keys [email protected] [email protected]
gpg --verify linux-${KVER}.tar.sign linux-${KVER}.tar

La línea importante es Good signature:

gpg: assuming signed data in 'linux-6.12.50.tar'
gpg: Signature made ...
gpg:                using RSA key 647F28654894E3BD457199BE38DBBDC86092693E
gpg: Good signature from "Greg Kroah-Hartman <[email protected]>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!

El aviso WARNING: This key is not certified es normal si no has firmado esas claves en tu anillo; lo que importa es que la firma sea válida. Si ves BAD signature, borra el archivo y vuelve a descargarlo.

Extrae el código fuente y entra en el directorio:

tar xf linux-${KVER}.tar
cd linux-${KVER}

Paso 3: Preparar la configuración

La forma más segura de empezar es reutilizar la configuración del kernel de Ubuntu que ya arranca en tu servidor. Cópiala como .config:

cp /boot/config-$(uname -r) .config

La configuración de Ubuntu hace referencia a certificados de Canonical (debian/canonical-certs.pem y debian/canonical-revoked-certs.pem) que no existen en el código fuente de kernel.org. Desactiva esas dos opciones o la compilación fallará:

scripts/config --disable SYSTEM_TRUSTED_KEYS
scripts/config --disable SYSTEM_REVOCATION_KEYS

Añade un sufijo a la versión para distinguir tu kernel de los de Ubuntu:

scripts/config --set-str LOCALVERSION "-custom"

Por último, adapta la configuración a la nueva versión. olddefconfig conserva tus opciones y asigna el valor por defecto a las que no existían en el kernel de Ubuntu, sin hacerte preguntas:

make olddefconfig
#
# configuration written to .config
#

Opcional: reducir el kernel a los módulos cargados

La configuración de Ubuntu compila miles de módulos para soportar cualquier hardware. Si quieres un kernel más pequeño y una compilación mucho más rápida, localmodconfig desactiva todos los módulos que no estén cargados en este momento:

make localmodconfig

Pulsa Intro en cada pregunta para aceptar el valor por defecto.

Opcional: cambiar opciones concretas

Para revisar o modificar opciones con un menú interactivo usa menuconfig. Con / puedes buscar una opción por nombre:

make menuconfig

Si prefieres cambios puntuales y reproducibles, scripts/config modifica una opción sin abrir el menú. Tras cualquier cambio, ejecuta de nuevo make olddefconfig para resolver las dependencias.

Comprueba que el sufijo de versión ha quedado aplicado:

grep '^CONFIG_LOCALVERSION=' .config
CONFIG_LOCALVERSION="-custom"

Paso 4: Compilar el kernel como paquetes .deb

En Ubuntu y Debian lo más limpio es generar paquetes .deb con make bindeb-pkg. Así el kernel se instala y se desinstala con apt, y los scripts de Ubuntu generan el initramfs y actualizan GRUB automáticamente. -j"$(nproc)" usa todos los núcleos disponibles.

Como la compilación dura bastante, ejecútala dentro de tmux o screen para que no se interrumpa si se corta la sesión SSH:

make -j"$(nproc)" bindeb-pkg

Cuando termine, los paquetes quedan en el directorio padre:

ls ../*.deb
../linux-headers-6.12.50-custom_6.12.50-1_amd64.deb
../linux-image-6.12.50-custom_6.12.50-1_amd64.deb
../linux-image-6.12.50-custom-dbg_6.12.50-1_amd64.deb
../linux-libc-dev_6.12.50-1_amd64.deb

Los nombres exactos pueden variar ligeramente según la versión del kernel. El paquete -dbg contiene los símbolos de depuración y no necesitas instalarlo. Tampoco instales linux-libc-dev: sustituiría las cabeceras del sistema que usa Ubuntu para compilar programas.

Paso 5: Instalar el nuevo kernel

Instala la imagen del kernel y sus cabeceras (las cabeceras las necesitan módulos externos como DKMS):

sudo apt install ../linux-image-${KVER}-custom_*_amd64.deb ../linux-headers-${KVER}-custom_*_amd64.deb

Si has abierto una sesión nueva desde el paso 2, vuelve a definir KVER antes de ejecutar el comando.

Durante la instalación, los scripts de /etc/kernel/postinst.d/ generan el initramfs y ejecutan update-grub. Comprueba que los archivos están en /boot:

ls /boot | grep custom
System.map-6.12.50-custom
config-6.12.50-custom
initrd.img-6.12.50-custom
vmlinuz-6.12.50-custom

Y que GRUB ha añadido una entrada para él:

grep -E "menuentry .*${KVER}-custom" /boot/grub/grub.cfg | head -n2

GRUB ordena los kernels por versión y arranca por defecto el más reciente, así que si tu versión es mayor que la de Ubuntu será la que arranque. El kernel anterior sigue disponible en Opciones avanzadas para Ubuntu.

Comprobar Secure Boot

Tu kernel no está firmado con la clave de Canonical. Si el servidor arranca con Secure Boot activado, el firmware se negará a cargarlo. Compruébalo antes de reiniciar:

mokutil --sb-state
SecureBoot disabled

Si la salida es SecureBoot enabled, tendrás que firmar el kernel con tu propia clave MOK o desactivar Secure Boot en el firmware; ese proceso queda fuera de esta guía. En la mayoría de VPS Secure Boot está desactivado o el comando indica que no está soportado.

Paso 6: Reiniciar y verificar

Reinicia el servidor:

sudo reboot

Cuando vuelvas a conectarte, comprueba la versión en ejecución:

uname -r
6.12.50-custom

Revisa los mensajes del arranque en busca de errores y comprueba que los servicios han arrancado:

sudo dmesg --level=err,warn | head -n 20
systemctl --failed
  UNIT LOAD ACTIVE SUB DESCRIPTION

0 loaded units listed.

Comprueba también que la red y el disco funcionan (ip -br a, df -h) y que los módulos que necesitas están disponibles, por ejemplo:

lsmod | head

Paso 7: Volver al kernel anterior o eliminar el personalizado

Si algo no funciona, reinicia y en el menú de GRUB elige Opciones avanzadas para Ubuntu y el kernel -generic anterior. En Ubuntu el menú suele estar oculto; mantén pulsada la tecla Mayús (BIOS) o pulsa Esc (UEFI) al arrancar desde la consola VNC para mostrarlo.

Una vez arrancado con el kernel de Ubuntu, desinstala el personalizado con apt, que también limpia /boot y regenera la configuración de GRUB:

sudo apt remove linux-image-${KVER}-custom linux-headers-${KVER}-custom

Para liberar espacio después de compilar, puedes borrar el árbol de compilación:

rm -rf ~/kernel/linux-${KVER}

Solución de problemas

No rule to make target 'debian/canonical-certs.pem': no se desactivaron SYSTEM_TRUSTED_KEYS o SYSTEM_REVOCATION_KEYS. Repite los comandos scripts/config del paso 3, ejecuta make olddefconfig y vuelve a compilar.

BTF: .tmp_vmlinux.btf: pahole (pahole) is not available: falta el paquete dwarves. Instálalo con sudo apt install dwarves y vuelve a lanzar la compilación.

El compilador muere con Killed o signal 9: el sistema se ha quedado sin memoria. Reduce el número de trabajos en paralelo, por ejemplo make -j2 bindeb-pkg, o añade swap temporalmente.

dpkg-buildpackage se queja de dependencias: el mensaje Unmet build dependencies indica qué paquetes faltan. Instálalos con apt y repite make bindeb-pkg.

Kernel panic - not syncing: VFS: Unable to mount root fs: el kernel no encuentra el controlador del disco o del sistema de archivos raíz. Suele ocurrir tras localmodconfig si el controlador no estaba en el initramfs. Arranca con el kernel anterior, revisa que CONFIG_VIRTIO_BLK, CONFIG_VIRTIO_SCSI (en máquinas virtuales KVM) y CONFIG_EXT4_FS estén activados como =y o =m y recompila.

Conclusión

Has compilado un kernel Linux desde el código fuente oficial, verificado su firma, adaptado la configuración de Ubuntu e instalado el resultado como paquetes .deb que puedes retirar con apt. Como siguientes pasos puedes:

  • Repetir el proceso con cada versión nueva de la rama longterm elegida, reutilizando tu .config con make olddefconfig.
  • Medir el impacto de tus cambios con herramientas como perf o sysbench antes y después de cambiar de kernel.
  • Explorar funciones que dependen del kernel, como eBPF, que aprovecha la información BTF que has generado.