Created
January 5, 2026 18:40
-
-
Save thapakazi/f06269fa3933cbe9614bac165c6023d6 to your computer and use it in GitHub Desktop.
Automated Arch Linux installation for Lima/QEMU (aarch64)
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 | |
| # Automated Arch Linux installation for Lima/QEMU | |
| # Usage: curl -sL <gist-url>/install-arch.sh | bash | |
| # | |
| # Run this inside the Archboot live environment | |
| # Installs to /dev/vda with EFI + root partitions | |
| set -e | |
| # Configuration | |
| DISK="${DISK:-/dev/vda}" | |
| HOSTNAME="${HOSTNAME:-archbox}" | |
| TIMEZONE="${TIMEZONE:-UTC}" | |
| LOCALE="${LOCALE:-en_US.UTF-8}" | |
| ROOT_PASSWORD="${ROOT_PASSWORD:-arch}" | |
| # Colors | |
| RED='\033[0;31m' | |
| GREEN='\033[0;32m' | |
| YELLOW='\033[1;33m' | |
| NC='\033[0m' | |
| log() { echo -e "${GREEN}==>${NC} $1"; } | |
| warn() { echo -e "${YELLOW}==> WARNING:${NC} $1"; } | |
| error() { echo -e "${RED}==> ERROR:${NC} $1"; exit 1; } | |
| # Check if running as root | |
| [[ $EUID -ne 0 ]] && error "This script must be run as root" | |
| # Check if disk exists | |
| [[ ! -b "$DISK" ]] && error "Disk $DISK not found" | |
| log "Starting Arch Linux installation to $DISK" | |
| log "Hostname: $HOSTNAME | Timezone: $TIMEZONE" | |
| echo "" | |
| read -p "This will ERASE $DISK. Continue? [y/N] " -n 1 -r | |
| echo | |
| [[ ! $REPLY =~ ^[Yy]$ ]] && exit 1 | |
| # Step 1: Partition disk | |
| log "Partitioning $DISK..." | |
| parted -s "$DISK" mklabel gpt | |
| parted -s "$DISK" mkpart ESP fat32 1MiB 513MiB | |
| parted -s "$DISK" set 1 esp on | |
| parted -s "$DISK" mkpart root ext4 513MiB 100% | |
| # Wait for partitions | |
| sleep 2 | |
| partprobe "$DISK" | |
| # Determine partition names (handles both vda1 and vda-part1 naming) | |
| if [[ -b "${DISK}1" ]]; then | |
| EFI_PART="${DISK}1" | |
| ROOT_PART="${DISK}2" | |
| elif [[ -b "${DISK}p1" ]]; then | |
| EFI_PART="${DISK}p1" | |
| ROOT_PART="${DISK}p2" | |
| else | |
| error "Cannot find partitions on $DISK" | |
| fi | |
| log "EFI partition: $EFI_PART" | |
| log "Root partition: $ROOT_PART" | |
| # Step 2: Format partitions | |
| log "Formatting partitions..." | |
| mkfs.fat -F32 "$EFI_PART" | |
| mkfs.ext4 -F "$ROOT_PART" | |
| # Step 3: Mount partitions | |
| log "Mounting partitions..." | |
| mount "$ROOT_PART" /mnt | |
| mkdir -p /mnt/boot | |
| mount "$EFI_PART" /mnt/boot | |
| # Step 4: Install base system | |
| log "Installing base system (this may take a while)..." | |
| pacstrap -K /mnt \ | |
| base \ | |
| linux \ | |
| linux-firmware \ | |
| base-devel \ | |
| sudo \ | |
| openssh \ | |
| cloud-init \ | |
| cloud-guest-utils \ | |
| vim \ | |
| git \ | |
| curl \ | |
| wget \ | |
| htop \ | |
| networkmanager | |
| # Step 5: Generate fstab | |
| log "Generating fstab..." | |
| genfstab -U /mnt >> /mnt/etc/fstab | |
| # Step 6: Configure system (chroot) | |
| log "Configuring system..." | |
| cat > /mnt/setup.sh << CHROOT_EOF | |
| #!/bin/bash | |
| set -e | |
| # Timezone | |
| ln -sf /usr/share/zoneinfo/$TIMEZONE /etc/localtime | |
| hwclock --systohc | |
| # Locale | |
| echo "$LOCALE UTF-8" > /etc/locale.gen | |
| locale-gen | |
| echo "LANG=$LOCALE" > /etc/locale.conf | |
| # Hostname | |
| echo "$HOSTNAME" > /etc/hostname | |
| cat > /etc/hosts << EOF | |
| 127.0.0.1 localhost | |
| ::1 localhost | |
| 127.0.1.1 $HOSTNAME.localdomain $HOSTNAME | |
| EOF | |
| # Root password | |
| echo "root:$ROOT_PASSWORD" | chpasswd | |
| # Create arch user for cloud-init fallback | |
| useradd -m -G wheel -s /bin/bash arch || true | |
| echo "arch:arch" | chpasswd | |
| echo "%wheel ALL=(ALL:ALL) NOPASSWD: ALL" >> /etc/sudoers | |
| # Install bootloader (systemd-boot) | |
| bootctl install | |
| # Create boot entry | |
| mkdir -p /boot/loader/entries | |
| cat > /boot/loader/entries/arch.conf << EOF | |
| title Arch Linux | |
| linux /vmlinuz-linux | |
| initrd /initramfs-linux.img | |
| options root=$ROOT_PART rw quiet | |
| EOF | |
| cat > /boot/loader/loader.conf << EOF | |
| default arch.conf | |
| timeout 3 | |
| console-mode max | |
| EOF | |
| # Configure cloud-init | |
| mkdir -p /etc/cloud/cloud.cfg.d | |
| cat > /etc/cloud/cloud.cfg.d/99_lima.cfg << EOF | |
| # Lima/QEMU cloud-init config | |
| datasource_list: [ NoCloud, None ] | |
| disable_root: false | |
| ssh_pwauth: true | |
| users: | |
| - default | |
| EOF | |
| # Enable services | |
| systemctl enable sshd | |
| systemctl enable NetworkManager | |
| systemctl enable cloud-init-local.service | |
| systemctl enable cloud-init.service | |
| systemctl enable cloud-config.service | |
| systemctl enable cloud-final.service | |
| # Generate initramfs | |
| mkinitcpio -P | |
| echo "Setup complete inside chroot" | |
| CHROOT_EOF | |
| chmod +x /mnt/setup.sh | |
| arch-chroot /mnt /setup.sh | |
| rm /mnt/setup.sh | |
| # Step 7: Unmount and finish | |
| log "Unmounting..." | |
| umount -R /mnt | |
| echo "" | |
| echo -e "${GREEN}========================================${NC}" | |
| echo -e "${GREEN} Arch Linux installation complete!${NC}" | |
| echo -e "${GREEN}========================================${NC}" | |
| echo "" | |
| echo "Default credentials:" | |
| echo " root:$ROOT_PASSWORD" | |
| echo " arch:arch (sudo enabled)" | |
| echo "" | |
| echo "Run 'poweroff' to shutdown and save the image." | |
| echo "Then update your Lima config to use the new qcow2." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment