Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Kernel Configuration

Introduction

Kernel configuration is the process of selecting which features, drivers, and subsystems to include in a Linux kernel build. With over 15,000 configuration options, the kernel is one of the most configurable pieces of software in existence. Proper configuration is critical: including too many features wastes memory and increases attack surface, while missing features can render the system unbootable.

This chapter covers the configuration file format, available configuration tools, strategies for custom kernels, and practical tips.

The .config File

The .config file is the central configuration artifact. It resides in the kernel source root and contains all configuration decisions:

# Example .config excerpt
#
# Automatically generated file; DO NOT EDIT.
# Linux/x86 6.1.0 Kernel Configuration
#
CONFIG_CC_VERSION_TEXT="gcc (Debian 12.2.0-14) 12.2.0"
CONFIG_CC_IS_GCC=y
CONFIG_GCC_VERSION=120200
CONFIG_CLANG_VERSION=0
CONFIG_AS_IS_GNU=y
CONFIG_AS_VERSION=24000

#
# General setup
#
CONFIG_INIT_ENV_ARG_LIMIT=32
CONFIG_COMPILE_TEST=y
# CONFIG_WERROR is not set
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_BUILD_SALT=""
CONFIG_DEFAULT_HOSTNAME="(none)"
CONFIG_SYSVIPC=y
CONFIG_SYSVIPC_SYSCTL=y
CONFIG_POSIX_MQUEUE=y
CONFIG_WATCH_QUEUE=y
CONFIG_CROSS_MEMORY_ATTACH=y

#
# Enable loadable module support
#
CONFIG_MODULES=y
CONFIG_MODULE_FORCE_LOAD=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y

.config Format Rules

Each line in .config follows one of three patterns:

CONFIG_FEATURE_A=y       # Built into the kernel
CONFIG_FEATURE_B=m       # Compiled as a loadable module
# CONFIG_FEATURE_C is not set  # Disabled (explicit)

Some symbols have values:

CONFIG_DEFAULT_TCP_CONG="cubic"    # String
CONFIG_BASE_SMALL=0                # Integer
CONFIG_PHYSICAL_START=0x1000000    # Hexadecimal

.config vs auto.conf

After running make, two additional configuration files are generated:

.config                  # Human-readable, full config
include/config/auto.conf  # Machine-readable, for Makefiles
include/config/auto.conf.cmd  # Dependency tracking
include/generated/autoconf.h   # C header for #ifdef

autoconf.h is included by every C file:

/* Generated include/generated/autoconf.h (excerpt) */
#define CONFIG_EXT4_FS 1
#define CONFIG_MODULES 1
#define CONFIG_DEFAULT_TCP_CONG "cubic"
#define CONFIG_HZ 250

Source code uses these defines:

/* fs/ext4/super.c */
#ifdef CONFIG_EXT4_FS_POSIX_ACL
    /* ACL support code */
    sb->s_flags |= SB_POSIXACL;
#endif

Configuration Tools

make menuconfig (ncurses)

The most popular configuration tool. Navigate with arrow keys, select with Enter:

$ make menuconfig

Key navigation:

KeyAction
↑/↓Navigate options
EnterEnter submenu / toggle
YBuild-in
MModule
NDisable
/Search
?Help
Esc×2Exit
TabMove to buttons

make xconfig (Qt)

Graphical configuration tool using Qt:

$ sudo apt install qtbase5-dev
$ make xconfig

Provides a tree view with search, dependency visualization, and help panels.

make gconfig (GTK)

GTK-based graphical tool:

$ sudo apt install libgtk-3-dev
$ make gconfig

make oldconfig

Prompts only for new options. Essential after kernel version upgrades:

# Copy old config
$ cp /boot/config-$(uname -r) .config

# Update for new kernel, prompt for new options
$ make oldconfig

make olddefconfig

Like oldconfig but uses defaults for new options (no prompts):

$ make olddefconfig

make defconfig

Generates a default configuration for the architecture:

$ make defconfig          # Architecture default
$ make x86_64_defconfig   # Specific defconfig
$ make tinyconfig         # Minimal configuration
$ make allnoconfig        # Everything off
$ make allyesconfig       # Everything on (as modules/built-in)
$ make randconfig         # Random configuration

make localmodconfig

Generates a config based on currently loaded modules — excellent for building a minimal kernel for your specific hardware:

# Step 1: Boot with a generic distribution kernel
# Step 2: Use all hardware you need (USB, WiFi, etc.)
# Step 3: Generate config from loaded modules
$ make localmodconfig

# The resulting config includes only what you're actually using

This typically reduces build time from hours to minutes and produces a much smaller kernel.

make tinyconfig

Creates the smallest possible kernel configuration:

$ make tinyconfig
# Results in a very minimal kernel — may not boot on most systems
# Useful as a starting point for embedded systems

make kvm_guest.config

Optimizes for KVM virtual machine guests:

$ make kvm_guest.config

Scripted Configuration

# Enable a feature
$ scripts/config --enable CONFIG_EXT4_FS

# Disable a feature
$ scripts/config --disable CONFIG_DEBUG_INFO

# Set to module
$ scripts/config --module CONFIG_BTRFS_FS

# Set a value
$ scripts/config --set-val CONFIG_DEFAULT_TCP_CONG bbr

# Enable multiple features
$ scripts/config --enable CONFIG_BBR --enable CONFIG_TCP_CONG_BBR

# Disable multiple features
$ scripts/config --disable CONFIG_DEBUG_KERNEL \
                 --disable CONFIG_DEBUG_INFO \
                 --disable CONFIG_KASAN

Programmatic Configuration

# Read current value
$ grep CONFIG_EXT4_FS .config
CONFIG_EXT4_FS=y

# Check if feature is enabled in running kernel
$ cat /proc/config.gz | gunzip | grep CONFIG_EXT4_FS
CONFIG_EXT4_FS=y

# Or if /proc/config.gz is not available:
$ grep CONFIG_EXT4_FS /boot/config-$(uname -r)

Configuration Dependencies

Understanding configuration dependencies is essential:

graph TD
    CONFIG_NET[CONFIG_NET -- Networking support]
    CONFIG_INET[CONFIG_INET -- TCP/IP networking]
    CONFIG_IPV6[CONFIG_IPV6 -- IPv6]
    CONFIG_TCP_CONG[CONFIG_TCP_CONG_CUBIC -- default congestion]
    CONFIG_BBR[CONFIG_TCP_CONG_BBR -- BBR congestion]
    CONFIG_NETFILTER[CONFIG_NETFILTER -- Netfilter framework]
    CONFIG_NF_CONNTRACK[CONFIG_NF_CONNTRACK -- Connection tracking]
    CONFIG_IPTABLES[CONFIG_NETFILTER_XTABLES -- iptables]

    CONFIG_NET --> CONFIG_INET
    CONFIG_INET --> CONFIG_IPV6
    CONFIG_INET --> CONFIG_TCP_CONG
    CONFIG_INET --> CONFIG_BBR
    CONFIG_NET --> CONFIG_NETFILTER
    CONFIG_NETFILTER --> CONFIG_NF_CONNTRACK
    CONFIG_NETFILTER --> CONFIG_IPTABLES

Checking Dependencies

# View all dependencies of a symbol
$ grep -r "depends on CONFIG_EXT4" fs/ext4/Kconfig

# In menuconfig, press ? to see dependencies
# Or use scripts/kconfig/merge_config.sh

Handling Missing Dependencies

# If a feature can't be enabled, check its dependencies
$ make menuconfig
# Navigate to the feature, press ? to see "Depends on"

# Or use scripts/diffconfig to compare configs
$ scripts/diffconfig .config.old .config

Common Configuration Profiles

Minimal Desktop Kernel

# Start with distribution config
$ cp /boot/config-$(uname -r) .config
$ make olddefconfig

# Disable debug features
$ scripts/config --disable CONFIG_DEBUG_KERNEL
$ scripts/config --disable CONFIG_DEBUG_INFO
$ scripts/config --disable CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT
$ scripts/config --disable CONFIG_KASAN
$ scripts/config --disable CONFIG_KCSAN
$ scripts/config --disable CONFIG_KMEMLEAK

# Disable unnecessary filesystems
$ scripts/config --disable CONFIG_GFS2_FS
$ scripts/config --disable CONFIG_OCFS2_FS
$ scripts/config --disable CONFIG_NILFS2_FS

# Disable unused hardware drivers
$ scripts/config --disable CONFIG_INFINIBAND
$ scripts/config --disable CONFIG_FCOE
$ scripts/config --disable CONFIG_SCSI_FC_ATTRS

# Rebuild
$ make olddefconfig
$ make -j$(nproc)

Server Kernel

