Minimal Alpine Linux
Alpine Linux is a lightweight and delightful community-driven Linux distribution that does things a bit differently than the standard defaults (musl vs glibc for C library, openrc vs systemd for init). I use an Alpine installation image to create an encrypted, console-only minimal system that provides a solid foundation while I explore building it up bit by bit to a workstation, laptop, and server configuration.
- 1. Start Here
- 2. Configure the Live Environment
- 3. Initial System Setup
- 4. Prepare the DISK
- 5. Installation
- 6. Configure the System
- 7. Finish Up
- 8. Resources
1. Start Here
This guide makes a few assumptions:
- Target device is
x86_64architecture and uses UEFI to boot. - Alpine will be installed as the sole operating system on a single disk.
- Network access during install uses a wired interface.
Alpine includes a setup-alpine script in the installer that can quickly get a system up-and-running. I will use the script to set a few basic settings, then skip the disk setup stage and proceed to manually create a custom partition layout, followed by chroot-ing into the newly-installed system to complete the setup.
This custom partition layout includes:
- Separate
rootanddatapartitions encrypted with LUKS2 and formatted with theext4file system. I like to keep my user data in a separate partition to preserve its contents and make things simpler if/when I wiperootand re-install Linux. - An EFI partition formatted with the
fat32file system and mounted toboot. Because this partition will also be storing kernels and initramfs in addition to EFI-related files - and to future-proof it for whatever else Linux might want to store here - I assign it a generous 2GB of storage. - In lieu of creating a partition for
swapmemory, I use the Linuxzramkernel module to configure a compressed block device in RAM to provide swapspace.
NOTE
Throughout this guide, square brackets [] in code blocks indicates the word of code (square brackets included) should be replaced with something else. This is detailed in the instructions before or after the code block.
Acquire an installation image
The latest official installation images are available here: Downloads
Download alpine-standard-[RELEASE]-x86_64.iso and alpine-standard-[RELEASE]-x86_64.iso.sha256. As of 2026-02-04 the latest RELEASE is 3.23.3.
On a Linux system, verify the integrity of the image with sha256sum:
sha256sum -c --ignore-missing alpine-standard-3.23.3-x86_64.iso.sha256
Prepare the USB installation medium
WARNING
Be very careful to note the proper device (which can be identified with the lsblk command). All contents on the device will be lost!
Write the installer to an unmounted USB storage device running the dd command as root.
Example: On a Linux system, if a USB stick appears as sdx1, then write the installer to sdx (omit partition number):
sudo dd if=alpine-standard-3.23.3-x86_64.iso of=/dev/sdx bs=4M conv=fsync oflag=direct status=progress; sync
2. Configure the Live Environment
Boot the target device from the Alpine installation media. Login as root with no password.
Set the console keyboard
Default console keymap is us. Available layouts are located in /usr/share/bkeymaps.
If some other keymap is desired, set a different one using the setup-keymap script:
setup-keymap [LAYOUT] [VARIANT]
Example: I configure the system to use the us layout with my preferred colemak variant:
setup-keymap us us-colemak
Or run setup-keymap in interactive mode:
# setup-keymap
Select keyboard layout: `us`
Select variant: `us-colemak`
Verify the boot mode
Confirm target device is using UEFI boot mode:
cat /sys/firmware/efi/fw_platform_size
If the command returns 64, then system is booted in UEFI with 64-bit x64 UEFI and we are good to go.
NOTE
If the file does not exist, the device is not using UEFI.
Connect to the internet
Configure the wired interface by running the setup-interfaces script in interactive mode:
setup-interfaces
Example: I configure the ethernet interface device identified as eth0:
- Interface:
eth0 - Ip address:
dhcp - Manual configuration:
n
Bring up the interface:
ifup eth0
Verify the network interface is active, has been assigned an address, and the internet is reachable:
ip addr
ping -c 5 alpinelinux.org
If this fails, or a wireless interface is required, consult the User Handbook: Networking page.
Remote login to the installer
One option to make this manual installation process easier (i.e. cut-n-paste commands) is to remotely log into the installer via ssh from another computer.
On the installer, add the sshd daemon using setup-sshd:
setup-sshd -c openssh
NOTE
Editor vi is used for modifying files, or install nano with:
apk add nano
Modify /etc/ssh/sshd_config by setting PermitRootLogin to allow root logins:
PermitRootLogin yes
Reload the daemon:
rc-service sshd reload
Set a password for root:
passwd
Switch to the other computer and ssh into the target device:
ssh root@[ip_address]
…where [ip_address] is the target device’s address obtained with the ip addr command above.
3. Initial System Setup
Begin the system configuration using the setup-alpine script:
setup-alpine
Example configuration steps:
- Keyboard layout:
us## skipped if set above - Keyboard variant:
us-colemak## skipped if set above - Enter system hostname:
alpinebox.home.arpa - Interface:
eth0 - Ip address:
dhcp - Manual network configuration?
n - Root password:
xxxxxxxx - Timezone:
Canada - Sub-timezone:
Eastern - Proxy:
none - Network Time Protocol:
chrony## skipped if running in a virtual machine; defaults to built-inbusybox - APK Mirror:
c## enable community repository - APK Mirror:
f## find and use fastest mirror - Setup user:
foo - Full name:
foo - User password:
xxxxxxxx - SSH key:
none - SSH server:
openssh
At the Disk & Install step, enter Ctrl-C to exit script.
4. Prepare the DISK
Setup a custom partition layout on a single disk before implementing the Alpine base installation.
Install extra tools
apk update && apk add cryptsetup dosfstools e2fsprogs lsblk sgdisk wipefs
Define DISK variables
Identify the disk where Alpine will be installed by listing block devices:
lsblk -f
Set DISK variables for either a SATA or NVMe device:
SATA (example device: sda)
export DISK="/dev/sda"
export ESP_PART="1"
export ROOT_PART="2"
export DATA_PART="3"
export ESP_DISK="${DISK}${ESP_PART}"
export ROOT_DISK="${DISK}${ROOT_PART}"
export DATA_DISK="${DISK}${DATA_PART}"
NVMe (example device: nvme0n1)
export DISK="/dev/nvme0n1"
export ESP_PART="1"
export ROOT_PART="2"
export DATA_PART="3"
export ESP_DISK="${DISK}p${ESP_PART}"
export ROOT_DISK="${DISK}p${ROOT_PART}"
export DATA_DISK="${DISK}p${DATA_PART}"
Erase DISK
Erase existing file systems and partition table on DISK:
wipefs -af $DISK && sgdisk --zap-all --clear $DISK
Notify the system of the changes to the partition table:
partprobe $DISK
NOTE
If the Logical Volume Manager (LVM) framework was previously installed on DISK, the above might fail with an error such as Device or resource busy. This is because the LVM volume group might have gotten set up at boot.
If so, bring down the volume group:
vgchange -an
After that, wipefs should work as expected.
Partition DISK
Create a custom GPT partition table on DISK with the following layout:
| Number | Size | Code | Format | Use as |
|---|---|---|---|---|
| 1 | 2g | EF00 | vfat | ESP partition |
| 2 | 48g | 8309 | luks | Encrypted root partition |
| 3 | ->END | 8309 | luks | Encrypted data partition |
Create the ESP partition:
sgdisk -n "${ESP_PART}:1m:+2g" -t "${ESP_PART}:ef00" -c 0:esp $DISK
Create the encrypted root partition:
sgdisk -n "${ROOT_PART}:0:+48g" -t "${ROOT_PART}:8309" -c 0:root $DISK
Create the encrypted data partition:
sgdisk -n "${DATA_PART}:0:0" -t "${DATA_PART}:8309" -c 0:data $DISK
NOTE
Run command mdev -s to create partition nodes in /dev.
Notify the system of changes to the partition table and display layout:
partprobe $DISK && mdev -s && sgdisk -p $DISK
Encrypt the root partition
Load the encryption kernel module:
modprobe dm-crypt
Encrypt the partition using cryptsetup:
cryptsetup luksFormat -y --type luks2 $ROOT_DISK
Open the newly-created root device and map to /dev/mapper/root:
cryptsetup open $ROOT_DISK root
Define a variable for this device:
export ROOT_DEV="/dev/mapper/root"
Encrypt the data partition
Encrypt the partition:
cryptsetup luksFormat -y --type luks2 $DATA_DISK
Open the newly-created data device and map to /dev/mapper/data:
cryptsetup open $DATA_DISK data
Define a variable for this device:
export DATA_DEV="/dev/mapper/data"
Format and mount the root device
NOTE
Labels on file systems are optional, but helpful. They allow for easy identification/mounting without a UUID.
Create a ext4 file system on the device:
mkfs.ext4 -L rootfs $ROOT_DEV
Mount the device:
mount -t ext4 $ROOT_DEV /mnt
Format and mount the data device
Create a ext4 file system on the device:
mkfs.ext4 -L datafs $DATA_DEV
Create the data mountpoint and mount the device:
mkdir /mnt/data && mount -t ext4 $DATA_DEV /mnt/data
Format and mount the ESP partition
Create a fat32 file system on the partition:
mkfs.fat -n ESP -F 32 $ESP_DISK
Create the boot mountpoint and mount the partition:
mkdir /mnt/boot && mount -t vfat $ESP_DISK /mnt/boot && df -h
5. Installation
Use the setup-disk script to install an Alpine base system to the root device currently mounted on /mnt:
setup-disk -m sys /mnt
6. Configure the System
Before chroot-ing into the system to configure it, a number of directories must be mounted:
mount --rbind /dev /mnt/dev
mount --make-rslave /mnt/dev
mount -t proc /proc /mnt/proc
mount --rbind /sys /mnt/sys
mount --make-rslave /mnt/sys
mount --rbind /tmp /mnt/tmp
mount --bind /run /mnt/run
Chroot
Enter the newly-installed base system:
chroot /mnt
Zram swap
Install zram-init, a wrapper script for the zram kernel module:
apk update && apk add zram-init
The configuration file /etc/conf.d/zram-init is well-commented. These are the settings I modify/verify are set as follows:
load_on_start=yes
unload_on_stop=yes
num_devices=1
type0=swap
size0=`LC_ALL=C free -m | awk '/^Mem:/{print int($2/4)}'` ## use a fourth of available memory
algo0=zstd
Enable the service:
rc-update add zram-init
After rebooting the system, check status with:
zramctl
Auto-mount DATA_DISK
Decrypt and auto-mount DATA_DISK at boot by using a keyfile securely stored on the encrypted ROOT_DISK.
Create the keyfile:
dd if=/dev/urandom of=/root/crypt-data-keyfile.bin bs=1024 count=4
Restrict permissions so only root can read it:
chmod 400 /root/crypt-data-keyfile.bin
Add the keyfile to a LUKS key slot on DATA_DISK:
cryptsetup luksAddKey $DATA_DISK /root/crypt-data-keyfile.bin
cryptsetup luksDump $DATA_DISK | grep luks2
Original passphrase for DATA_DISK occupies slot 0 and the keyfile has been added to slot 1.
Make note of the device-UUID required by the dmcrypt config file, which can be obtained using blkid or cryptsetup:
cryptsetup luksUUID $DATA_DISK
Edit /etc/conf.d/dmcrypt:
## Definition for /dev/mapper/data (for /data) with keyfile
target=data
source=UUID="[device-UUID]"
key=/root/crypt-data-keyfile.bin
… where [device-UUID] is replaced with the UUID of DATA_DISK.
Enable the dmcrypt service to start on boot:
rc-update add dmcrypt boot
NOTE
Verify an entry for /data exists in /etc/fstab. Otherwise, add it:
/dev/mapper/data /data ext4 rw,relatime 0 2
Mkinitfs
Edit /etc/mkinitfs/mkinitfs.conf, adding cryptsetup and keymap to the features list:
features="ata base ide scsi usb virtio ext4 cryptsetup keymap"
Generate a new initramfs:
mkinitfs $(ls /lib/modules)
Bootloader
Install packages:
apk add grub-efi efibootmgr
Install boot loader:
grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=ALPINE
Make note of the device-UUID required by the grub config file:
cryptsetup luksUUID $ROOT_DISK
Edit /etc/default/grub:
GRUB_CMDLINE_LINUX_DEFAULT="modules=sd-mod,usb-storage,ext4 cryptroot=UUID=[device-UUID] cryptdm=root quiet rootfstype=ext4"
… where [device-UUID] is replaced with the UUID of ROOT_DISK.
Run:
update-grub
7. Finish Up
Exit chroot:
exit
Unmount partitions:
umount /mnt/boot && umount /mnt/data && umount -l /mnt
Remove encrypted device mapping:
cryptsetup close data && cryptsetup close root
Reboot system:
reboot
User is prompted for the passphrase to unlock the encrypted root partition. Upon success, boot resumes:
.
.
.
alpinebox.home.arpa login:
Welcome to Alpine!
8. Resources
- Alpine Linux Wiki, particularly:
- Gentoo Linux Wiki, particularly:
You can like, share, or comment on this post on the Fediverse 💬
« Previous: Real-time File Synchronization Across Devices Using Syncthing