$linuxjunkies
>

How to Compile the Linux Kernel

Step-by-step guide to downloading, configuring, compiling, and booting a custom Linux kernel from kernel.org on Debian, Fedora, and Arch Linux.

AdvancedUbuntuDebianFedoraArch10 min readUpdated June 7, 2026

Before you start

  • Root or sudo access on the target machine
  • At least 15 GB of free disk space in /usr/src and /boot
  • Stable internet connection to download the source tarball (~130 MB)
  • Familiarity with the Linux command line and your system's bootloader

Compiling your own kernel lets you strip out unnecessary drivers, enable experimental features, apply custom patches, or simply learn how the foundation of your system actually works. It is not a task for an afternoon if you expect a production machine at the end — but it is well within reach if you follow the steps carefully. These instructions target the vanilla kernel from kernel.org on x86-64. ARM and other architectures follow the same logic but may need a cross-compiler and a different ARCH= value.

Prerequisites and Build Dependencies

You need a working build toolchain, flex/bison for the parser, libelf for BTF support (required for modern kernels with eBPF), and OpenSSL headers for module signing. Install them before touching the source tree.

Debian / Ubuntu

sudo apt update
sudo apt install -y build-essential bc bison flex libssl-dev \
  libelf-dev libncurses-dev dwarves git cpio zstd

Fedora / RHEL / Rocky

sudo dnf groupinstall -y "Development Tools"
sudo dnf install -y bison flex elfutils-libelf-devel \
  openssl-devel ncurses-devel dwarves bc git cpio zstd

Arch Linux

sudo pacman -S --needed base-devel bc bison flex libelf \
  openssl ncurses dwarves git cpio zstd

Step 1 — Get the Kernel Source

Download the latest stable tarball from kernel.org. Avoid cloning the full git history for a one-off build — the tarball is faster. Always verify the PGP signature before extracting.

cd /usr/src
sudo wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.9.9.tar.xz
sudo wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.9.9.tar.sign

The .tar.sign file covers the uncompressed tarball. Decompress first, then verify:

sudo xz -d linux-6.9.9.tar.xz
gpg --locate-keys [email protected] [email protected]
gpg --verify linux-6.9.9.tar.sign linux-6.9.9.tar

A Good signature message is what you need. Extract and enter the directory:

sudo tar -xf linux-6.9.9.tar
cd linux-6.9.9

Step 2 — Configure the Kernel

Configuration is the most consequential step. A wrong choice here means missing drivers or a kernel that will not boot. The fastest safe starting point is to copy your running distro config and then open the menu to adjust it.

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

olddefconfig silently sets every new symbol to its default — no prompts. If you want an interactive review, use make menuconfig (requires libncurses) instead. For a genuinely minimal config based only on modules loaded right now, use:

make localmodconfig

Warning: localmodconfig only includes drivers for hardware currently active. Build the kernel on the target machine, not a VM, or you risk missing storage or network drivers on boot.

Disable module signing for a local build

If you are not setting up a signing key, disable the requirement to avoid build errors:

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

Step 3 — Build the Kernel and Modules

Pass -j a value roughly equal to your logical CPU count. The build takes anywhere from 5 minutes on a modern 16-core machine to over an hour on a dual-core system.

make -j$(nproc)

If the build fails early with a certificates-related error, re-run the two scripts/config commands from the previous step and retry. Kernel version-specific build errors are common; check the kernel's Documentation/ tree and the mailing list archives for your exact error.

Step 4 — Install Modules

Modules go into /lib/modules/<version>/. Run this as root:

sudo make modules_install

This step is non-destructive to your existing kernel's modules because each kernel version gets its own subdirectory.

Step 5 — Install the Kernel Image and Headers

The make install target copies the compressed kernel image, System.map, and config to /boot and, on most distros, calls the bootloader update hook automatically.

sudo make install

On Debian/Ubuntu this invokes installkernel, which also runs update-initramfs and update-grub. On Fedora/RHEL it calls new-kernel-pkg or kernel-install. On Arch it copies only the image — you must handle the initramfs and bootloader manually (see below).

Step 6 — Generate the initramfs (if needed)

