home · contact · privacy
Script to set up minimal Debian inside new LVM.
authorPlom Heller <plom@plomlompom.com>
Mon, 24 Aug 2026 03:06:02 +0000 (05:06 +0200)
committerPlom Heller <plom@plomlompom.com>
Mon, 24 Aug 2026 03:06:02 +0000 (05:06 +0200)
install_debian.sh [new file with mode: 0755]

diff --git a/install_debian.sh b/install_debian.sh
new file mode 100755 (executable)
index 0000000..b3ca6e2
--- /dev/null
@@ -0,0 +1,118 @@
+#!/bin/sh
+set -Ceuvx
+
+die() {
+    echo "$*" >&2
+    exit 1
+}
+
+error() {
+    die "error: $*"
+}
+
+try_quiet() {
+    "$@" >/dev/null 2>&1
+}
+
+check_illegal_chars() {
+    case "$1" in *[!A-Za-z0-9_.-]*|"")
+        error "illegal characters in $2 '$1'" ;;
+    esac
+}
+
+# constants unlikely to change
+PATH_DEV=/dev
+NAME_ROOT=root
+PATH_EFI=/boot/efi
+NAME_INITRD=initrd.img
+NAME_VMLINUZ=vmlinuz
+
+# constants we might want to change at some point
+DEB_SUITE=trixie
+PATH_BOOT_DEVICE="${PATH_DEV}/nvme0n1"
+IDX_BOOT_PARTITION=1
+PATH_MNT=/mnt/debinst
+
+# sanity checks: required tools
+for CMD in debootstrap pvcreate vgcreate lvcreate vgs efibootmgr; do
+    try_quiet command -v "${CMD}"\
+        || error "required tool not found: ${CMD}"
+done
+
+# inputs to confirm
+[ $# -eq 3 ]\
+    || die "usage: $0 <partition> <volume-group-name> <boot-label>"
+PARTITION=$1
+NAME_VOLGROUP=$2
+BOOT_LABEL=$3
+
+# inputs sanity check: PARTITION
+[ -b "${PARTITION}" ]\
+    || error "${PARTITION} is not a block device"
+try_quiet findmnt --source "${PARTITION}"\
+    && error "${PARTITION} is already mounted"
+# inputs sanity check: NAME_VOLGROUP
+check_illegal_chars "${NAME_VOLGROUP}" "volume group name"
+try_quiet vgs "${NAME_VOLGROUP}" \
+    && error "volume group '${NAME_VOLGROUP}' already exists"
+# inputs sanity check: BOOT_LABEL
+check_illegal_chars "${BOOT_LABEL}" "boot label"
+[ -e "${PATH_EFI}/${BOOT_LABEL}" ] \
+    && error "${PATH_EFI}/${BOOT_LABEL} already exists"
+efibootmgr \
+    | sed -n 's/^Boot[0-9A-Fa-f]\{4\}\*\{0,1\} //p' \
+    | grep -Fxq "${BOOT_LABEL}" \
+    && error "an EFI boot entry named '${BOOT_LABEL}' already exists"
+
+# run inputs by user and ask for confirmation
+echo "\
+target partition: [${PARTITION}] \
+name for volume group: [${NAME_VOLGROUP}] \
+boot label: [${BOOT_LABEL}]"
+printf "\
+this will erase %s – type YES! (all caps, \
+with exclamation mark) to continue: " "${PARTITION}"
+read CONFIRM
+[ "${CONFIRM}" = 'YES!' ]\
+    || die "aborted: confirmation not given"
+
+# constants derived from changeables
+LOGVOL_ROOT="${PATH_DEV}/${NAME_VOLGROUP}/${NAME_ROOT}"
+PATH_EFI_BOOT_LABEL="${PATH_EFI}/${BOOT_LABEL}"
+DEV_SLAVE="${PATH_MNT}${PATH_DEV}"
+
+# set up LVM and filesystem
+pvcreate "${PARTITION}"
+vgcreate "${NAME_VOLGROUP}" "${PARTITION}"
+lvcreate -l '100%FREE' -n "${NAME_ROOT}" "${NAME_VOLGROUP}"
+mkfs.ext4 "${LOGVOL_ROOT}"
+
+# mount and install base
+mkdir -p "${PATH_MNT}"
+mount "${LOGVOL_ROOT}" "${PATH_MNT}"
+debootstrap "${DEB_SUITE}" "${PATH_MNT}"
+mount --rbind "${PATH_DEV}" "${DEV_SLAVE}"
+mount --make-rslave "${DEV_SLAVE}"
+
+# set up kernel, initrd, login
+LANG=C.UTF-8 chroot "${PATH_MNT}" /bin/sh -c "\
+    apt update &&\
+    apt install -y lvm2 linux-image-amd64 &&\
+    passwd"
+
+# install kernel and initrd into EFI tree/vars
+mkdir "${PATH_EFI_BOOT_LABEL}"
+for FILENAME in "${NAME_INITRD}" "${NAME_VMLINUZ}"; do
+    cp "${PATH_MNT}/${FILENAME}" "${PATH_EFI_BOOT_LABEL}/"
+done
+efibootmgr \
+    --create \
+    --disk "${PATH_BOOT_DEVICE}" \
+    --part "${IDX_BOOT_PARTITION}" \
+    --label "${BOOT_LABEL}" \
+    --loader "${BOOT_LABEL}/${NAME_VMLINUZ}" \
+    --unicode "root=${LOGVOL_ROOT} ro initrd=${BOOT_LABEL}\\${NAME_INITRD}"
+
+# clean up mounts
+umount -R "${DEV_SLAVE}"
+umount "${PATH_MNT}"