aboutsummaryrefslogtreecommitdiff
path: root/README
diff options
context:
space:
mode:
authorLena <lena@omega>2026-02-01 00:00:00 +0000
committerLena <lena@omega>2026-02-01 00:00:00 +0000
commitda0bb7fe3fd16b5d5b6269715d6e235d7f04b295 (patch)
treea9241a1ec34c7e28905eab71d17a7cbd4dbaa633 /README
downloadalpine-qemu-install-da0bb7fe3fd16b5d5b6269715d6e235d7f04b295.tar.gz
Enter alpine-qemu-installHEADmaster
Unattended Alpine install onto a disk image, driven over the serial console: the virt ISO boots under QEMU with an injected apkovl that runs setup-alpine from a pre-baked answer file.
Diffstat (limited to 'README')
-rw-r--r--README115
1 files changed, 115 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..fa29a0b
--- /dev/null
+++ b/README
@@ -0,0 +1,115 @@
+alpine-qemu-install
+===================
+Unattended install of Alpine Linux onto a disk image, driven entirely over the
+serial console. No keypresses, no graphics, no interaction.
+
+
+What it does
+------------
+Given an Alpine virt ISO and a disk image you created beforehand, the script:
+
+ - extracts the kernel, initramfs, and modloop from the ISO
+ - builds an apkovl overlay containing the kernel modules and a first-boot
+ script
+ - boots that kernel under QEMU with the disk attached as /dev/vda
+ - runs setup-alpine non-interactively against a pre-baked answer file
+ - patches the installed root password, SSH key, and serial getty
+ - powers the guest off when finished
+
+The disk image is the target. It appears as /dev/vda inside the guest and is
+erased. After install the layout is vda1=boot, vda2=swap, vda3=root.
+
+
+Requirements
+------------
+On the host:
+
+ - 7z (7zip or p7zip-full; extracting the modloop squashfs needs it)
+ - GNU tar
+ - openssl
+ - qemu-system-x86_64
+
+KVM is used automatically when /dev/kvm is writable, otherwise the install
+runs under plain emulation (slower, but works). You also need an x86_64
+Alpine virt ISO and a disk image created up front with qemu-img. qcow2 is
+recommended: it allocates sparsely and supports snapshots. Any other format
+qemu-img writes also works, since QEMU detects it.
+
+
+Usage
+-----
+Create a disk, then run the install:
+
+ qemu-img create -f qcow2 disk.qcow2 2G
+ ROOT_PASSWORD=changeme \
+ ./alpine-qemu-install alpine-virt-3.20.0-x86_64.iso disk.qcow2
+
+The install log streams to your terminal. When it reaches the end the guest
+powers off and the script exits. Boot the resulting image however you like,
+for example:
+
+ qemu-system-x86_64 -m 1024 -nographic -drive file=disk.qcow2,if=virtio
+
+
+Configuration
+-------------
+Configuration is by environment variable. Only ROOT_PASSWORD is required.
+
+ - ROOT_PASSWORD root password for the installed system (required)
+ - ROOT_PUBKEY an authorized_keys line; enables root SSH login
+ - SSHD openssh, dropbear, or none (default openssh)
+ - VM_HOSTNAME installed hostname (default alpine)
+ - APK_MIRROR apk mirror base URL
+ (default https://dl-cdn.alpinelinux.org/alpine)
+ - RAM_MB guest memory in MB during install (default 1024)
+ - SMP guest CPU count during install (default 2)
+
+The mirror must be reachable during install: setup-alpine fetches packages
+before the disk is even partitioned.
+
+
+How it works
+------------
+QEMU's vvfat is unreliable for the ~150 MB modloop file, and a failed
+modloop mount leaves the initramfs without /lib/modules, so setup-alpine
+cannot modprobe, partition, or run post-install scripts. To avoid that path,
+the script unpacks the modloop squashfs on the host and ships the modules
+inside the apkovl overlay instead. Only one small file goes on the vvfat
+drive: the apkovl tarball itself.
+
+The first-boot work runs from /etc/local.d/autoinstall.start via the default
+runlevel's local service. It removes itself before setup-disk copies the
+overlay onto the target, so the trigger never fires on the installed system.
+
+
+Debugging
+---------
+The install is fully visible. QEMU runs with -nographic, so everything the
+first-boot script does is logged to ttyS0, which is your terminal. The script
+runs under set -x, so each command is printed before it runs.
+
+QEMU runs with -no-reboot, so on success or failure the guest stays down and
+the full log remains on screen. To leave QEMU manually, press Ctrl-a then x.
+
+The guest reports distinct success and failure values through qemu's
+isa-debug-exit device. The script exits 0 only when the guest reported
+completion, 3 when the first-boot script failed, and 1 when qemu stopped
+without any result, including a manual Ctrl-a x.
+
+Common failures:
+
+ - "need 7z" or "need qemu-system-x86_64": install the missing host tool.
+ - "modloop layout changed": install 7zip or p7zip-full, or the ISO changed
+ and the modloop extraction needs updating.
+ - "/dev/vda did not appear": the disk image was not attached or is missing.
+ - apk fetch errors: the mirror is unreachable or APK_MIRROR is wrong.
+
+
+Security
+--------
+ROOT_PASSWORD is hashed on the host; openssl reads it on stdin, so the
+plaintext never reaches the guest, the apkovl, the set -x install log, or
+a process listing. The hash is kept out of the log too, but any crypt hash
+can be attacked offline, so pick a real password for images you keep. Root
+SSH login is key-only: ROOT_PUBKEY installs the key, and Alpine's default
+PermitRootLogin prohibit-password refuses password logins over SSH.