Created
July 17, 2025 13:25
-
-
Save FalconNL93/b3709ac77248801fdc6b65a07bee458c to your computer and use it in GitHub Desktop.
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
| #!/bin/bash | |
| set -euo pipefail | |
| ISO_ORIG="$HOME/Dev/ISO/debian-12.11.0-amd64-netinst.iso" | |
| ISO_NEW="$HOME/Dev/ISO/debian-12.11.0-amd64-unattended-cloudinit.iso" | |
| PRESEED_FILE="$(pwd)/preseed.cfg" | |
| WORKDIR="$HOME/Dev/ISO/Debian/iso-work" | |
| ISO_MOUNT="$HOME/Dev/ISO/Debian/iso-mount" | |
| REMOTE_USER="" | |
| REMOTE_HOST="" | |
| REMOTE_PATH="/var/lib/vz/template/iso" | |
| # Ensure required packages are installed | |
| ensure_packages_installed() { | |
| local packages=(gzip cpio rsync xorriso qemu-system-x86) | |
| local missing=() | |
| for pkg in "${packages[@]}"; do | |
| if ! command -v "$pkg" &>/dev/null && ! rpm -q "$pkg" &>/dev/null; then | |
| missing+=("$pkg") | |
| fi | |
| done | |
| if [ ${#missing[@]} -gt 0 ]; then | |
| echo "[*] Installing missing packages: ${missing[*]}..." | |
| if [ -f /etc/os-release ]; then | |
| . /etc/os-release | |
| ID_LIKE=${ID_LIKE:-""} # Ensure ID_LIKE is defined | |
| if [[ "$ID" =~ ^(ubuntu|debian)$ || "$ID_LIKE" == *"debian"* ]]; then | |
| sudo apt update && sudo apt install -y "${missing[@]}" | |
| elif [[ "$ID" =~ ^(fedora|rhel|centos)$ || "$ID_LIKE" == *"rhel"* ]]; then | |
| sudo dnf install -y "${missing[@]}" | |
| elif [[ "$ID" == "arch" || "$ID_LIKE" == *"arch"* ]]; then | |
| sudo pacman -Sy --noconfirm "${missing[@]}" | |
| else | |
| echo "Unsupported OS. Please install: ${missing[*]} manually." | |
| exit 1 | |
| fi | |
| else | |
| echo "Unable to detect OS. Please install: ${missing[*]} manually." | |
| exit 1 | |
| fi | |
| else | |
| echo "[*] All required packages are already installed." | |
| fi | |
| } | |
| # Call the function at the start of the script | |
| ensure_packages_installed | |
| # Check required files | |
| check_required_files() { | |
| echo "[*] Checking required files..." | |
| [[ -f "$ISO_ORIG" ]] || { echo "ERROR: ISO file not found: $ISO_ORIG"; exit 1; } | |
| [[ -f "$PRESEED_FILE" ]] || { echo "ERROR: Preseed file not found in current directory."; exit 1; } | |
| } | |
| check_required_files | |
| # Clean up old work directories and ISO | |
| cleanup_old_files() { | |
| echo "[*] Cleaning up old work dirs and ISO..." | |
| sudo rm -rf "$WORKDIR" "$ISO_MOUNT" "$ISO_NEW" | |
| mkdir -p "$WORKDIR" "$ISO_MOUNT" | |
| } | |
| cleanup_old_files | |
| # Cleanup function for unmounting and stopping VM | |
| cleanup() { | |
| if mountpoint -q "$ISO_MOUNT"; then | |
| echo "[*] Unmounting ISO..." | |
| sudo umount "$ISO_MOUNT" | |
| fi | |
| if pgrep -f "debian12" > /dev/null; then | |
| echo "[*] Stopping KVM VM 'debian12'..." | |
| pkill -f "debian12" | |
| sleep 2 | |
| fi | |
| if [ -f "$WORKDIR/debian12.qcow2" ]; then | |
| echo "[*] Removing virtual drive: $WORKDIR/debian12.qcow2..." | |
| rm -f "$WORKDIR/debian12.qcow2" | |
| fi | |
| } | |
| trap cleanup EXIT | |
| # Mount original ISO | |
| mount_iso() { | |
| echo "[*] Mounting original ISO..." | |
| sudo mount -o loop "$ISO_ORIG" "$ISO_MOUNT" | |
| } | |
| mount_iso | |
| # Copy ISO contents | |
| copy_iso_contents() { | |
| echo "[*] Copying ISO contents..." | |
| rsync -a -H --no-owner --no-group --exclude=TRANS.TBL \ | |
| --chmod=Du=rwx,Dgo=rx,Fu=rw,Fgo=r \ | |
| "$ISO_MOUNT/" "$WORKDIR/" | |
| sudo umount "$ISO_MOUNT" | |
| } | |
| copy_iso_contents | |
| # Embed preseed.cfg inside initrd.gz | |
| embed_preseed() { | |
| echo "[*] Embedding preseed.cfg inside initrd.gz..." | |
| mkdir -p /tmp/initrd-extract | |
| cd /tmp/initrd-extract | |
| gzip -dc "$WORKDIR/install.amd/initrd.gz" | \ | |
| cpio --quiet --extract --make-directories --no-absolute-filenames --no-preserve-owner 2>/dev/null || true | |
| cp "$PRESEED_FILE" ./preseed.cfg | |
| (find . | cpio --quiet --create --format='newc' | gzip -9 > "$WORKDIR/install.amd/initrd.gz") || true | |
| cd - | |
| rm -rf /tmp/initrd-extract | |
| } | |
| embed_preseed | |
| # Copy scripts to ISO work directory | |
| copy_scripts() { | |
| echo "[*] Copying scripts to the ISO work directory for preseed usage..." | |
| SCRIPTS_DIR="$(pwd)/scripts" | |
| if [ -d "$SCRIPTS_DIR" ]; then | |
| cp -r "$SCRIPTS_DIR" "$WORKDIR/media" | |
| else | |
| echo "[!] Scripts directory not found: $SCRIPTS_DIR" | |
| exit 1 | |
| fi | |
| } | |
| copy_scripts | |
| # Add boot entry and set default | |
| configure_boot_menu() { | |
| echo "[*] Adding 'Automated Install' boot entry to txt.cfg..." | |
| cat <<EOF >> "$WORKDIR/isolinux/txt.cfg" | |
| label auto | |
| menu label ^Automated Install | |
| kernel /install.amd/vmlinuz | |
| append vga=788 initrd=/install.amd/initrd.gz auto priority=critical preseed/file=/preseed.cfg --- quiet | |
| EOF | |
| echo "[*] Setting 'auto' as default boot option in isolinux.cfg..." | |
| sed -i 's/^default .*/default auto/' "$WORKDIR/isolinux/isolinux.cfg" | |
| } | |
| configure_boot_menu | |
| # Fix MD5 checksums | |
| fix_checksums() { | |
| echo "[*] Fixing MD5 checksums..." | |
| pushd "$WORKDIR" > /dev/null | |
| md5sum $(find -type f) > md5sum.txt | |
| popd > /dev/null | |
| } | |
| fix_checksums | |
| # Build new ISO using xorriso | |
| build_iso() { | |
| echo "[*] Building new ISO..." | |
| xorriso -as mkisofs \ | |
| -o "$ISO_NEW" \ | |
| -r -J -joliet-long \ | |
| -V "Debian 12.11.0 amd64 n" \ | |
| -b isolinux/isolinux.bin \ | |
| -c isolinux/boot.cat \ | |
| -no-emul-boot -boot-load-size 4 -boot-info-table \ | |
| -eltorito-alt-boot \ | |
| -e boot/grub/efi.img \ | |
| -no-emul-boot \ | |
| "$WORKDIR" | |
| } | |
| build_iso | |
| # Create virtual drive only when running KVM test | |
| create_virtual_drive() { | |
| echo "[*] Creating a 20 GB virtual drive for Debian installation..." | |
| DRIVE_FILE="$WORKDIR/debian12.qcow2" | |
| if [ ! -f "$DRIVE_FILE" ]; then | |
| qemu-img create -f qcow2 "$DRIVE_FILE" 20G | |
| else | |
| echo "[*] Virtual drive already exists: $DRIVE_FILE" | |
| fi | |
| } | |
| # Start KVM test boot | |
| start_kvm_test() { | |
| echo "[*] Starting KVM test boot (debian12)..." | |
| create_virtual_drive | |
| qemu-system-x86_64 \ | |
| -name debian12 \ | |
| -m 2048 \ | |
| -smp 2 \ | |
| -cdrom "$ISO_NEW" \ | |
| -boot d \ | |
| -drive file="$WORKDIR/debian12.qcow2",format=qcow2 \ | |
| -netdev user,id=net0,hostfwd=tcp::2222-:22 \ | |
| -device e1000,netdev=net0 \ | |
| -display gtk \ | |
| -enable-kvm | |
| } | |
| # Parse command-line arguments | |
| RUN_KVM_TEST=false | |
| UPLOAD_TO_PROXMOX=false | |
| for arg in "$@"; do | |
| case $arg in | |
| --run) | |
| RUN_KVM_TEST=true | |
| shift | |
| ;; | |
| --upload) | |
| UPLOAD_TO_PROXMOX=true | |
| shift | |
| ;; | |
| *) | |
| echo "[!] Unknown argument: $arg" | |
| exit 1 | |
| ;; | |
| esac | |
| done | |
| # Start KVM test boot if --run is provided | |
| if [ "$RUN_KVM_TEST" = true ]; then | |
| start_kvm_test | |
| fi | |
| # Upload to Proxmox if --upload is provided | |
| if [ "$UPLOAD_TO_PROXMOX" = true ]; then | |
| upload_to_proxmox | |
| fi | |
| echo "[+] ISO creation and setup completed." |
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
| # Locale | |
| d-i debian-installer/locale string en_US.UTF-8 | |
| d-i debian-installer/language string en | |
| d-i debian-installer/country string NL | |
| d-i localechooser/supported-locales multiselect en_US.UTF-8 | |
| d-i time/zone string Europe/Amsterdam | |
| # Keyboard | |
| d-i console-setup/ask_detect boolean false | |
| d-i keyboard-configuration/modelcode string pc105 | |
| d-i keyboard-configuration/layoutcode string us | |
| d-i keyboard-configuration/variantcode string | |
| d-i keyboard-configuration/unsupported_layout boolean true | |
| d-i keyboard-configuration/xkb-keymap select us | |
| # Network | |
| d-i netcfg/choose_interface select auto | |
| d-i netcfg/get_hostname string debian | |
| d-i netcfg/get_domain string local | |
| # Mirror | |
| d-i mirror/country string manual | |
| d-i mirror/http/hostname string deb.debian.org | |
| d-i mirror/http/directory string /debian | |
| d-i mirror/http/proxy string | |
| # Root | |
| d-i passwd/root-password password changeme | |
| d-i passwd/root-password-again password changeme | |
| d-i passwd/make-user boolean false | |
| # Partitioning | |
| d-i partman-auto/method string regular | |
| d-i partman-auto/expert_recipe string custom :: \ | |
| 1000 10000 100000000 ext4 \ | |
| $primary{ } $bootable{ } \ | |
| method{ format } format{ } \ | |
| use_filesystem{ } filesystem{ ext4 } \ | |
| mountpoint{ / } \ | |
| . \ | |
| 500 10000 100000000 linux-swap \ | |
| method{ swap } format{ } \ | |
| . | |
| # Use GPT partitioning scheme | |
| d-i partman-partitioning/default_label string gpt | |
| # Automatically confirm partitioning | |
| d-i partman/confirm_write_new_label boolean true | |
| d-i partman/confirm boolean true | |
| d-i partman/confirm_nooverwrite boolean true | |
| # Automatically finish partitioning | |
| d-i partman/choose_partition select finish | |
| d-i partman/finish_partitioning boolean true | |
| d-i partman/commit boolean true | |
| # Package Selection | |
| tasksel tasksel/first multiselect standard, ssh-server | |
| d-i pkgsel/include string sudo curl git cloud-init | |
| popularity-contest popularity-contest/participate boolean false | |
| # Skip media scanning dialog | |
| d-i cdrom-detect/eject boolean false | |
| d-i apt-setup/cdrom/set-first boolean false | |
| d-i apt-setup/disable-cdrom-entries boolean true | |
| # GRUB Bootloader | |
| d-i grub-installer/only_debian boolean true | |
| d-i grub-installer/with_other_os boolean true | |
| # Automatically install GRUB on the primary drive | |
| d-i grub-installer/bootdev string /dev/sda | |
| # Reboot After Install | |
| d-i finish-install/reboot_in_progress note | |
| d-i cdrom-detect/eject boolean false | |
| # Debug Preseed Loading Confirmation | |
| d-i preseed/early_command string echo '>>> Preseed loaded successfully' > /dev/console | |
| # Late Command | |
| d-i preseed/late_command string \ | |
| in-target systemctl enable ssh; \ | |
| in-target sed -i 's/preserve_hostname: true/preserve_hostname: false/' /etc/cloud/cloud.cfg; \ | |
| in-target cloud-init clean --logs; \ | |
| in-target cp /media/post_boot.sh /root/post_boot.sh; \ | |
| in-target chmod +x /root/post_boot.sh; \ | |
| in-target echo "@reboot root /root/post_boot.sh" >> /etc/crontab |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment