Minimal Alpine Linux

Last edited on 2026-02-04 Tagged under  #alpine   #linux   #encrypt 

mountain range

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

This guide makes a few assumptions:

  • Target device is x86_64 architecture 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 root and data partitions encrypted with LUKS2 and formatted with the ext4 file system. I like to keep my user data in a separate partition to preserve its contents and make things simpler if/when I wipe root and re-install Linux.
  • An EFI partition formatted with the fat32 file system and mounted to boot. 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 swap memory, I use the Linux zram kernel 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-in busybox
  • 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:

NumberSizeCodeFormatUse as
12gEF00vfatESP partition
248g8309luksEncrypted root partition
3->END8309luksEncrypted 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

You can like, share, or comment on this post on the Fediverse 💬

Thanks for reading! Read other posts?

« Previous: Real-time File Synchronization Across Devices Using Syncthing