Skip to content

Instantly share code, notes, and snippets.

@olafdietsche
Last active December 26, 2025 21:04
Show Gist options
  • Select an option

  • Save olafdietsche/d0fd494d6f8f63e5fb0d9740ae16ee0d to your computer and use it in GitHub Desktop.

Select an option

Save olafdietsche/d0fd494d6f8f63e5fb0d9740ae16ee0d to your computer and use it in GitHub Desktop.
Create a minimal debian image
#! /bin/bash
#
# usage: TMPDIR=/path/to/tmp bash $0 <image-path> <debian-release> [<debian-mirror>]
# sudo TMPDIR=/path/to/tmp bash build-image.sh /path/to/file.img trixie "file:///path/to/mirror-debian"
# sudo TMPDIR=/path/to/tmp bash build-image.sh /dev/sdx trixie
usage()
{
echo "usage: $0 <image-file/block-device> <debian-release> <debian-mirror>" >&2
exit 2
}
if test $# -lt 1 -o $# -gt 3; then
usage
fi
set -x
set -e
PS4='+ [$(date +"%Y-%m-%d %H:%M:%S.%N")] ${BASH_SOURCE}(${LINENO}) rc=$? '
cleanup()
{
set +e
mountpoint --quiet "${rootdir}/proc" && umount "${rootdir}/proc"
mountpoint --quiet "${rootdir}/sys/firmware/efi/efivars" && umount "${rootdir}/sys/firmware/efi/efivars"
mountpoint --quiet "${rootdir}/sys" && umount "${rootdir}/sys"
mountpoint --quiet "${rootdir}/dev/pts" && umount "${rootdir}/dev/pts"
mountpoint --quiet "${rootdir}/dev" && umount "${rootdir}/dev"
mountpoint --quiet "${rootdir}/boot/efi" && umount "${rootdir}/boot/efi"
mountpoint --quiet "${rootdir}" && umount "${rootdir}"
partx --delete "${partition_efi}"
partx --delete "${partition_lx}"
losetup --detach "${block_device}"
rmdir "${rootdir}"
}
image_path="$1"
rootdir="$(mktemp -d)"
trap "cleanup" exit
debian_release="$2"
debian_mirror="$3"
# create partitions
sfdisk "${image_path}" <<EOF
label: dos
type=uefi size=128m
type=linux
EOF
# setup block device
if test -f "${image_path}"; then
block_device=$(losetup --show --partscan --find "${image_path}")
elif test -b "${image_path}"; then
block_device="${image_path}"
else
echo "${image_path}: not a regular file or block device" >&2
usage
fi
{
read -r partition_efi
read -r partition_lx
} < <(lsblk --noheadings --output=type,path --sort=path "${block_device}" | awk '$1 == "part" {print $2;}')
mkfs -t vfat -F 32 "${partition_efi}"
mkfs -t ext2 -T big "${partition_lx}"
mount "${partition_lx}" "${rootdir}"
mkdir -p "${rootdir}/boot/efi"
mount "${partition_efi}" "${rootdir}/boot/efi"
base_packages="linux-image-amd64,grub-efi,locales,console-setup,zstd,iputils-ping,iproute2,isc-dhcp-client,less,sudo,lsof"
systemd_packages="dbus,systemd-resolved,systemd-sysv"
init_packages="${systemd_packages}"
sysvinit_packages="sysvinit-core,systemd-standalone-sysusers"
# init_packages="${sysvinit_packages}"
system_packages="mdadm,cryptsetup,smartmontools,fdisk,lvm2,e2fsprogs,udev"
server_packages="openssh-server,openssh-sftp-server,cifs-utils,rsync"
all_packages="${base_packages},${init_packages},${system_packages},${server_packages}"
debootstrap --variant=minbase --include="${all_packages}" "${debian_release}" "${rootdir}" ${debian_mirror}
mountpoint --quiet "${rootdir}/proc" || mount -t proc none "${rootdir}/proc"
mountpoint --quiet "${rootdir}/sys" || mount -t sysfs none "${rootdir}/sys"
mountpoint --quiet "${rootdir}/dev" || mount -t devtmpfs none "${rootdir}/dev"
mountpoint --quiet "${rootdir}/dev/pts" || mount -t devpts none "${rootdir}/dev/pts"
timezone="Europe/Berlin"
rm -f "${rootdir}/etc/localtime"; ln -s "/usr/share/zoneinfo/${timezone}" "${rootdir}/etc/localtime"
echo "${timezone}" >"${rootdir}/etc/timezone"
cat >>"${rootdir}/etc/initramfs-tools/initramfs.conf" <<EOF
#
# KEYMAP: [ y | n ]
#
# Load a keymap during the initramfs stage.
#
KEYMAP=y
EOF
cat >"${rootdir}/etc/default/keyboard" <<EOF
XKBMODEL="pc105"
XKBLAYOUT="de"
XKBVARIANT="nodeadkeys"
XKBOPTIONS=""
EOF
cat >"${rootdir}/etc/systemd/network/lan.network" <<EOF
[Match]
Name=en*
[Network]
DHCP=yes
EOF
echo host01 >"${rootdir}/etc/hostname"
# passwd root
# password=debian
# openssl passwd -5 debian
hashed_password='$5$3z53yQfW5Y0BMzTt$O8UD2LG.hx6HG.ory05S/k8wrBwc6TPDdVagRJE1hN1'
usermod --root "${rootdir}" --password "${hashed_password}" root
# adduser olaf
# password=olaf
# openssl passwd -5 olaf
hashed_password='$5$CIC5d4a1IsXfW59W$vApq7IsiWYeJnPN/lp025cYBE/alDqG1A91trATdJjB'
useradd --root "${rootdir}" --password "${hashed_password}" --create-home --user-group --groups sudo olaf
# fetch uuid of root partition
uuid=$(lsblk --noheadings --output mountpoint,uuid | awk '$1 == "'"${rootdir}"'" {print $2;}')
# make /var (root) writable
echo "UUID=${uuid} / ext2 errors=remount-ro,rw 0 1" >>"${rootdir}/etc/fstab"
# inside chroot
cat >"${rootdir}/tmp/setup.sh" <<EOF
grub-install --target x86_64-efi --removable "${block_device}"
grub-mkconfig -o /boot/grub/grub.cfg
locale-gen de_DE.UTF-8
locale-gen en_US.UTF-8
systemctl enable systemd-networkd.service systemd-resolved.service
update-initramfs -u
apt-get clean
rm /var/lib/apt/lists/*_Release /var/lib/apt/lists/*_Packages
rm /var/cache/debconf/*
EOF
chroot "${rootdir}" sh -x /tmp/setup.sh
rm -f "${rootdir}/tmp/setup.sh"
# eof chroot
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment