How to Compile and Install the Linux Kernel on Ubuntu

In this post I will show you how to compile and install the Linux kernel from source on Ubuntu.

I know that there are tons of tutorials on compiling the Linux kernel. However, while I tried many of them, none of them worked for me. I always either got error messages during compilation or the compilation terminated without error messages but failed at installation. Therefore, I decided to write down how I did it.

The setup I tested this on

I used a freshly installed VirtualBox with Ubuntu Server 22.04. I did not do any modifications to the machine and didn’t install any packages on it beforehand. Additionally, I also tested the steps presented in this post on a real computer with an AMD Ryzen 7 2700X CPU.

Installing dependencies, downloading the kernel source

First we need to install a few packages that are required for the compilation:

$ sudo apt install build-essential libncurses-dev bison flex libssl-dev libelf-dev fakeroot

Additionally we also need to install the dwarves package. When I tried it without the package, the compilation failed with an error message.

$ sudo apt install dwarves

Next we need to need to download the kernel source from the offical kernel.org website.

Choose the latest longterm release and copy the link of the tarball hyperlink. Then use this link to download and unpack the kernel source to your Ubuntu machine:

$ wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.89.tar.xz
$ tar -xf linux-5.15.89.tar.gz

Configuring the kernel

Now enter the directory of the Linux source:

$ cd linux-5.15.89

The configuration of the Linux kernel can be specified in a .config file. A good starting point is to copy the config file of your currently installed Linux:

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

However, this config file includes tons of unnecessary drivers and kernel modules which dramatically increases the build time. To mitigate this, we can use the localmodconfig command. This command looks at the loaded kernel modules of your system and modifies the .config file such that only these modules are included in the build. This should work perfectly fine as long as you don’t plan to use the generated build on another machine than the one you compile the source on.

make localmodconfig

Next, you need to make four modifications to the configuration. Otherwise the build will fail. To do this, you can either directly modify the .config file or simply run the following commands:

$ scripts/config --disable SYSTEM_TRUSTED_KEYS
$ scripts/config --disable SYSTEM_REVOCATION_KEYS
$ scripts/config --set-str CONFIG_SYSTEM_TRUSTED_KEYS ""
$ scripts/config --set-str CONFIG_SYSTEM_REVOCATION_KEYS ""

Compiling

Now it’s time to compile the kernel. For this just run the command

$ fakeroot make

You can also speed up the build by using multiple CPU cores of your machine. For instance,

$ fakeroot make -j8

will use eight cores of your machine.

The build time heavily depends on your machine and is especially slow on virtual machines. On my VirtualBox with only one CPU core it took around 3 hours. On a physical computer with an AMD Ryzen 7 2700X with 8 cores it took only 6 minutes.

After the build finishes, you can check whether it is successful by running

$ echo $?

This outputs the return code of the previous command. If it returns 0, the build was sucessful. For any other value than 0 the build was not sucessful.

Installation

The installation is split into two parts: Installing the kernel modules and installing the kernel itself.

First install the kernel modules by running

$ sudo make modules_install

Then install the kernel itself:

$ sudo make install

After that, reboot your machine:

$ sudo reboot

Checking if kernel was installed sucessfully

You can check the version of the installed kernel by running

$ uname -rs

This outputs something like

You know that the installation was sucessfull if the displayed Linux version matches the one of the kernel source you downloaded.

Bonus: Modifying the kernel source

Of course you can also modify the Kernel source before installation to make your own custom version Linux. As a very simple example for such a modification I’ll modify the name of the operating system. Any other modification of the source code works the same.

The default name is of course “Linux”. It is stored in the include/linux/uts.h header file, which looks like this:

// include/linux/uts.h

/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_UTS_H
#define _LINUX_UTS_H

/*
 * Defines for what uname() should return 
 */
#ifndef UTS_SYSNAME
#define UTS_SYSNAME "Linux"
#endif

#ifndef UTS_NODENAME
#define UTS_NODENAME CONFIG_DEFAULT_HOSTNAME /* set by sethostname() */
#endif

#ifndef UTS_DOMAINNAME
#define UTS_DOMAINNAME "(none)"	/* set by setdomainname() */
#endif

#endif

We can now change the operating system name by changing the UTS_SYSNAME field. In my case I’ll change it to DavidOS:

// include/linux/uts.h

/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_UTS_H
#define _LINUX_UTS_H

/*
 * Defines for what uname() should return 
 */
#ifndef UTS_SYSNAME
#define UTS_SYSNAME "DavidOS" // <-- CHANGED
#endif

#ifndef UTS_NODENAME
#define UTS_NODENAME CONFIG_DEFAULT_HOSTNAME /* set by sethostname() */
#endif

#ifndef UTS_DOMAINNAME
#define UTS_DOMAINNAME "(none)"	/* set by setdomainname() */
#endif

#endif

After you modified the file, you can simple re-compile the kernel and then install it:

$ fakeroot make
$ sudo make modules_install
$ sudo make install
$ sudo reboot

The compile time should now be significantly shorter than the first time. The reason is that make re-uses some results from the first compilation run.

When you now run uname -rs you get the following:

As you can see, it now displays DavidOS instead of Linux.

And that’s it

Now you know how to compile the Linux kernel yourself. You can use this knowledge to upgrade to the latest kernel version long before your Linux distribution does. Besides this you can also customize the kernel to adapt it to your needs.

Questions? Feedback? Send an email to .