# EcoOS ISO Builder # Build from eco_os directory: # docker build -t ecoos-builder -f isobuild/Dockerfile . # docker run --privileged -v $(pwd)/isobuild/output:/output ecoos-builder FROM ubuntu:24.04 ENV DEBIAN_FRONTEND=noninteractive # Install build dependencies RUN apt-get update && apt-get install -y \ live-build \ debootstrap \ xorriso \ squashfs-tools \ grub-efi-amd64-bin \ grub-efi-amd64-signed \ grub-pc-bin \ shim-signed \ mtools \ dosfstools \ syslinux-utils \ syslinux \ syslinux-common \ isolinux \ curl \ unzip \ git \ && rm -rf /var/lib/apt/lists/* \ && ln -sf /usr/bin/isohybrid /usr/local/bin/isohybrid 2>/dev/null || true # Install Deno RUN curl -fsSL https://deno.land/install.sh | DENO_INSTALL=/usr/local sh # Create build directory WORKDIR /build # Copy isobuild configuration COPY isobuild/config/ /build/config/ COPY isobuild/scripts/ /build/scripts/ COPY isobuild/ts/ /build/ts/ COPY isobuild/deno.json /build/ COPY isobuild/mod.ts /build/ # Copy hooks to enable services (already in config/, but put in separate dir for build script) COPY isobuild/config/hooks/ /build/hooks/ # Copy daemon source (for bundling) COPY ecoos_daemon/ /daemon/ # Bundle the daemon RUN cd /daemon && deno compile --allow-all --output /build/daemon-bundle/eco-daemon mod.ts # Download Chromium during Docker build (network works here, not in chroot hooks) RUN echo "Downloading Chromium from official snapshots..." && \ cd /tmp && \ LATEST=$(curl -fsSL "https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/Linux_x64%2FLAST_CHANGE?alt=media" 2>/dev/null || echo "1368529") && \ echo "Using Chromium build: $LATEST" && \ curl -fsSL "https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/Linux_x64%2F${LATEST}%2Fchrome-linux.zip?alt=media" -o chromium.zip || \ curl -fsSL "https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/Linux_x64%2F1368529%2Fchrome-linux.zip?alt=media" -o chromium.zip && \ mkdir -p /build/chromium && \ unzip -q chromium.zip -d /tmp && \ mv /tmp/chrome-linux/* /build/chromium/ && \ rm -rf chromium.zip /tmp/chrome-linux && \ chmod +x /build/chromium/chrome && \ echo "Chromium downloaded to /build/chromium/" # Make scripts executable RUN chmod +x /build/scripts/*.sh # Create dummy isohybrid for UEFI-only builds (real isohybrid needs BIOS boot record) RUN echo '#!/bin/sh' > /usr/local/bin/isohybrid && \ echo 'echo "Skipping isohybrid (UEFI-only build)"' >> /usr/local/bin/isohybrid && \ echo 'exit 0' >> /usr/local/bin/isohybrid && \ chmod +x /usr/local/bin/isohybrid # Build script COPY <<'EOF' /build/docker-build.sh #!/bin/bash set -e export PATH="/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin:$PATH" echo "=== EcoOS ISO Builder (Docker) ===" cd /build # Initialize live-build - UEFI only (no syslinux/BIOS) # Using German mirror for faster/more stable downloads lb config \ --architectures amd64 \ --distribution noble \ --archive-areas "main restricted universe multiverse" \ --mirror-bootstrap "http://ftp.halifax.rwth-aachen.de/ubuntu/" \ --mirror-chroot "http://ftp.halifax.rwth-aachen.de/ubuntu/" \ --mirror-chroot-security "http://ftp.halifax.rwth-aachen.de/ubuntu/" \ --mirror-binary "http://ftp.halifax.rwth-aachen.de/ubuntu/" \ --mirror-binary-security "http://ftp.halifax.rwth-aachen.de/ubuntu/" \ --binary-images iso-hybrid \ --debian-installer false \ --memtest none \ --bootloader grub-efi \ --iso-application "EcoOS" \ --iso-publisher "EcoBridge" \ --iso-volume "EcoOS" # Copy package lists cp /build/config/live-build/package-lists/*.list.chroot config/package-lists/ # Prepare includes.chroot mkdir -p config/includes.chroot/opt/eco/bin mkdir -p config/includes.chroot/opt/eco/daemon mkdir -p config/includes.chroot/etc/systemd/system # Copy daemon bundle cp /build/daemon-bundle/eco-daemon config/includes.chroot/opt/eco/bin/ chmod +x config/includes.chroot/opt/eco/bin/eco-daemon # Copy pre-downloaded Chromium echo "Installing pre-downloaded Chromium into chroot..." mkdir -p config/includes.chroot/opt/chromium cp -r /build/chromium/* config/includes.chroot/opt/chromium/ chmod +x config/includes.chroot/opt/chromium/chrome # Create symlinks for chromium-browser command mkdir -p config/includes.chroot/usr/bin cat > config/includes.chroot/usr/bin/chromium-browser << 'CHROMEWRAPPER' #!/bin/sh exec /opt/chromium/chrome "$@" CHROMEWRAPPER chmod +x config/includes.chroot/usr/bin/chromium-browser ln -sf /opt/chromium/chrome config/includes.chroot/usr/bin/chromium echo "Chromium installed to /opt/chromium/" # Create dummy isohybrid in chroot (UEFI-only, no BIOS boot record) mkdir -p config/includes.chroot/usr/bin cat > config/includes.chroot/usr/bin/isohybrid << 'ISOHYBRID' #!/bin/sh echo "Skipping isohybrid (UEFI-only build)" exit 0 ISOHYBRID chmod +x config/includes.chroot/usr/bin/isohybrid # Copy systemd services cp /build/config/systemd/eco-daemon.service config/includes.chroot/etc/systemd/system/ # Copy installer (files are already in config/includes.chroot via COPY) chmod +x config/includes.chroot/opt/eco/installer/install.sh 2>/dev/null || true # Copy hooks to enable services mkdir -p config/hooks/normal cp /build/hooks/normal/*.hook.chroot config/hooks/normal/ chmod +x config/hooks/normal/*.hook.chroot # Copy autoinstall config mkdir -p config/includes.binary/autoinstall cp /build/config/autoinstall/user-data config/includes.binary/autoinstall/ touch config/includes.binary/autoinstall/meta-data # Prepare EFI boot files in includes.binary echo "Preparing EFI boot structure..." mkdir -p config/includes.binary/EFI/BOOT mkdir -p config/includes.binary/boot/grub # Copy signed EFI files from host (installed in Docker image) cp /usr/lib/shim/shimx64.efi.signed.latest config/includes.binary/EFI/BOOT/BOOTX64.EFI || \ cp /usr/lib/shim/shimx64.efi.signed config/includes.binary/EFI/BOOT/BOOTX64.EFI || \ cp /usr/lib/shim/shimx64.efi config/includes.binary/EFI/BOOT/BOOTX64.EFI || true cp /usr/lib/grub/x86_64-efi-signed/grubx64.efi.signed config/includes.binary/EFI/BOOT/grubx64.efi || \ cp /usr/lib/grub/x86_64-efi/grubx64.efi config/includes.binary/EFI/BOOT/grubx64.efi || true # Also provide mmx64.efi for some UEFI implementations if [ -f config/includes.binary/EFI/BOOT/grubx64.efi ]; then cp config/includes.binary/EFI/BOOT/grubx64.efi config/includes.binary/EFI/BOOT/mmx64.efi fi # Create grub.cfg for live boot with installer option cat > config/includes.binary/boot/grub/grub.cfg << 'GRUBCFG' set default=0 set timeout=10 insmod part_gpt insmod fat insmod efi_gop insmod efi_uga menuentry "Install EcoOS (auto-selects in 10s)" { linux /casper/vmlinuz boot=casper quiet splash ecoos_install=1 --- initrd /casper/initrd } menuentry "EcoOS Live (Try without installing)" { linux /casper/vmlinuz boot=casper quiet splash --- initrd /casper/initrd } menuentry "EcoOS Live (Safe Mode)" { linux /casper/vmlinuz boot=casper nomodeset --- initrd /casper/initrd } GRUBCFG # Also put grub.cfg in EFI/BOOT for fallback cp config/includes.binary/boot/grub/grub.cfg config/includes.binary/EFI/BOOT/grub.cfg # Build ISO - use individual lb stages to control the process lb bootstrap lb chroot # Try lb binary, but continue even if isohybrid fails lb binary || { echo "lb binary had errors, checking if ISO was created anyway..." if ls /build/*.iso 2>/dev/null; then echo "ISO exists despite errors, continuing..." else echo "No ISO found, build truly failed" exit 1 fi } # Check if EFI was created properly echo "Checking binary directory for EFI..." ls -la binary/EFI/BOOT/ 2>/dev/null || echo "EFI/BOOT not found in binary dir" # Find the ISO file echo "Searching for ISO file..." find /build -name "*.iso" -type f 2>/dev/null ls -la /build/*.iso 2>/dev/null || true ISO_FILE=$(find /build -name "*.iso" -type f 2>/dev/null | head -1) if [ -z "$ISO_FILE" ]; then echo "ERROR: No ISO file found in build directory" echo "Listing /build contents:" ls -la /build/ exit 1 fi echo "Found ISO: $ISO_FILE" # Always create proper EFI boot image and rebuild ISO echo "Creating UEFI-bootable ISO..." # Extract ISO contents mkdir -p /tmp/iso_extract xorriso -osirrox on -indev "$ISO_FILE" -extract / /tmp/iso_extract # Find the actual kernel and initrd names VMLINUZ=$(ls /tmp/iso_extract/casper/vmlinuz* 2>/dev/null | head -1 | xargs basename) INITRD=$(ls /tmp/iso_extract/casper/initrd* 2>/dev/null | head -1 | xargs basename) echo "Found kernel: $VMLINUZ, initrd: $INITRD" # Ensure EFI structure exists with proper files mkdir -p /tmp/iso_extract/EFI/BOOT mkdir -p /tmp/iso_extract/boot/grub # Copy EFI files from host cp /usr/lib/shim/shimx64.efi.signed.latest /tmp/iso_extract/EFI/BOOT/BOOTX64.EFI 2>/dev/null || \ cp /usr/lib/shim/shimx64.efi.signed /tmp/iso_extract/EFI/BOOT/BOOTX64.EFI 2>/dev/null || \ cp /usr/lib/shim/shimx64.efi /tmp/iso_extract/EFI/BOOT/BOOTX64.EFI 2>/dev/null || true cp /usr/lib/grub/x86_64-efi-signed/grubx64.efi.signed /tmp/iso_extract/EFI/BOOT/grubx64.efi 2>/dev/null || \ cp /usr/lib/grub/x86_64-efi/grubx64.efi /tmp/iso_extract/EFI/BOOT/grubx64.efi 2>/dev/null || true # Copy mmx64.efi for secure boot compatibility if [ -f /tmp/iso_extract/EFI/BOOT/grubx64.efi ]; then cp /tmp/iso_extract/EFI/BOOT/grubx64.efi /tmp/iso_extract/EFI/BOOT/mmx64.efi fi # Create grub.cfg with correct filenames and installer option cat > /tmp/iso_extract/boot/grub/grub.cfg << GRUBCFG2 set default=0 set timeout=10 insmod part_gpt insmod fat insmod efi_gop insmod efi_uga menuentry "Install EcoOS (auto-selects in 10s)" { linux /casper/${VMLINUZ} boot=casper quiet splash ecoos_install=1 --- initrd /casper/${INITRD} } menuentry "EcoOS Live (Try without installing)" { linux /casper/${VMLINUZ} boot=casper quiet splash --- initrd /casper/${INITRD} } menuentry "EcoOS Live (Safe Mode)" { linux /casper/${VMLINUZ} boot=casper nomodeset --- initrd /casper/${INITRD} } GRUBCFG2 cp /tmp/iso_extract/boot/grub/grub.cfg /tmp/iso_extract/EFI/BOOT/grub.cfg # Create EFI boot image (FAT filesystem for UEFI El Torito boot) echo "Creating EFI boot image..." dd if=/dev/zero of=/tmp/efi.img bs=1M count=10 mkfs.fat -F 12 /tmp/efi.img mmd -i /tmp/efi.img ::/EFI mmd -i /tmp/efi.img ::/EFI/BOOT mcopy -i /tmp/efi.img /tmp/iso_extract/EFI/BOOT/BOOTX64.EFI ::/EFI/BOOT/ mcopy -i /tmp/efi.img /tmp/iso_extract/EFI/BOOT/grubx64.efi ::/EFI/BOOT/ 2>/dev/null || true mcopy -i /tmp/efi.img /tmp/iso_extract/EFI/BOOT/mmx64.efi ::/EFI/BOOT/ 2>/dev/null || true mcopy -i /tmp/efi.img /tmp/iso_extract/EFI/BOOT/grub.cfg ::/EFI/BOOT/ # Rebuild ISO with EFI boot support (UEFI-only, no BIOS boot) echo "Rebuilding ISO with UEFI boot support..." xorriso -as mkisofs \ -r -V "EcoOS" \ -o /tmp/ecoos-efi.iso \ -J -joliet-long \ -eltorito-alt-boot \ -e --interval:appended_partition_2:all:: \ -no-emul-boot -isohybrid-gpt-basdat \ -append_partition 2 0xef /tmp/efi.img \ /tmp/iso_extract if [ -f /tmp/ecoos-efi.iso ]; then ISO_FILE=/tmp/ecoos-efi.iso echo "Created UEFI-bootable ISO: $ISO_FILE" else echo "ERROR: Failed to create EFI ISO" exit 1 fi rm -rf /tmp/iso_extract # Copy to output mkdir -p /output cp "$ISO_FILE" /output/ecoos.iso # Final verification echo "" echo "=== Final ISO EFI check ===" xorriso -indev /output/ecoos.iso -find / -maxdepth 2 -type d 2>/dev/null || true echo "" echo "=== Build Complete ===" echo "ISO: /output/ecoos.iso" ls -lh /output/ecoos.iso EOF RUN chmod +x /build/docker-build.sh CMD ["/build/docker-build.sh"]