Build and Check a Custom initramfs with mkinitramfs
Get mkinitramfs wrong on the wrong output path and you can leave a machine unable to reach its own root filesystem. This guide builds the image to a scratch path instead, checks what went into it, and only then talks about promoting it. The examples use mkinitramfs from initramfs-tools-core 0.142ubuntu25.8.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow 15 to 30 minutes. You need a shell, enough space for a temporary image, and the matching kernel files under /lib/modules. This guide creates a separate file: it does not install an image, alter the bootloader or replace anything under /boot. Most inspection commands run fine as an ordinary user; only the output directory might need elevated privileges.
Safety boundary
Do not point the output at a filename already used by a boot entry until you have checked the path, kernel version and contents. A bad initramfs can prevent a machine from reaching its normal root filesystem.
1. Check the installed tool and its required option
The low-level command requires -o and an output filename. Leave out the version argument and it builds for the running kernel. Check the local help before copying anything into a script:
$ mkinitramfs --help
Usage: mkinitramfs [option]... -o outfile [version]
Options:
-c compress Override COMPRESS setting in initramfs.conf.
-d confdir Specify an alternative configuration directory.
-l level Override COMPRESSLEVEL setting in initramfs.conf.
-k Keep temporary directory used to make the image.
-o outfile Write to outfile.
-r root Override ROOT setting in initramfs.conf.
The installed script accepts --help but has no useful version-reporting option, so record the package version instead:
$ dpkg-query -W -f='${Package} ${Version}\n' initramfs-tools-core
initramfs-tools-core 0.142ubuntu25.8
Checkpoint
The command should print usage with -o outfile. If mkinitramfs is missing, install or repair initramfs-tools-core through your normal package-management process before continuing.
2. Choose a scratch output path
Use a new file in a temporary directory while learning or testing. mktemp reserves the name and the command writes the image there:
out=$(mktemp /tmp/initramfs-test.XXXXXX.img)
mkinitramfs -o "$out" "$(uname -r)"
status=$?
printf 'exit status: %s\nimage: %s\n' "$status" "$out"
test "$status" -eq 0
Naming the kernel version explicitly keeps the target visible in the command instead of relying on someone remembering which kernel is running. That version needs usable module data under /lib/modules/<version>. The resulting file is a compressed cpio archive, not a filesystem image you mount directly.
A successful run ends with exit status: 0 and a non-empty file at the path. If the build fails, keep the error output and do not treat the file as a boot image. Check the requested version without changing anything:
$ printf 'running: '; uname -r
running: 6.8.0-XX-generic
$ test -d "/lib/modules/$(uname -r)" && echo 'module directory exists'
module directory exists
XX above only stands in for illustration. In a real command, use the value uname -r actually prints; never type a guessed kernel version.
3. Understand the configuration that shapes the image
The main configuration file is /etc/initramfs-tools/initramfs.conf. Snippets in /etc/initramfs-tools/conf.d are read afterwards, so a snippet can override the main file. Read the effective inputs before diagnosing an unexpected result:
$ sed -n '1,220p' /etc/initramfs-tools/initramfs.conf
$ find /etc/initramfs-tools/conf.d -maxdepth 1 -type f -print -exec sed -n '1,80p' {} \;
$ sed -n '1,120p' /etc/initramfs-tools/modules
MODULES=mostis the documented default and adds common filesystem and storage drivers.deptries to include only modules needed by the running machine.netbootadds base and network support while skipping block devices.listlimits extra modules to the explicitly listed set.
The modules file and files in /usr/share/initramfs-tools/modules.d are always included regardless of that setting. Other settings have real boot consequences too: BUSYBOX=n removes BusyBox even though many boot scripts need its utilities; RESUME=none disables hibernation resume, while an unset or auto value selects the largest available swap partition; FSTYPE=auto detects the current root and /usr filesystem types; and for an NFS root, BOOT=nfs plus the NFS variables select the network setup.
Do not edit the system configuration just to test one image. Use -c, -l, -r, or a whole alternate configuration tree with -d. Command-line overrides are easier to review and undo than a config file you might forget to revert.
4. Test compression without changing configuration
This machine's installed configuration uses COMPRESS=zstd, but you can override that for a single build:
out_lz4=$(mktemp /tmp/initramfs-lz4.XXXXXX.img)
mkinitramfs -c lz4 -l 1 -o "$out_lz4" "$(uname -r)"
printf 'exit status: %s\n' "$?"
file "$out_lz4"
-c selects the compression method and -l its level; the valid range depends on the compressor. If the kernel lacks support for the configured format, or the matching userspace utility is missing, the tool falls back to gzip according to initramfs.conf(5). Do not guess the format from the filename extension, inspect the file instead.
Tip
UMASK in the configuration controls permissions on the generated image and can stop embedded keys from being disclosed. Treat an initramfs as sensitive: it can contain credentials, keys or hardware-specific configuration.
5. Inspect the archive before using it
Use lsinitramfs to list the archive without unpacking it:
$ lsinitramfs "$out"
.
bin
bin/sh
conf
conf/arch.conf
conf/initramfs.conf
scripts
scripts/init-bottom
scripts/init-top
The exact list varies with the host, package version, kernel version and configuration, so look for the expected kernel modules, hooks and configuration rather than diffing the whole listing against a fixed transcript:
lsinitramfs "$out" | sed -n '1,80p'
lsinitramfs "$out" | grep -E '(^|/)(init|scripts|lib/modules/)' | sed -n '1,80p'
test -s "$out" && echo 'image is non-empty'
If the image is empty, missing, or is missing the drivers needed to reach the root filesystem, stop here. Recheck the kernel version, MODULES, the modules file and any configuration snippets. Do not compensate by copying random drivers into the archive.
6. Clean up or promote the result carefully
Once you have finished checking a scratch image, remove only the exact temporary paths you created:
$ rm -- "$out" "$out_lz4"
This is irreversible for those files, so verify the variables first with printf '%s\n' "$out" "$out_lz4". If you need a real boot image, the normal administration command is update-initramfs, which handles naming, hashes and backups for installed kernels. Do not copy a hand-built test image over an existing file unless you have a recovery path and have separately verified the target.
Checkpoint
A finished test has an exit status of zero, a non-empty archive, the intended kernel version, and a listing containing the expected early-boot files. The original files under /boot remain unchanged.
Common failure traps
- A missing output argument is a command-shape error, not a reason to edit configuration. Recheck
-oand quote paths containing spaces. - A successful build does not prove the machine can boot from it. Archive inspection checks contents; boot testing is a separate operational decision.
TMPDIRcontrols temporary build directories and defaults to/var/tmp. It must allow execution, so anoexecmount can make an otherwise valid build fail.-kkeeps the temporary build directory for debugging. It can contain sensitive material and consumes space, so use it deliberately and remove the exact retained directory after inspection.SOURCE_DATE_EPOCHmakes the tool attempt a reproducible image. Reproducibility does not make a mismatched kernel or incomplete driver set safe.
Done means
- You built to a new scratch path for an explicit kernel version.
- The command returned zero and produced a non-empty compressed cpio archive.
- You checked effective configuration, including later
conf.doverrides and requested modules. - You inspected the archive with
lsinitramfsand confirmed the expected early-boot content. - You left installed boot images untouched, or used the normal
update-initramfsworkflow with a recovery plan.