# Enable performance features
$ scripts/config --enable CONFIG_PREEMPT_NONE      # Server: minimize latency variance
$ scripts/config --enable CONFIG_NO_HZ_FULL        # Adaptive tickless
$ scripts/config --enable CONFIG_HIGH_RES_TIMERS
$ scripts/config --enable CONFIG_TCP_CONG_BBR      # BBR congestion control
$ scripts/config --enable CONFIG_NET_SCH_FQ        # Fair queueing

# Enable monitoring
$ scripts/config --enable CONFIG_FTRACE
$ scripts/config --enable CONFIG_FUNCTION_TRACER
$ scripts/config --enable CONFIG_PERF_EVENTS
$ scripts/config --enable CONFIG_BPF_SYSCALL

# Security features
$ scripts/config --enable CONFIG_SECURITY_SELINUX
$ scripts/config --enable CONFIG_SECCOMP
$ scripts/config --enable CONFIG_SECCOMP_FILTER

# Networking
$ scripts/config --enable CONFIG_TCP_CONG_BBR
$ scripts/config --enable CONFIG_NET_SCH_FQ_CODEL

Embedded / IoT Kernel

$ make tinyconfig

# Enable only what's needed
$ scripts/config --enable CONFIG_NET
$ scripts/config --enable CONFIG_INET
$ scripts/config --enable CONFIG_EXT4_FS
$ scripts/config --enable CONFIG_SERIAL_8250
$ scripts/config --enable CONFIG_SERIAL_8250_CONSOLE
$ scripts/config --enable CONFIG_PRINTK
$ scripts/config --enable CONFIG_TMPFS
$ scripts/config --enable CONFIG_DEVTMPFS
$ scripts/config --enable CONFIG_DEVTMPFS_MOUNT

$ make olddefconfig
$ make -j$(nproc)

Kernel Configuration for Containers

When building a kernel for container workloads (Docker, Kubernetes, LXC):

# Essential: Namespaces
$ scripts/config --enable CONFIG_NAMESPACES
$ scripts/config --enable CONFIG_UTS_NS
$ scripts/config --enable CONFIG_IPC_NS
$ scripts/config --enable CONFIG_USER_NS
$ scripts/config --enable CONFIG_PID_NS
$ scripts/config --enable CONFIG_NET_NS
$ scripts/config --enable CONFIG_CGROUP_NS

# Essential: Cgroups
$ scripts/config --enable CONFIG_CGROUPS
$ scripts/config --enable CONFIG_CGROUP_CPUACCT
$ scripts/config --enable CONFIG_CGROUP_DEVICE
$ scripts/config --enable CONFIG_CGROUP_FREEZER
$ scripts/config --enable CONFIG_CGROUP_SCHED
$ scripts/config --enable CONFIG_CGROUP_PIDS
$ scripts/config --enable CONFIG_MEMCG
$ scripts/config --enable CONFIG_CGROUP_PERF

# Essential: Networking
$ scripts/config --enable CONFIG_VETH
$ scripts/config --enable CONFIG_BRIDGE
$ scripts/config --enable CONFIG_BRIDGE_NETFILTER
$ scripts/config --enable CONFIG_NETFILTER_XT_MATCH_CONNTRACK
$ scripts/config --enable CONFIG_NETFILTER_XT_MATCH_ADDRTYPE
$ scripts/config --enable CONFIG_NETFILTER_XT_MATCH_IPVS
$ scripts/config --enable CONFIG_IP_NF_NAT
$ scripts/config --enable CONFIG_IP_NF_TARGET_MASQUERADE
$ scripts/config --enable CONFIG_IP_VS
$ scripts/config --enable CONFIG_IP_VS_NFCT
$ scripts/config --enable CONFIG_OVERLAY_FS

# Essential: Storage
$ scripts/config --enable CONFIG_BLK_DEV_DM
$ scripts/config --enable CONFIG_DM_THIN_PROVISIONING
$ scripts/config --enable CONFIG_EXT4_FS
$ scripts/config --enable CONFIG_BTRFS_FS

# Security
$ scripts/config --enable CONFIG_SECCOMP
$ scripts/config --enable CONFIG_SECCOMP_FILTER
$ scripts/config --enable CONFIG_USER_NS

Debugging Configuration

Missing Module / Feature

# Find which config option enables a specific module
$ grep -r "e1000e" drivers/net/ethernet/intel/e1000e/Kconfig
config E1000E
    tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support"

# Check if it's enabled in .config
$ grep CONFIG_E1000E .config
CONFIG_E1000E=m

# If missing, enable it
$ scripts/config --module CONFIG_E1000E
$ make olddefconfig

Configuration Comparison

# Compare two .config files
$ scripts/diffconfig .config.old .config