Debian/Ubuntu generate the initramfs automatically during make install. For other distros or if something went wrong:

Fedora / RHEL / Rocky

sudo dracut --force /boot/initramfs-6.9.9.img 6.9.9

Arch Linux

# Copy the image (make install may have done this already)
sudo cp arch/x86/boot/bzImage /boot/vmlinuz-linux-custom

# Create a mkinitcpio preset or generate directly
sudo mkinitcpio -k 6.9.9 -g /boot/initramfs-linux-custom.img

Step 7 — Update the Bootloader

GRUB is the most common bootloader. After make install, regenerate the GRUB configuration to pick up the new entry.

Debian / Ubuntu

sudo update-grub

Fedora / RHEL / Rocky

sudo grub2-mkconfig -o /boot/grub2/grub.cfg

Arch Linux (systemd-boot)

If you use systemd-boot instead of GRUB, create a boot entry manually:

cat /boot/loader/entries/linux-custom.conf

A minimal entry looks like:

title   Linux Custom 6.9.9
linux   /vmlinuz-linux-custom
initrd  /initramfs-linux-custom.img
options root=PARTUUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx rw

Replace the PARTUUID with the output of blkid /dev/sdXY for your root partition.

Step 8 — Boot and Verify

Reboot and select the new kernel from the GRUB menu. Hold Shift (BIOS) or Esc (UEFI) during boot to force the menu if it is hidden.

uname -r

The output should show your new version string, e.g. 6.9.9. Confirm critical subsystems loaded correctly:

systemctl --failed
dmesg | grep -i error | head -20
lsmod | wc -l

Your old kernel remains in /boot and in GRUB's menu until you explicitly remove it, so you can always reboot back to it.

Troubleshooting

  • Kernel panics at boot — can't mount root: Your storage controller driver is missing. Reboot the old kernel, re-run make menuconfig, and ensure the driver for your disk controller (e.g., CONFIG_SATA_AHCI, NVMe via CONFIG_BLK_DEV_NVME) is built-in ([*]), not as a module ([M]), or is included in the initramfs.
  • No network after boot: Same issue — your NIC driver was left out. Check lspci -k on the old kernel to find the driver name, then enable it in the config.
  • Build fails: No rule to make target 'debian/canonical-certs.pem': Re-run the scripts/config --disable SYSTEM_TRUSTED_KEYS command and clean the relevant object: make scripts, then rebuild.
  • Wayland / GPU issues: If you stripped DRM drivers, your desktop will not start. Keep CONFIG_DRM and your specific GPU driver (CONFIG_DRM_I915, CONFIG_DRM_AMDGPU, CONFIG_DRM_NOUVEAU) enabled. Proprietary NVIDIA drivers require the kernel headers to be installed: sudo make headers_install.
  • Slow boot, many failed units: Run journalctl -b 0 -p err to see boot-time errors for the current session. Missing firmware files appear here; install the appropriate linux-firmware package for your distro.
tested on:Ubuntu 24.04Fedora 40Arch rollingDebian 12

Frequently asked questions

How long does a full kernel build take?
On a modern 8-core CPU with a config derived from localmodconfig, expect 5–15 minutes. A full distro-style config with all modules enabled can take 45–90 minutes on the same hardware.
Is it safe to compile a kernel on my main machine?
The build itself is safe — it writes only to the source tree and /boot. The risk is the new kernel not booting correctly. Keep your old kernel entry in GRUB as a fallback, and test on non-critical hardware first.
What is the difference between make menuconfig, olddefconfig, and localmodconfig?
olddefconfig sets all new options to their compiled-in defaults without prompting. localmodconfig disables everything not currently loaded, producing a minimal config. menuconfig opens a full interactive TUI for manual review of every option.
Will proprietary NVIDIA drivers work with a custom kernel?
Yes, but the DKMS mechanism needs your kernel headers. Run sudo make headers_install after building, and ensure dkms is installed so the NVIDIA module rebuilds automatically for the new version.
How do I remove a custom kernel I no longer need?
Delete the vmlinuz, initramfs, System.map, and config files for that version from /boot, remove the module directory under /lib/modules/<version>, then regenerate your bootloader config with update-grub or equivalent.

Related guides