Automated Alpine Linux Installation
Alpine Linux is a minimal distribution that also includes the most essential Unix utilities. The versatility and consistent design of this distribution has made it successful. Alpine also has some significant limitations, although most problems can be solved by applying custom OpenRC scripts.
The Alpine Linux
answer file
is sourced as a shell script, so it is able to write files. In practice this
is difficult to take advantage of because the new rootfs is not yet mounted,
and it is unmounted after
setup-alpine
completes. This leaves several missing features:
- No means of setting root or user passwords
-
No means of modifying
doasconfiguration. - No syntax for specifying LVM mount points
These limitations can be overcome by patching the MFS root.
PXE boot
If TFTP and HTTP are used, unpack the netboot files in two locations
dist in "/tftpboot/alpine" "/var/www/htdocs/pub/alpine"; do mkdir $dist cd $dist tar -zxvf /var/www/htdocs/iso/alpine-netboot-3.23.3-x86_64.tar.gz chmod o+r boot/initramfs-* done
iPXE configuration
#!ipxe set tftp_url tftp://192.168.0.2/alpine set http_url http://192.168.0.2/pub/alpine set alpine_repo https://dl-cdn.alpinelinux.org/alpine/v3.23/main kernel ${tftp_url}/boot/vmlinuz-lts initrd=initramfs-lts modules=loop,squashfs quiet alpine_repo=${alpine_repo} modloop=${http_url}/boot/modloop-lts initrd ${tftp_url}/boot/initramfs-lts
-
initrdmust be set for EFI boot -
By default, 50% of RAM is allocated to the memory file system.
For systems with less than 700MB of RAM, add
rootflags=size=350Mto ensure there is enough space for the modloop download -
If using a serial console, use
console=tty0
Unattended Install
Alpine has a built-in
local backup utility
which creates a
tar.gz
file that can be loaded at boot. This is somewhat similar to OpenBSD's
siteNN.tgz
file, except it is applied early in the ramdisk boot, allowing us to
add functionality to the
initramfs.
To use this feature, add
apkovl=
to the boot line
#!ipxe set tftp_base tftp://192.168.0.2/alpine3.23 set http_base http://192.168.0.2/pub/alpine3.23 set alpine_repo https://dl-cdn.alpinelinux.org/alpine/v3.23/main set overlay http://192.168.0.2/alpine/autoinstall.apkovl.tar.gz kernel ${tftp_base}/boot/vmlinuz-lts initrd=initramfs-lts modules=loop,squashfs quiet alpine_repo=${alpine_repo} modloop=${http_base}/boot/modloop-lts apkovl=${overlay} initrd ${tftp_base}/boot/initramfs-lts
The autoinstall overlay will have this structure
.
`-- etc
|-- fstab
|-- init.d
| `-- firstboot
`-- runlevels
`-- default
`-- modloop -> /etc/init.d/modloop
-
etc/fstabis required for the overlay to be applied -
The
runlevels/default/modloopsymlink is required to mount extra kernel moduels as they not load automatically if an overlay is applied. -
etc/init.d/firstbootis an OpenRC script that will start the install
#!/sbin/openrc-run start() { local rc=0 mac=$(ifconfig eth0 | awk '/HWaddr/ { print $NF }') setup-apkrepos -1 apk add tzdata # prevent repeat DHCP requests pkill udhcpc printf "auto lo\n iface lo inet loopback\n" > /etc/network/interfaces # inject post-setup script sed -i -e '/cleanup_chroot_mounts /i\\tsh -x /tmp/chroot-final.sh' /usr/sbin/setup-disk # run setup setup-alpine -ef "http://192.168.0.2/alpine/${mac}.answers" rc=$? if [ $rc -eq 0 ]; then echo "Rebooting in 10 seconds" sleep 10 reboot fi eend $rc }
Create this overlay using relative base paths
cd overlay tar -czf /var/www/htdocs/alpine/autoinstall.apkovl.tar.gz *
Answers File
HOSTNAMEOPTS="alpine" KEYMAPOPTS=none DEVDOPTS=mdev TIMEZONEOPTS="-z US/Eastern" PROXYOPTS=none APKREPOSOPTS="-1" SSHDOPTS="openssh" NTPOPTS="openntpd" USE_EFI=1 DISKOPTS="-v -L -m sys /dev/nvme0n1" USEROPTS="-a -u -g audio,video,netdev eradman" USERSSHKEY="ssh-ed25519 AAAAC3N ..." DNSOPTS="-d lan -n 192.168.2.3" INTERFACESOPTS="auto lo iface lo inet loopback auto eth0 iface eth0 inet6 manual address 192.168.2.21/24 gateway 192.168.2.7 address fd00:52::15/64 gateway fd00:52::7 hostname alpine " export ERASE_DISKS="/dev/nvme0n1" export ROOT_SIZE="7000" # about 30GB cat > /tmp/chroot-final.sh <<'EOF' #!/bin/sh echo 'root:$5$47Z1ja56Y2ltHKyx$sw/oGtkvLP81S/dfC4XIwX9TAfGh1zEnT4yOILEE.gB' | chpasswd -e -R /mnt echo 'eradman:$5$47Z1ja56Y2ltHKyx$sw/oGtkvLP81S/dfC4XIwX9TAfGh1zEnT4yOILEE.gB' | chpasswd -e -R /mnt echo 'permit nopass :wheel' > /mnt/etc/doas.d/20-wheel.conf EOF
By using LVM and limiting the root size additional mount points can be created after the base install completes. Confusingly, the size is the number of LVM extents, which is 4MB by default.
Generate password hashes using
printf '******' | mkpasswd -m sha256.