Skip to content

How to create a customized bootable and automated debian install ?

Official documentation

Quick overview of the ISO creation process

We are making a initrd preseed configuration which means that upon boot, we'll select "Install" and not "Automated install".

  1. We start by using an official image
  2. We extract the image
  3. Create and modify the preseed configuration
  4. We modify the init ram disk (initrd) to add the preseed
  5. We repack everything into a new ISO

Everything is done using the Gitlab CI. It also can be done directly with docker.

Detailed process

The following script has to be run on a debian based system. However, it can be run in a dockerized environment (such as Gitlab CI with the debian:11.7 image)


export ORIGINAL_ISO=firmware-11.7.0-amd64-netinst.iso
export REMASTERED_ISO=customized-11.7.0-amd64-netinst.iso

# 1. Download the original ISO image:
# This command downloads the official Debian ISO image from the specified URL
# and saves it as the file defined in the `ORIGINAL_ISO` variable.

# 2. Extract the ISO image:
# This command creates a new directory called `isofiles` and extracts the 
# contents of the original ISO image into it using the `xorriso` tool.
mkdir isofiles
xorriso -osirrox on -indev $ORIGINAL_ISO -extract / isofiles/

# 3. Modify the initrd (initial ramdisk):
# These commands make the `install.amd` directory writable, decompress the 
# `initrd.gz` file, add the `preseed.cfg` file to the initrd using the `cpio` 
# command, compress the initrd back into a `.gz` file, and make the 
# `install.amd` directory read-only again.
chmod +w -R isofiles/install.amd/
gunzip isofiles/install.amd/initrd.gz
echo preseed.cfg | cpio -H newc -o -A -F isofiles/install.amd/initrd
gzip isofiles/install.amd/initrd
chmod -w -R isofiles/install.amd/

# 4. Update the MD5 checksums:
cd isofiles && find -follow -type f ! -name md5sum.txt -print0 | xargs -0 md5sum > md5sum.txt
chmod -w md5sum.txt
cd ..

# 5. Extract the isohdpfx.bin file from the original iso:
# This command uses the `dd` tool to extract the first 432 bytes of the original 
# ISO image and save them as the `isohdpfx.bin` file, which is required for
# creating a bootable ISO image.
dd if=$ORIGINAL_ISO bs=1 count=432 of=isohdpfx.bin

# 6. Create the customized ISO image:
# This command uses the `xorriso` tool to create a new ISO image with the 
# modified initrd and preseed configuration. It sets various options,
# such as the volume label, output file name, checksum algorithms, and boot 
# options, to ensure the resulting ISO image is bootable and compatible 
# with different systems.
mkdir -p public/
xorriso -as mkisofs \
        -r -checksum_algorithm_iso sha256,sha512 \
        -V 'Debian 11.7.0 amd64 n' \
        -o public/$REMASTERED_ISO \
        -J \
        -joliet-long \
        -cache-inodes \
        -isohybrid-mbr isohdpfx.bin \
        -b isolinux/isolinux.bin \
        -c isolinux/ \
        -boot-load-size 4 \
        -boot-info-table \
        -no-emul-boot \
        -eltorito-alt-boot \
        -e boot/grub/efi.img \
        -no-emul-boot \
        -isohybrid-gpt-basdat \
        -isohybrid-apm-hfsplus isofiles

# 7. Clean up:
rm -r isofiles

The new iso image is available in the ./public/ directory

You can now flash your USB pen as usual

sudo dd if=customized-11.7.0-amd64-netinst.iso of=/dev/<your usb disk>

Cheat sheet

Generate an encrypted password for users

openssl passwd -6

Preseed keyboard configuration for french people

d-i keyboard-configuration/xkb-keymap select fr(latin9)

Add post-install external script

d-i preseed/late_command string in-target wget https://<your-host>/ ; in-target /bin/bash

A configuration example

# Debian autoinstaller configuration file

# Localization
d-i debian-installer/language string fr
d-i debian-installer/country string FR
d-i debian-installer/locale string fr_FR.UTF-8

# Keyboard selection.
d-i keyboard-configuration/xkb-keymap select fr(latin9)

# Network configuration
d-i netcfg/choose_interface select eno1
d-i netcfg/link_wait_timeout string 5
d-i netcfg/dhcp_timeout string 60

d-i netcfg/get_domain string

# Users and passwords
# replace XXXXX by the output of the command openssl -6
d-i passwd/root-password-crypted password XXXXXXXX
d-i passwd/make-user boolean true
d-i passwd/user-fullname string debian
d-i passwd/username string debian
d-i passwd/user-password-crypted password XXXXX
d-i passwd/user-default-groups string sudo audio cdrom video

# Clock is UTC
d-i clock-setup/utc boolean true
d-i time/zone string UTC

# Partitioning
d-i partman-auto/method string regular
d-i partman-auto/disk string /dev/nvme0n1
d-i partman-auto/choose_recipe select atomic
d-i partman-partitioning/confirm_write_new_label boolean true
d-i partman/choose_partition select finish
d-i partman/confirm boolean true

d-i partman-efi/non_efi_system boolean true

d-i apt-setup/local0/repository string bullseye main contrib non-free

# Package selection
tasksel tasksel/first multiselect standard

d-i pkgsel/include string openssh-server build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev libsqlite3-dev wget libbz2-dev python3 sudo wget

# Mirror settings
d-i mirror/country string France
d-i mirror/http/hostname string
d-i mirror/http/directory string /debian
d-i mirror/http/proxy string

# Popularity contest
popularity-contest popularity-contest/participate boolean false

d-i apt-setup/cdrom/set-first boolean false

d-i preseed/late_command string in-target wget https://<your-host>/ ; in-target /bin/bash

Discover more content ?

Do you want to learn more and faster with dense and tailored technical resources ?

Advanced Stack