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.
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 viaCONFIG_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 -kon 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 thescripts/config --disable SYSTEM_TRUSTED_KEYScommand and clean the relevant object:make scripts, then rebuild. - Wayland / GPU issues: If you stripped DRM drivers, your desktop will not start. Keep
CONFIG_DRMand 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 errto see boot-time errors for the current session. Missing firmware files appear here; install the appropriatelinux-firmwarepackage for your distro.
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
AI and Artificial-Life Tools on Linux
Set up open-source AI/ML and artificial-life toolkits on Linux: PyTorch, JAX, DEAP, Avida, NetLogo, and RL environments with GPU driver guidance.
Assembly Language on Linux: A Starter Guide
Write x86-64 assembly on Linux from scratch: install NASM and GAS, learn syscalls, assemble and link a working program, then inspect and debug it.
How to Benchmark Disk Performance with fio
Learn to benchmark Linux disk performance with fio: writing job files, testing latency and throughput, and interpreting IOPS and percentile output correctly.
The Linux Boot Process Explained
Trace the full Linux boot sequence from UEFI firmware through GRUB2, the kernel, initramfs, and systemd to your login prompt — with diagnostics at each stage.