# Generate config diff after make oldconfig
$ diff -u .config.old .config | head -50

Kernel Boot Config

The running kernel exposes its configuration:

# From /proc/config.gz (if available)
$ zcat /proc/config.gz | less

# From /boot/
$ ls /boot/config-*
/boot/config-6.1.0-23-amd64

# Check specific option
$ zcat /proc/config.gz | grep CONFIG_PREEMPT
# CONFIG_PREEMPT is not set
CONFIG_PREEMPT_VOLUNTARY=y
# CONFIG_PREEMPT_NONE is not set

Validating Configuration

# Check for errors in configuration
$ make olddefconfig
# If there are issues, warnings will be printed

# Verify specific feature is available
$ cat /proc/filesystems | grep ext4
nodev   ext4

Kernel Config Fragments

Config fragments allow modular configuration management:

# Create a fragment
$ cat > my-fragment.config << 'EOF'
CONFIG_TCP_CONG_BBR=y
CONFIG_NET_SCH_FQ=y
CONFIG_DEFAULT_TCP_CONG="bbr"
EOF

# Merge fragment into existing config
$ scripts/kconfig/merge_config.sh .config my-fragment.config

# Or use KCONFIG_CONFIG
$ KCONFIG_CONFIG=.config scripts/kconfig/merge_config.sh \
    base.config \
    networking.config \
    security.config

Using merge_config.sh

# Merge multiple fragments
$ scripts/kconfig/merge_config.sh \
    arch/x86/configs/x86_64_defconfig \
    fragments/containers.config \
    fragments/security.config \
    fragments/debug.config

# The merged .config is created
$ make olddefconfig

Hardware-Specific Configuration

Detecting Required Drivers

# List all PCI devices and their kernel modules
$ lspci -k | head -20
00:00.0 Host bridge: Intel Corporation Xeon E3-1200
        Subsystem: Dell Device 0617
00:02.0 VGA compatible controller: Intel Corporation HD 530
        Kernel driver in use: i915
        Kernel modules: i915
00:14.0 USB controller: Intel Corporation 100 Series
        Kernel driver in use: xhci_hcd
        Kernel modules: xhci_pci

# List all loaded modules
$ lsmod

# Get modinfo for a module
$ modinfo e1000e
filename:       /lib/modules/6.1.0/kernel/drivers/net/ethernet/intel/e1000e/e1000e.ko
version:        5.14.2
license:        GPL v2
description:    Intel(R) PRO/1000 Network Driver
author:         Intel Corporation
firmware:       e1000e/82571-1.fw

Auto-Detecting Hardware

# Generate config from running hardware
$ make localmodconfig

# Or more specific
$ lsmod > /tmp/my-modules.txt
$ make LSMOD=/tmp/my-modules.txt localmodconfig

Configuration Tips and Best Practices

1. Always Start from a Working Config

# Copy distribution kernel config as starting point
$ cp /boot/config-$(uname -r) .config
$ make olddefconfig

2. Use localmodconfig for Speed

# Dramatically reduces build time
$ make localmodconfig
$ time make -j$(nproc)    # May go from 2 hours to 15 minutes

3. Enable /proc/config.gz

$ scripts/config --enable CONFIG_IKCONFIG
$ scripts/config --enable CONFIG_IKCONFIG_PROC

4. Keep Debug Info Separate

# Minimal debug info in kernel, full debug in separate package
$ scripts/config --enable CONFIG_DEBUG_INFO_NONE
# Or for debugging:
$ scripts/config --enable CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT

5. Version Your Configs

# Tag your custom config
$ scripts/config --set-str CONFIG_LOCALVERSION "-mycustom"
$ make olddefconfig

6. Test in Virtual Machine First

# Build and test in QEMU
$ qemu-system-x86_64 -kernel arch/x86/boot/bzImage \
    -append "console=ttyS0" \
    -nographic \
    -m 2G

7. Use CONFIG_MODULES for Flexibility

# Build most drivers as modules for flexibility
$ scripts/config --enable CONFIG_MODULES
$ scripts/config --enable CONFIG_MODULE_UNLOAD
# Enable hotplug module loading
$ scripts/config --enable CONFIG_MODULES

Configuration File Locations

LocationDescription
.configMain configuration file
arch/*/configs/*_defconfigArchitecture-specific defaults
include/generated/autoconf.hC header for #ifdef
include/config/auto.confMakefile include
/proc/config.gzRunning kernel config
/boot/config-*Installed kernel config

Further Reading