Last active
October 17, 2025 13:49
-
-
Save jeffangelion/f666fef66b2cf5a6c0b88915964addcd to your computer and use it in GitHub Desktop.
WIP: automated script for including custom packages in Debian ISO without network mirror/preseed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| # Sources: | |
| # https://wiki.debian.org/DebianInstaller/Modify/CD | |
| # https://wiki.debian.org/RepackBootableISO | |
| # Variables | |
| needed_packages='ifenslave sudo' | |
| mirror_url='http://[FQDN]/debian' | |
| mirror_components='main' | |
| #orig_iso="$HOME"/debian-12.12.0-amd64-netinst.iso | |
| #new_files="$HOME"/bookworm-modified | |
| #iso_label='Debian 12.12.0 amd64 n' | |
| apt_cache_dir="$HOME"/apt-cache | |
| config_deb="$HOME"/config-deb | |
| indices_dir="$HOME"/indices | |
| #debian_release=bookworm | |
| #new_iso="$HOME"/debian-12.12.0-amd64-modified.iso | |
| mbr_template="$HOME"/isohdpfx.bin | |
| # Split needed_packages string by whitespaces with 'read -a' and here-string (<<<) | |
| read -ra needed_packages <<< "$needed_packages" | |
| # Extract MBR template file to disk | |
| printf '\033[0;33mExtracting MBR from %s\033[0m\n' "$orig_iso" | |
| dd if="$orig_iso" bs=432 count=1 of="$mbr_template" &>/dev/null | |
| # Extract orig_iso files to new_files | |
| # TODO: better cleanup before extracting | |
| printf '\033[0;33mExtracting files from %s to %s\033[0m\n' "$orig_iso" "$new_files" | |
| mkdir -p "$new_files" | |
| rm -rf "${new_files:?}"/* &>/dev/null || true | |
| bsdtar -C "$new_files" -xf "$orig_iso" | |
| # TODO: get iso_label from "$new_files"/.disk/mkisofs | |
| # Make new_files content writable | |
| chmod -R +w "$new_files" | |
| # Create APT cache directory | |
| printf '\033[0;33mCreating temp APT cache directory: %s\033[0m\n' "$apt_cache_dir" | |
| mkdir -p "$apt_cache_dir" | |
| rm "${apt_cache_dir:?}"/* &>/dev/null || true | |
| # Create apt.conf | |
| cat >"$apt_cache_dir"/apt.conf << EOF | |
| pkgCacheGen::Essential="none"; | |
| Dir::Etc::sourcelist="$apt_cache_dir/sources.list"; | |
| Dir::Cache::archives="$apt_cache_dir"; | |
| Dir::Cache="$apt_cache_dir"; | |
| EOF | |
| # Create custom APT sources.list for needed_packages | |
| # TODO: add DEB882 support | |
| cat >"$apt_cache_dir"/sources.list << EOF | |
| deb $mirror_url $debian_release $mirror_components | |
| EOF | |
| # Populate APT cache | |
| printf '\033[0;33mPopulating APT cache\033[0m\n' | |
| apt update \ | |
| -o pkgCacheGen::Essential=none \ | |
| -o Dir::Etc::sourcelist="$apt_cache_dir"/sources.list \ | |
| -o Dir::Cache::archives="$apt_cache_dir" \ | |
| -o Dir::Cache="$apt_cache_dir" &>/dev/null | |
| # Download needed_packages | |
| # TODO: option for specifying network mirror? | |
| for i in "${needed_packages[@]}"; do | |
| printf '\033[0;33mDownloading custom package: %s\033[0m\n' "$i" | |
| # -c "$apt_cache_dir"/apt.conf | |
| apt install --download-only --reinstall -y "$i" \ | |
| -o pkgCacheGen::Essential=none \ | |
| -o Dir::Etc::sourcelist="$apt_cache_dir"/sources.list \ | |
| -o Dir::Cache::archives="$apt_cache_dir" \ | |
| -o Dir::Cache="$apt_cache_dir" &>/dev/null | |
| done | |
| #Repopulate APT cache after 'poisoning' it | |
| printf '\033[0;33mRepopulating APT cache\033[0m\n' | |
| apt update &>/dev/null | |
| # Create folder for needed_packages | |
| # TODO: place needed_packages to same paths as in network mirror? | |
| printf '\033[0;33mCreating pool directory for custom packages: %s\033[0m\n' "$new_files"/pool/main/custom | |
| mkdir -p "$new_files"/pool/main/custom | |
| # Move needed_packages to new_files | |
| printf '\033[0;33mMoving custom packages to pool\033[0m\n' | |
| mv "$apt_cache_dir"/*.deb "$new_files"/pool/main/custom | |
| # Generate override | |
| # By setting package priority to 'required', it will be installed by default | |
| # More: https://wiki.debian.org/FtpMaster/Override | |
| printf '\033[0;33mGenerating override file: %s\033[0m\n' "$indices_dir"/override | |
| mkdir -p "$indices_dir" | |
| rm -rf "${indices_dir:?}"/* | |
| for i in "${needed_packages[@]}"; do | |
| cat >>"$indices_dir"/override << EOF | |
| $i required admin | |
| EOF | |
| done | |
| # Generate config-deb | |
| printf '\033[0;33mGenerating config-deb: %s\033[0m\n' "$config_deb" | |
| cat >"$config_deb" << EOF | |
| Dir { | |
| ArchiveDir "$new_files"; | |
| OverrideDir "$indices_dir"; | |
| CacheDir "$indices_dir"; | |
| }; | |
| TreeDefault { | |
| Directory "pool/"; | |
| }; | |
| BinDirectory "pool/main" { | |
| Packages "dists/$debian_release/main/binary-amd64/Packages"; | |
| BinOverride "override"; | |
| }; | |
| Default { | |
| Packages { | |
| Extensions ".deb"; | |
| }; | |
| }; | |
| EOF | |
| # Generate Packages.gz file | |
| printf '\033[0;33mGenerating Packages.gz file\033[0m\n' | |
| apt-ftparchive generate "$config_deb" &>/dev/null | |
| # Generate Release file | |
| printf '\033[0;33mCalculating new checksums\033[0m\n' | |
| sed -i '/MD5Sum:/,$d' "$new_files"/dists/"$debian_release"/Release | |
| apt-ftparchive release "$new_files"/dists/"$debian_release" >> "$new_files"/dists/"$debian_release"/Release | |
| printf '\033[0;33mNOTE: "File system loop detected" is not an error\033[0m\n' | |
| # shellcheck disable=SC2046 | |
| md5sum $(find "$new_files" ! -name "md5sum.txt" ! -path "./isolinux/*" -follow -type f) > md5sum.txt | |
| # Make new_files content read-only | |
| chmod -R -w "$new_files" | |
| # Create the new ISO image | |
| printf '\033[0;33mCreating modified ISO: %s\033[0m\n' "$new_iso" | |
| xorriso -as mkisofs \ | |
| -r -V "$iso_label" \ | |
| -o "$new_iso" \ | |
| -J -joliet-long -cache-inodes \ | |
| -isohybrid-mbr "$mbr_template" \ | |
| -b isolinux/isolinux.bin \ | |
| -c isolinux/boot.cat \ | |
| -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 \ | |
| "$new_files" &>/dev/null | |
| printf '\033[0;32mModified ISO successfully created: %s\033[0m\n' "$new_iso" | |
| # Cleanup | |
| rm -rf "$new_files" | |
| rm -rf "$apt_cache_dir" | |
| rm "$config_deb" | |
| rm -rf "$indices_dir" | |
| rm "$mbr_template" | |
| exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment