#!/bin/bash # Custom ISO builder that works on ARM Mac by modifying pre-built Alpine ISO # instead of building from scratch set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ALPINE_VERSION="${ALPINE_VERSION:-3.19}" ARCH="${ARCH:-x86_64}" ISO_URL="https://dl-cdn.alpinelinux.org/alpine/v${ALPINE_VERSION}/releases/${ARCH}/alpine-standard-${ALPINE_VERSION}.0-${ARCH}.iso" WORK_DIR="$SCRIPT_DIR/build/iso-custom" OUTPUT_DIR="$SCRIPT_DIR/results" echo "🏔️ Building custom Archipelago ISO from Alpine base" echo "" echo "📋 Configuration:" echo " Alpine Version: $ALPINE_VERSION" echo " Architecture: $ARCH" echo " Base ISO URL: $ISO_URL" echo "" # Create work directories mkdir -p "$WORK_DIR" mkdir -p "$OUTPUT_DIR" # Download Alpine base ISO if not exists BASE_ISO="$WORK_DIR/alpine-base.iso" if [ ! -f "$BASE_ISO" ]; then echo "📥 Downloading Alpine base ISO..." curl -L -o "$BASE_ISO" "$ISO_URL" || { echo "❌ Failed to download Alpine ISO" exit 1 } echo "✅ Downloaded base ISO" else echo "✅ Using cached base ISO" fi # Extract ISO contents echo "📦 Extracting ISO contents..." CUSTOM_DIR="$WORK_DIR/custom" rm -rf "$CUSTOM_DIR" mkdir -p "$CUSTOM_DIR" # Use 7zip to extract ISO (works on both macOS and Linux) if command -v 7z >/dev/null 2>&1; then 7z x "$BASE_ISO" -o"$CUSTOM_DIR" -y >/dev/null || { echo "❌ Failed to extract ISO with 7zip" exit 1 } elif [[ "$OSTYPE" == "darwin"* ]]; then # Fallback: Try mounting on macOS MOUNT_POINT="$WORK_DIR/mnt" mkdir -p "$MOUNT_POINT" hdiutil attach "$BASE_ISO" -mountpoint "$MOUNT_POINT" -readonly && { rsync -a "$MOUNT_POINT"/ "$CUSTOM_DIR"/ hdiutil detach "$MOUNT_POINT" } || { echo "❌ Failed to extract ISO. Install p7zip: brew install p7zip" exit 1 } else # On Linux, mount the ISO MOUNT_POINT="$WORK_DIR/mnt" mkdir -p "$MOUNT_POINT" sudo mount -o loop "$BASE_ISO" "$MOUNT_POINT" && { cp -a "$MOUNT_POINT"/* "$CUSTOM_DIR"/ sudo umount "$MOUNT_POINT" } || { echo "❌ Failed to mount ISO" exit 1 } fi echo "✅ ISO contents extracted" # Add custom packages echo "📦 Adding custom packages..." APKS_DIR="$CUSTOM_DIR/apks/$(uname -m)" mkdir -p "$APKS_DIR" # Create a custom apk repository file cat > "$CUSTOM_DIR/archipelago.list" <<'EOF' # Archipelago custom packages # These will be installed during setup-alpine or via apk add # Container runtime podman crun fuse-overlayfs slirp4netns # Web server nginx # SSH server openssh # Networking iptables iproute2 EOF # Create automated installation script echo "📝 Creating installation script..." mkdir -p "$CUSTOM_DIR/archipelago" cat > "$CUSTOM_DIR/archipelago/install.sh" <<'INSTALL_EOF' #!/bin/sh # Archipelago automated installation script set -e echo "🏝️ Installing Archipelago Bitcoin Node OS" echo "" # Install required packages echo "📦 Installing packages..." apk add --no-cache \ podman \ crun \ fuse-overlayfs \ slirp4netns \ nginx \ openssh \ iptables \ iproute2 \ bash \ curl # Create archipelago user echo "👤 Creating archipelago user..." if ! id archipelago >/dev/null 2>&1; then adduser -D -s /bin/bash archipelago echo "archipelago:archipelago" | chpasswd fi # Setup Podman for archipelago user echo "🐳 Setting up Podman..." mkdir -p /home/archipelago/.config/containers chown -R archipelago:archipelago /home/archipelago # Create data directories echo "📁 Creating data directories..." mkdir -p /var/lib/archipelago/{apps,secrets,logs,backups} chown -R archipelago:archipelago /var/lib/archipelago # Install Archipelago backend if available if [ -f /media/cdrom/archipelago/bin/archipelago ]; then echo "🦀 Installing Archipelago backend..." mkdir -p /usr/local/bin cp /media/cdrom/archipelago/bin/archipelago /usr/local/bin/ chmod +x /usr/local/bin/archipelago echo "✅ Backend installed" fi # Install Archipelago frontend if available if [ -d /media/cdrom/archipelago/web ]; then echo "🎨 Installing Archipelago web UI..." mkdir -p /usr/share/archipelago/web cp -r /media/cdrom/archipelago/web/* /usr/share/archipelago/web/ # Configure nginx cat > /etc/nginx/http.d/archipelago.conf <<'NGINX_EOF' server { listen 8100; server_name _; root /usr/share/archipelago/web; index index.html; location / { try_files $uri $uri/ /index.html; } # Proxy API requests to backend location /api/ { proxy_pass http://127.0.0.1:8101/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; } } NGINX_EOF rc-update add nginx default echo "✅ Web UI installed" fi # Create Archipelago service if [ -f /usr/local/bin/archipelago ]; then echo "⚙️ Creating Archipelago service..." cat > /etc/init.d/archipelago <<'SERVICE_EOF' #!/sbin/openrc-run name="Archipelago" description="Archipelago Bitcoin Node OS Backend" command="/usr/local/bin/archipelago" command_background=true pidfile="/run/archipelago.pid" depend() { need net after networking } SERVICE_EOF chmod +x /etc/init.d/archipelago rc-update add archipelago default echo "✅ Archipelago service created" fi # Install app manifests if available if [ -d /media/cdrom/archipelago/apps ]; then echo "📦 Installing app manifests..." mkdir -p /var/lib/archipelago/manifests cp -r /media/cdrom/archipelago/apps/* /var/lib/archipelago/manifests/ chown -R archipelago:archipelago /var/lib/archipelago/manifests echo "✅ App manifests installed" fi # Configure networking (DHCP) echo "🌐 Configuring network..." cat > /etc/network/interfaces <<'NET_EOF' auto lo iface lo inet loopback auto eth0 iface eth0 inet dhcp auto enp0s3 iface enp0s3 inet dhcp auto enp0s25 iface enp0s25 inet dhcp NET_EOF # Enable services echo "⚙️ Enabling services..." rc-update add networking default rc-update add sshd default rc-update add local default # Set hostname echo "archipelago" > /etc/hostname # Configure SSH echo "🔐 Configuring SSH..." sed -i 's/#PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config # Create welcome message cat > /etc/motd <<'MOTD_EOF' ╔═══════════════════════════════════════════════════════════╗ ║ ║ ║ 🏝️ ARCHIPELAGO BITCOIN NODE OS ║ ║ ║ ║ A sovereign computing platform built on Alpine Linux ║ ║ ║ ╚═══════════════════════════════════════════════════════════╝ Default user: archipelago Default pass: archipelago (CHANGE THIS IMMEDIATELY!) To access the web UI: http://$(hostname -i):8100 To start Archipelago: sudo systemctl start archipelago Documentation: /usr/share/doc/archipelago/ MOTD_EOF echo "" echo "✅ Archipelago installation complete!" echo "" echo "Next steps:" echo " 1. Reboot the system" echo " 2. Login with user: archipelago, pass: archipelago" echo " 3. Change the default password: passwd" echo " 4. Access web UI at http://:8100" echo "" INSTALL_EOF chmod +x "$CUSTOM_DIR/archipelago/install.sh" # Create README cat > "$CUSTOM_DIR/archipelago/README.txt" <<'README_EOF' ARCHIPELAGO BITCOIN NODE OS =========================== This is a customized Alpine Linux ISO with Archipelago packages. INSTALLATION: 1. Boot from this USB/ISO 2. Login as root (no password) 3. Run: setup-alpine 4. Follow the prompts to install Alpine 5. After installation, run: sh /media/*/archipelago/install.sh 6. Reboot QUICK INSTALL: For automated installation on dedicated hardware: 1. Boot from USB/ISO 2. Login as root 3. Run: sh /media/*/archipelago/install.sh 4. This will set up Alpine + Archipelago automatically For more information, visit: https://github.com/your-repo/archipelago README_EOF # Modify boot configuration to show Archipelago branding if [ -f "$CUSTOM_DIR/boot/grub/grub.cfg" ]; then echo "⚙️ Customizing boot menu..." sed -i.bak 's/Alpine Linux/Archipelago Bitcoin Node OS/g' "$CUSTOM_DIR/boot/grub/grub.cfg" 2>/dev/null || true fi if [ -f "$CUSTOM_DIR/boot/syslinux/syslinux.cfg" ]; then sed -i.bak 's/Alpine Linux/Archipelago Bitcoin Node OS/g' "$CUSTOM_DIR/boot/syslinux/syslinux.cfg" 2>/dev/null || true fi # Include Archipelago backend if available if [ -n "$INCLUDE_BACKEND" ] && [ -f "$INCLUDE_BACKEND" ]; then echo "🦀 Including Archipelago backend..." mkdir -p "$CUSTOM_DIR/archipelago/bin" cp "$INCLUDE_BACKEND" "$CUSTOM_DIR/archipelago/bin/" chmod +x "$CUSTOM_DIR/archipelago/bin/archipelago" echo "✅ Backend included: $(du -h "$INCLUDE_BACKEND" | cut -f1)" fi # Include Archipelago frontend if available if [ -n "$INCLUDE_FRONTEND" ] && [ -d "$INCLUDE_FRONTEND" ]; then echo "🎨 Including Archipelago frontend..." mkdir -p "$CUSTOM_DIR/archipelago/web" cp -r "$INCLUDE_FRONTEND"/* "$CUSTOM_DIR/archipelago/web/" echo "✅ Frontend included" fi # Include app manifests if available APPS_DIR="$(dirname "$0")/../apps" if [ -d "$APPS_DIR" ]; then echo "📦 Including app manifests..." mkdir -p "$CUSTOM_DIR/archipelago/apps" # Copy all app directories with manifest.yml files find "$APPS_DIR" -maxdepth 1 -type d -exec test -f {}/manifest.yml \; -exec cp -r {} "$CUSTOM_DIR/archipelago/apps/" \; APP_COUNT=$(find "$CUSTOM_DIR/archipelago/apps" -name "manifest.yml" | wc -l | tr -d ' ') echo "✅ Included $APP_COUNT app manifests" fi # Create the ISO OUTPUT_ISO="$OUTPUT_DIR/archipelago-${ALPINE_VERSION}-${ARCH}.iso" echo "" echo "🔥 Creating final ISO..." if [[ "$OSTYPE" == "darwin"* ]]; then # On macOS, use xorriso for hybrid BIOS+UEFI bootable ISO if command -v xorriso >/dev/null 2>&1; then # Try dual-boot (BIOS + UEFI) if EFI bootloader exists if [ -f "$CUSTOM_DIR/boot/grub/grub.cfg" ] || [ -d "$CUSTOM_DIR/efi" ] || [ -d "$CUSTOM_DIR/EFI" ]; then echo "🔄 Creating hybrid BIOS+UEFI bootable ISO..." xorriso -as mkisofs -o "$OUTPUT_ISO" \ -volid "ARCHIPELAGO" \ -J -R \ -c boot/syslinux/boot.cat \ -b boot/syslinux/isolinux.bin \ -no-emul-boot -boot-load-size 4 -boot-info-table \ -eltorito-alt-boot \ -e boot/grub/efi.img \ -no-emul-boot \ -isohybrid-gpt-basdat \ -isohybrid-mbr "$CUSTOM_DIR/boot/syslinux/isohdpfx.bin" \ "$CUSTOM_DIR" 2>&1 | grep -v "xorriso : UPDATE" || { echo "⚠️ Dual-boot failed, trying BIOS-only..." xorriso -as mkisofs -o "$OUTPUT_ISO" \ -volid "ARCHIPELAGO" \ -J -R \ -c boot/syslinux/boot.cat \ -b boot/syslinux/isolinux.bin \ -no-emul-boot -boot-load-size 4 -boot-info-table \ -isohybrid-mbr "$CUSTOM_DIR/boot/syslinux/isohdpfx.bin" \ "$CUSTOM_DIR" 2>&1 | grep -v "xorriso : UPDATE" } else echo "🔄 Creating BIOS-only bootable ISO..." xorriso -as mkisofs -o "$OUTPUT_ISO" \ -volid "ARCHIPELAGO" \ -J -R \ -c boot/syslinux/boot.cat \ -b boot/syslinux/isolinux.bin \ -no-emul-boot -boot-load-size 4 -boot-info-table \ -isohybrid-mbr "$CUSTOM_DIR/boot/syslinux/isohdpfx.bin" \ "$CUSTOM_DIR" 2>&1 | grep -v "xorriso : UPDATE" || true # Check if ISO was created if [ ! -f "$OUTPUT_ISO" ]; then echo "⚠️ xorriso failed, trying without isohybrid..." xorriso -as mkisofs -o "$OUTPUT_ISO" \ -volid "ARCHIPELAGO" \ -J -R \ -c boot/syslinux/boot.cat \ -b boot/syslinux/isolinux.bin \ -no-emul-boot -boot-load-size 4 -boot-info-table \ "$CUSTOM_DIR" 2>&1 | grep -v "xorriso : UPDATE" fi fi else # Fallback to hdiutil hdiutil makehybrid -o "$OUTPUT_ISO" "$CUSTOM_DIR" \ -iso -joliet -default-volume-name "ARCHIPELAGO" || { echo "❌ Failed to create ISO" exit 1 } fi else # On Linux, use genisoimage or xorriso if command -v genisoimage >/dev/null 2>&1; then genisoimage -o "$OUTPUT_ISO" \ -b boot/syslinux/isolinux.bin \ -c boot/syslinux/boot.cat \ -no-emul-boot -boot-load-size 4 -boot-info-table \ -J -R -V "ARCHIPELAGO" \ "$CUSTOM_DIR" elif command -v xorriso >/dev/null 2>&1; then xorriso -as mkisofs -o "$OUTPUT_ISO" \ -b boot/syslinux/isolinux.bin \ -c boot/syslinux/boot.cat \ -no-emul-boot -boot-load-size 4 -boot-info-table \ -J -R -V "ARCHIPELAGO" \ "$CUSTOM_DIR" else echo "❌ No ISO creation tool found (need genisoimage or xorriso)" exit 1 fi fi # Make bootable (add isohybrid for USB boot) if command -v isohybrid >/dev/null 2>&1 && [[ "$OSTYPE" != "darwin"* ]]; then isohybrid "$OUTPUT_ISO" fi echo "" echo "✅ ISO created successfully!" echo "" echo "📀 Output: $OUTPUT_ISO" echo " Size: $(du -h "$OUTPUT_ISO" | cut -f1)" echo "" echo "📝 To create a bootable USB:" if [[ "$OSTYPE" == "darwin"* ]]; then echo " 1. Insert USB drive" echo " 2. Find device: diskutil list" echo " 3. Unmount: diskutil unmountDisk /dev/diskN" echo " 4. Write: sudo dd if=$OUTPUT_ISO of=/dev/rdiskN bs=1m" else echo " sudo dd if=$OUTPUT_ISO of=/dev/sdX bs=4M status=progress" fi echo ""