Skip to main content
This guide walks through building a Linux kernel from source on a mainstream x86-64 distribution. The same process applies to other architectures with minor adjustments to the cross-compilation flags.
You will need at least 12 GB of free space in your build directory for a standard build with debug symbols enabled, or around 4 GB with debug symbols disabled. An additional 150 MB in /lib/ and 100 MB in /boot/ are needed at install time.

Install build dependencies

The kernel requires a C compiler, GNU Make, a linker, and several supporting tools. Install them with your distribution’s package manager:
sudo apt install bc binutils bison dwarves flex gcc git make openssl \
  pahole perl-base libssl-dev libelf-dev
On Debian you will also need to clear a stale certificate reference that would otherwise cause the build to fail:
./scripts/config --file .config --set-str SYSTEM_TRUSTED_KEYS ''

Minimal version requirements

The following table lists the minimum versions of tools required to build the current kernel. Verify installed versions with the commands shown.
ToolMinimum versionCheck command
GCC8.1gcc --version
GNU Make4.0make --version
Binutils2.30ld -v
Bash4.2bash --version
flex2.5.35flex --version
bison2.0bison --version
pahole1.22pahole --version
OpenSSL1.0.0openssl version
Python3.9.xpython3 --version
Clang/LLVM (optional)15.0.0clang --version
Rust (optional)1.78.0rustc --version

Secure Boot

On systems with Secure Boot enabled, self-compiled kernels will be rejected at boot unless they are signed with a key trusted by your firmware. The quickest approach on commodity x86 systems is to disable Secure Boot in your BIOS setup utility. Alternatively, on mainstream Linux distributions you can disable validation for your environment:
mokutil --disable-validation
This prompts for a one-time password. On the next boot, the Shim bootloader presents an MOK management menu where you confirm the change.

Get the source

1

Clone the stable kernel repository

A shallow clone retrieves only the history you need and downloads roughly the same amount of data as a tarball:
git clone --depth 1 -b master \
  https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git ~/linux/
cd ~/linux/
To access a specific stable series (for example, 6.6.y), add its remote branch and deepen accordingly:
git remote set-branches --add origin linux-6.6.y
git fetch --shallow-exclude=v6.5 origin
git checkout --detach origin/linux-6.6.y
If you need the very latest mainline code rather than the stable mirror (which lags by a few hours), add Linus’s tree as an additional remote:
git remote add mainline \
  https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
git fetch mainline
git checkout --detach mainline/master
2

(Optional) Download a tarball instead

If you only need to build a specific release without using git, download a tarball from kernel.org and extract it:
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.9.tar.xz
tar xf linux-6.9.tar.xz
cd linux-6.9/
Tarballs do not support git bisect, git revert, or easy patching. Use a git clone when doing any kind of debugging or development.

Configure the kernel

Kernel configuration is stored in a .config file. The build system provides several make targets to create or update this file. If you have patched the kernel or want to distinguish your build from a distribution kernel with the same version number, add a local version tag:
echo "-mybuild" > localversion
uname -r will then report something like 6.9.0-mybuild.

Adjust debug symbols

Debug symbols increase build artifacts from roughly 1 GB to around 5 GB. Disable them if you are short on space and do not need to decode stack traces:
./scripts/config --file .config \
  -d DEBUG_INFO \
  -d DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT \
  -d DEBUG_INFO_DWARF4 \
  -d DEBUG_INFO_DWARF5 \
  -e CONFIG_DEBUG_INFO_NONE
make olddefconfig
Enable them for full stack trace decoding:
./scripts/config --file .config \
  -d DEBUG_INFO_NONE \
  -e DEBUG_KERNEL \
  -e DEBUG_INFO \
  -e DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT \
  -e KALLSYMS \
  -e KALLSYMS_ALL
make olddefconfig

Build

1

Compile the kernel and modules

Use all available CPU cores to minimize build time:
make -j $(nproc --all)
A typical build takes 5–30 minutes depending on configuration size and hardware. If the build fails, re-run with verbose output to see the exact error:
make V=1
2

(Optional) Build a distributable package

To package the kernel as a .deb or .rpm rather than installing directly:
make -j $(nproc --all) bindeb-pkg
Install or remove the resulting packages with dpkg/apt or rpm/dnf as you would any distribution kernel.

Cross-compilation

To build for a different architecture, set ARCH and CROSS_COMPILE:
# Build an arm64 kernel on an x86-64 host
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
make defconfig
make -j $(nproc --all)
The CROSS_COMPILE prefix must match a toolchain installed on your build host. On Debian/Ubuntu, gcc-aarch64-linux-gnu provides the aarch64-linux-gnu-gcc compiler needed above.

Install

1

Install modules and kernel image

On most distributions a single command handles both steps:
command -v installkernel && sudo make modules_install install
make modules_install copies modules to /lib/modules/<release>/. make install then calls the distribution’s installkernel helper, which copies the kernel image to /boot/, generates an initramfs, and updates the bootloader configuration.
Always run modules_install before install. The initramfs generator called by installkernel may need the freshly installed modules.
2

Manual installation (Arch Linux and derivatives)

Arch Linux and some other distributions do not ship an installkernel executable. Install manually:
sudo make modules_install
sudo install -m 0600 $(make -s image_name) \
  /boot/vmlinuz-$(make -s kernelrelease)
sudo install -m 0600 System.map \
  /boot/System.map-$(make -s kernelrelease)
Then generate an initramfs using your distribution’s tooling (e.g., mkinitcpio on Arch) and add an entry to your bootloader (e.g., grub-mkconfig or a direct systemd-boot entry).
3

Reboot and verify

reboot
After rebooting, confirm the correct kernel is running:
uname -r
Check the kernel ring buffer for any hardware or driver errors:
dmesg | grep -i error
dmesg | grep -i fail

Remove an old kernel

Kernel files are stored in two locations and are named after the kernel’s release string, making removal straightforward.
# Remove modules (substitute your release string)
sudo rm -rf /lib/modules/6.9.0-mybuild

# Remove kernel files and bootloader entry (if kernel-install is available)
command -v kernel-install && sudo kernel-install remove 6.9.0-mybuild

# Otherwise remove manually
sudo rm -i /boot/{System.map,vmlinuz}-6.9.0-mybuild
# Also remove the initramfs, e.g.:
sudo rm -i /boot/initramfs-6.9.0-mybuild.img
Never remove the kernel you are currently running. Verify with uname -r before deleting any kernel files.

Rebuilding after a source update

When pulling a newer version of the source tree, preserve your existing configuration and adjust it to any new Kconfig symbols:
cd ~/linux/
git fetch --depth 1 origin
git checkout --force --detach origin/master
make olddefconfig
make -j $(nproc --all)
command -v installkernel && sudo make modules_install install
reboot

Build docs developers (and LLMs) love