Today, Alpine is the most-pulled base image on Docker Hub, used by nginx, Redis, Node.js, Python, and hundreds of official images.
Timeline
2005 → Natanael Copa starts Alpine as LEAF fork
2006 → Alpine Linux 1.0 released
2010 → Alpine Linux Foundation formed
2012 → Switched to OpenRC init system
2014 → Migrated from uClibc to musl libc
2015 → Became dominant Docker base image
2017 → Alpine 3.6 — first to ship musl 1.1.16
2021 → Alpine 3.14 — improved cloud/container support
2023 → Alpine 3.18 — improved Rust/Go toolchain support
2024 → Alpine 3.20 — latest stable branch
Introduction
What is Alpine Linux?
Alpine Linux is a security-oriented, lightweight Linux distribution based on musl libc and BusyBox.
It is designed for power users, containers, embedded systems, and servers where minimal footprint and security matter most.
Unlike most distros, Alpine does NOT use systemd — it uses OpenRC, a dependency-based init system.
The default shell is ash (from BusyBox), not bash.
Uses doas instead of sudo for privilege escalation (though sudo is available via apk).
Standard → Full installer, for bare metal / VMs
Extended → Standard + extra packages (useful tools pre-included)
Virtual → Optimized for virtual machines (smaller kernel)
Netboot → PXE boot over network, no local media needed
Mini Root FS → Tiny rootfs tarball for containers / chroot
Raspberry Pi → ARM image for RPi 2/3/4/5
Cloud → AWS, GCP, Azure, OpenStack images
Xen → Optimized for Xen hypervisor
# Download Alpine ISO from https://alpinelinux.org/downloads/# Choose: Standard (bare metal), Virtual (VM), or Extended# Create bootable USB on Linuxsudo dd if=alpine-standard-3.20.0-x86_64.iso of=/dev/sdX bs=4M status=progresssync# On macOSsudo dd if=alpine-standard-3.20.0-x86_64.iso of=/dev/rdiskX bs=4m# Using Ventoy (multi-boot) — just copy ISO to Ventoy USB# Using Rufus on Windows — select ISO, write in DD mode
The setup-alpine Script
Alpine uses a single interactive script setup-alpine to configure the system.
# Boot from USB → login as root (no password)# Run the setup script:setup-alpine# The script will ask:# 1. Keyboard layout (e.g., us)# 2. Hostname (e.g., alpine-server)# 3. Network interface (eth0, wlan0, etc.)# 4. IP address (DHCP or static)# 5. DNS server (e.g., 8.8.8.8)# 6. Root password# 7. Timezone (e.g., UTC or Asia/Kolkata)# 8. HTTP proxy (none if direct)# 9. NTP client (chrony recommended)# 10. Mirror for apk (select fastest)# 11. SSH server (openssh or dropbear)# 12. Disk to use (e.g., sda)# 13. Install mode: sys / data / lvm / cryptsys / none
Install Modes Explained
sys → Traditional install to disk (like any Linux distro)
Disk is read/write, changes persist on reboot
Best for: servers, VMs, workstations
data → OS runs from RAM (diskless), /var and /home on disk
Fast boot, disk used only for persistent data
Best for: appliances, routers
lvm → sys install but using LVM for disk management
Best for: servers needing flexible partitioning
cryptsys → sys install with full disk encryption (LUKS)
Best for: laptops, sensitive data
none → No disk install — pure diskless/RAM mode
Changes lost on reboot (use lbu to save)
Best for: live environments, embedded
Manual Disk Setup
# If you want manual partitioning before setup-alpine:# List disksfdisk -llsblk# Partition with fdisk (MBR) or gdisk (GPT)fdisk /dev/sda# Create: /dev/sda1 (boot, 512MB), /dev/sda2 (swap, 2GB), /dev/sda3 (root, rest)# Format partitionsmkfs.ext4 /dev/sda3mkfs.ext4 /dev/sda1mkswap /dev/sda2# For UEFI systems — EFI partitionmkfs.fat -F32 /dev/sda1# setup-alpine will detect and use these partitions
Network Setup During Install
# Static IP configuration during setup-alpine:# Interface: eth0# IP: 192.168.1.100# Netmask: 255.255.255.0# Gateway: 192.168.1.1# DNS: 8.8.8.8# Or use DHCP (just press Enter for auto)# After install, edit /etc/network/interfaces for changes
First Boot — Post-Install Steps
# Update package index and upgrade all packagesapk update && apk upgrade# Enable community repository (more packages)# Edit /etc/apk/repositories and uncomment community linevi /etc/apk/repositories# Uncomment: http://dl-cdn.alpinelinux.org/alpine/v3.20/community# Install essential toolsapk add bash curl wget git vim nano htop# Create a regular useradduser -D myuserpasswd myuser# Install doas (sudo alternative) and configureapk add doasecho "permit myuser as root" > /etc/doas.d/doas.conf# Or install sudo if preferredapk add sudoecho "myuser ALL=(ALL) ALL" >> /etc/sudoers# Enable and start SSHrc-update add sshd defaultrc-service sshd start
Kernel & Architecture
Alpine Kernel Variants
linux-lts → Long-term support kernel (default for most installs)
Stable, well-tested, recommended for servers
linux-hardened → LTS kernel + grsecurity/PaX patches
Extra security: stronger ASLR, PaX, RBAC
Slight performance overhead
linux-virt → Stripped-down kernel for VMs
Removes hardware drivers not needed in VMs
Smaller, faster boot in hypervisors
linux-edge → Latest upstream kernel (from edge branch)
Newest features, less tested
linux-rpi → Raspberry Pi specific kernel (ARM)
linux-rpi4 → Raspberry Pi 4 specific kernel
# Check current kerneluname -runame -a# Install hardened kernelapk add linux-hardened# List available kernel packagesapk search linux-
musl libc vs glibc
Feature
musl libc
glibc
Size
~600 KB
~2.5 MB
Standards compliance
Strict POSIX
Mostly POSIX + GNU extensions
Thread-local storage
Simpler model
Complex
DNS resolver
Built-in, simple
nsswitch.conf based
Locale support
Minimal
Full
Binary compatibility
musl binaries only
Broad compatibility
Security
Cleaner codebase, fewer CVEs
More CVEs historically
Performance
Slightly slower in some benchmarks
Faster in some workloads
Used by
Alpine, Void Linux
Debian, Ubuntu, Fedora, most distros
BusyBox — The Swiss Army Knife
BusyBox is a single binary (/bin/busybox) that provides ~300+ Unix utilities.
Each utility is a symlink to /bin/busybox:
ls -la /bin/ls # → /bin/busyboxls -la /bin/sh # → /bin/busyboxls -la /bin/grep # → /bin/busybox# List all BusyBox appletsbusybox --list# BusyBox versionbusybox --help | head -1
BusyBox applets are functional but have fewer options than GNU coreutils.
Install GNU coreutils if you need full compatibility:
apk add coreutils # GNU coreutilsapk add grep # GNU grep (replaces BusyBox grep)apk add sed # GNU sedapk add findutils # GNU find, xargsapk add util-linux # more utilities
OpenRC Init System
Alpine uses OpenRC — a dependency-based init system. NOT systemd.
OpenRC is lightweight, fast, and written in C + shell scripts.
PID 1 is /sbin/init (OpenRC’s init), not systemd.
# OpenRC is NOT systemd — different commands!# systemctl → rc-service / rc-update# journalctl → /var/log/ files or logread (syslog)
Boot Process (OpenRC)
flowchart TD
A[Power On / Reset] --> B[BIOS/UEFI POST]
B --> C[GRUB2 Bootloader\n/boot/grub/grub.cfg]
C --> D[Kernel loads\nvmlinuz-lts]
D --> E[initramfs mounts\nearly root filesystem]
E --> F[/sbin/init starts\nOpenRC PID 1]
F --> G[sysinit runlevel\nMount /proc /sys /dev\nfsck disk checks]
G --> H[boot runlevel\nMount filesystems\nSet hostname\nLoad modules]
H --> I[default runlevel\nStart services:\nnginx, sshd, crond...]
I --> J[Login prompt\n/sbin/getty on tty1]
J --> K[User logs in\nash shell]
style A fill:#2d3748,color:#fff
style F fill:#2b6cb0,color:#fff
style I fill:#276749,color:#fff
style K fill:#744210,color:#fff
Alpine FHS Layout
/ Root filesystem (ext4 or tmpfs in diskless mode)
├── /bin BusyBox symlinks (ls, sh, grep, etc.)
├── /boot Kernel (vmlinuz-lts), initramfs, grub/
├── /dev Device files (managed by mdev, not udev)
├── /etc System configuration
│ ├── /etc/apk/ apk package manager config
│ ├── /etc/init.d/ OpenRC service scripts
│ ├── /etc/conf.d/ Service configuration files
│ ├── /etc/runlevels/ Runlevel symlinks
│ ├── /etc/network/ Network configuration
│ └── /etc/doas.d/ doas privilege config
├── /home User home directories
├── /lib musl libc + kernel modules
├── /media Removable media mount points
├── /mnt Manual mount points
├── /opt Optional third-party software
├── /proc Virtual: process info
├── /root Root user home
├── /run Runtime data (tmpfs)
├── /sbin System binaries (init, apk, ip, etc.)
├── /srv Service data
├── /sys Virtual: hardware/driver info
├── /tmp Temporary files (tmpfs)
├── /usr User programs
│ ├── /usr/bin User binaries
│ ├── /usr/lib Libraries
│ ├── /usr/share Shared data, man pages
│ └── /usr/local Locally installed software
└── /var Variable data (logs, cache, spool)
├── /var/cache/apk/ apk package cache
└── /var/log/ System logs
mdev — Device Manager
Alpine uses mdev (from BusyBox) instead of udev for device management.
Lighter weight, suitable for embedded systems.
# mdev is configured in /etc/mdev.confcat /etc/mdev.conf# Trigger mdev to re-scan devicesmdev -s# For more complex device management, install eudevapk add eudevrc-update add udev sysinit
apk Package Manager
What is apk?
apk (Alpine Package Keeper) is Alpine’s native package manager — written in C, extremely fast.
Packages are .apk files (tar.gz archives with metadata).
Repository index is cached locally at /var/cache/apk/.
# apk is available immediately after boot — no daemon neededapk --version
Repository branches:
main → Core packages, officially supported
Stable, security-patched
community → Community-maintained packages
Wider selection, still stable
Must be enabled manually (uncomment in repos file)
edge/main → Latest upstream packages (rolling)
edge/community → Latest community packages
edge/testing → Experimental, may be broken
# Enable community repo (recommended)sed -i 's|#.*community|http://dl-cdn.alpinelinux.org/alpine/v3.20/community|' /etc/apk/repositories# Or edit manuallyvi /etc/apk/repositories# Add edge/testing for a specific package only (safer approach)apk add --repository http://dl-cdn.alpinelinux.org/alpine/edge/testing <package># Use setup-apkrepos for interactive mirror selectionsetup-apkrepos
Core apk Commands
## ── UPDATE & UPGRADE ──────────────────────────────────────apk update # Refresh package index from reposapk upgrade # Upgrade all installed packagesapk update && apk upgrade # Update index then upgrade (common combo)## ── INSTALL & REMOVE ──────────────────────────────────────apk add <package> # Install a packageapk add vim curl git htop # Install multiple packagesapk add --no-cache <package> # Install without caching (great for Dockerfiles)apk del <package> # Remove a packageapk del --purge <package> # Remove package + config files## ── SEARCH ────────────────────────────────────────────────apk search <term> # Search packages by name/descriptionapk search -v nginx # Verbose search with descriptionsapk search -e nginx # Exact name match only## ── INFO ──────────────────────────────────────────────────apk info # List all installed packagesapk info <package> # Info about installed packageapk info -L <package> # List files installed by packageapk info -R <package> # Show reverse dependencies (what needs it)apk info -r <package> # Show dependencies of packageapk info -a <package> # All info (size, deps, files)## ── FIX & VERIFY ──────────────────────────────────────────apk fix # Reinstall/repair broken packagesapk fix <package> # Fix specific packageapk verify # Verify package integrityapk audit # Check for modified files vs package dbapk audit --system # Audit system files only## ── CACHE MANAGEMENT ──────────────────────────────────────apk cache clean # Remove cached packagesapk cache download # Download packages to cacheapk cache sync # Sync cache with installed packages# Enable persistent cache (useful for offline installs)mkdir -p /var/cache/apkln -s /var/cache/apk /etc/apk/cache## ── STATS ─────────────────────────────────────────────────apk stats # Show repository and package statsapk version # Show installed vs available versionsapk version -l '<' # Show packages with available upgrades
apk Package Flow Diagram
flowchart LR
A[Developer\nCreates Package] --> B[Alpine Package\nRepository\ndl-cdn.alpinelinux.org]
B --> C{/etc/apk/\nrepositories}
C --> D[main]
C --> E[community]
C --> F[edge/testing]
D --> G[apk update\nFetch APKINDEX]
E --> G
F --> G
G --> H[Local Index Cache\n/var/cache/apk/]
H --> I{apk add\npackage}
I --> J[Download .apk\nfrom mirror]
J --> K[Verify GPG\nsignature]
K --> L{Valid?}
L -- Yes --> M[Extract to /\nUpdate /lib/apk/db/]
L -- No --> N[Reject &\nError]
M --> O[Run post-install\nscripts]
O --> P[Package\nInstalled ✓]
style A fill:#2d3748,color:#fff
style P fill:#276749,color:#fff
style N fill:#742a2a,color:#fff
World File & Package Pinning
# /etc/apk/world — list of explicitly installed packagescat /etc/apk/world# Pin a package to a specific versionapk add nginx=1.24.0-r0# Pin to a specific repoapk add nginx@community# Hold a package at current version (don't upgrade)apk add nginx=~1.24 # pin to 1.24.x# Unhold / allow upgradeapk add nginx # removes version constraint
Building Packages (APKBUILD)
# Alpine packages are built from APKBUILD files (similar to Arch's PKGBUILD)# Install build toolsapk add alpine-sdk abuild# Add user to abuild groupadduser myuser abuild# Generate signing keyabuild-keygen -a -i# Example minimal APKBUILD:
# APKBUILDpkgname=mypkgpkgver=1.0.0pkgrel=0pkgdesc="My custom package"url="https://example.com"arch="all"license="MIT"depends=""source="https://example.com/mypkg-$pkgver.tar.gz"build() { cd "$builddir" make}package() { cd "$builddir" make DESTDIR="$pkgdir" install}
# Build the packageabuild -r# Install locally built packageapk add --allow-untrusted ~/packages/mypkg-1.0.0-r0.apk
OpenRC Service Management
What is OpenRC?
OpenRC is a dependency-based init system used by Alpine Linux (and Gentoo, Void Linux).
It is NOT systemd — it uses shell scripts for service definitions.
Lightweight, fast, and easy to understand.
Services are defined in /etc/init.d/ as shell scripts.
Configuration for each service lives in /etc/conf.d/.
rc-service — Control Services
## ── SERVICE CONTROL ───────────────────────────────────────rc-service sshd start # Start a servicerc-service sshd stop # Stop a servicerc-service sshd restart # Restart a servicerc-service sshd reload # Reload config (if supported)rc-service sshd status # Check service statusrc-service sshd zap # Reset crashed service state# Short form (same as rc-service)service sshd startservice sshd status# List all services and their statusrc-status # Services in current runlevelrc-status --all # All services across all runlevelsrc-status --crashed # Show crashed servicesrc-status --unused # Services not in any runlevel
rc-update — Manage Runlevels
## ── RUNLEVEL MANAGEMENT ───────────────────────────────────rc-update add sshd default # Enable sshd at default runlevelrc-update del sshd default # Disable sshd from default runlevelrc-update add nginx boot # Enable nginx at boot runlevelrc-update show # Show all services and their runlevelsrc-update show default # Show services in default runlevel# Change runlevel manuallyopenrc default # Switch to default runlevelopenrc shutdown # Switch to shutdown runlevel
OpenRC Runlevels
Runlevel Purpose
─────────────────────────────────────────────────────────────
sysinit Very early boot: mount /proc, /sys, /dev
Load kernel modules, fsck, set up tmpfs
Services: devfs, dmesg, mdev, hwdrivers
boot System initialization: hostname, sysctl
Mount filesystems, set clock, start logging
Services: bootmisc, hostname, modules, syslog
default Normal multi-user mode (most services here)
Services: sshd, nginx, crond, networking, etc.
This is where you add your services
nonetwork Like default but without network services
Used for maintenance without network
shutdown Graceful shutdown sequence
Stop services, unmount filesystems, sync disks
single Single-user maintenance mode (root only)
OpenRC vs systemd Comparison
Feature
OpenRC
systemd
Language
Shell scripts
INI-style unit files
PID 1
/sbin/init
/lib/systemd/systemd
Service files
/etc/init.d/
/etc/systemd/system/
Config files
/etc/conf.d/
Inside unit files
Logging
syslog (/var/log/)
journald (binary)
Log viewer
cat /var/log/messages
journalctl
Socket activation
No (limited)
Yes
Cgroups
Optional
Core feature
Boot speed
Fast on minimal systems
Fast on complex systems
Complexity
Simple
Complex but powerful
Parallel start
Yes
Yes
Dependency tracking
Yes
Yes
Used by
Alpine, Gentoo, Void
Debian, Ubuntu, Fedora, Arch
Writing a Custom OpenRC Service
# Create service script at /etc/init.d/myappvi /etc/init.d/myapp
#!/sbin/openrc-run# OpenRC service script for myappname="myapp"description="My custom application"# Path to the binarycommand="/usr/local/bin/myapp"command_args="--config /etc/myapp/config.toml"# Run as this usercommand_user="myuser"# PID file for trackingpidfile="/run/${RC_SVCNAME}.pid"command_background=true# Dependencies — start after network is updepend() { need net after firewall}# Optional: custom start/stop functionsstart_pre() { # Runs before starting checkpath --directory --owner myuser:myuser /var/lib/myapp}
# Make executablechmod +x /etc/init.d/myapp# Enable at default runlevelrc-update add myapp default# Start itrc-service myapp startrc-service myapp status
Alpine’s default shell is ash — the Almquist Shell, provided by BusyBox.
ash is a POSIX-compliant shell, lighter than bash, but lacks many bash-specific features.
# Check current shellecho $SHELL # /bin/ash or /bin/shecho $0 # ash# ash vs bash differences:# - No arrays (ash has no array support)# - No [[ ]] (use [ ] instead)# - No process substitution <(cmd)# - No {a..z} brace expansion# - No $'...' string literals# - No local -n nameref# - No mapfile/readarray# - Simpler prompt customization# POSIX-safe shebang (works on Alpine)#!/bin/sh# bash-specific shebang (requires bash installed)#!/bin/bash
# List all available BusyBox appletsbusybox --list# Common applets and their GNU equivalents:# File operationsls, cp, mv, rm, mkdir, rmdir, ln, chmod, chown, chgrpfind, xargs, sort, uniq, wc, head, tail, cut, tr, tee# Text processinggrep, sed, awk (mawk-compatible), vi (minimal)# Archivetar, gzip, gunzip, bzip2, bunzip2, unzip, zcat# Networkwget, ping, ping6, traceroute, netstat, ifconfigudhcpc (DHCP client), ftpget, ftpput, httpd (tiny web server)# Systemps, top, kill, killall, free, df, du, mount, umountdmesg, sysctl, reboot, halt, poweroff, shutdown# User managementadduser, deluser, addgroup, delgroup, passwd# Initinit, syslogd, klogd, crond, crontab
Key Differences from GNU Coreutils
# BusyBox grep — no -P (Perl regex) flaggrep -P "pattern" file # FAILS on BusyBox grepgrep -E "pattern" file # Works (extended regex)apk add grep # Install GNU grep for -P support# BusyBox sed — no -i '' (macOS style)sed -i 's/old/new/' file # Works on BusyBox sed# BusyBox awk — limited compared to gawkapk add gawk # Install GNU awk# BusyBox find — fewer optionsfind . -name "*.log" -delete # Worksfind . -printf "%f\n" # May not work — install findutilsapk add findutils# BusyBox tar — slightly different flagstar -czf archive.tar.gz dir/ # Workstar --exclude-vcs # May not work — install tarapk add tar# BusyBox ps — limited outputps # Basic process listps aux # Works but fewer columnsapk add procps # Full ps, top, free, etc.
Shell Scripting on Alpine (POSIX-safe)
#!/bin/sh# POSIX-compliant script — works on Alpine's ash# VariablesNAME="Alpine"echo "Hello from $NAME"# Conditionals — use [ ] not [[ ]]if [ "$NAME" = "Alpine" ]; then echo "It's Alpine!"fi# Loopsfor i in 1 2 3 4 5; do echo "Item: $i"done# Functionsgreet() { local name="$1" echo "Hello, $name!"}greet "World"# Read inputprintf "Enter name: "read -r usernameecho "Welcome, $username"# Check if command existsif command -v nginx > /dev/null 2>&1; then echo "nginx is installed"fi# Exit codessome_command || { echo "Command failed"; exit 1; }
Essential Terminal Tools
# Install useful CLI toolsapk add \ vim \ # Text editor nano \ # Beginner-friendly editor htop \ # Interactive process viewer curl \ # HTTP client wget \ # File downloader git \ # Version control tmux \ # Terminal multiplexer jq \ # JSON processor ripgrep \ # Fast grep (rg) fd \ # Fast find bat \ # cat with syntax highlighting tree \ # Directory tree viewer ncdu \ # Disk usage analyzer lsof \ # List open files strace \ # System call tracer tcpdump \ # Network packet capture nmap # Network scanner
Networking
Network Configuration Files
# Main network config filecat /etc/network/interfaces# Example /etc/network/interfaces:
# Loopbackauto loiface lo inet loopback# DHCP on eth0auto eth0iface eth0 inet dhcp# Static IP on eth0auto eth0iface eth0 inet static address 192.168.1.100 netmask 255.255.255.0 gateway 192.168.1.1# DNS is configured in /etc/resolv.conf
# Apply nftables rulesnft -f /etc/nftables.nftrc-service nftables start# Using iptables (legacy, still works)apk add iptables ip6tables# Basic iptables rulesiptables -P INPUT DROPiptables -P FORWARD DROPiptables -P OUTPUT ACCEPTiptables -A INPUT -i lo -j ACCEPTiptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPTiptables -A INPUT -p tcp --dport 22 -j ACCEPTiptables -A INPUT -p tcp --dport 80 -j ACCEPTiptables -A INPUT -p tcp --dport 443 -j ACCEPT# Save iptables rulesrc-update add iptables boot/etc/init.d/iptables save
SSH — Dropbear vs OpenSSH
Dropbear OpenSSH
─────────────────────────────────────────────────────
Tiny (~110 KB) Full-featured (~1 MB+)
Built into Alpine Separate package
Basic SSH client/server Full SSH client/server
No SFTP server Full SFTP/SCP support
No SSH agent forwarding Full agent forwarding
Good for embedded/minimal Good for servers/workstations
Port: 22 (default) Port: 22 (default)
# Dropbear (default in Alpine)apk add dropbearrc-update add dropbear defaultrc-service dropbear start# Dropbear configvi /etc/conf.d/dropbear# DROPBEAR_OPTS="-p 22 -w" # -w disables root login# Switch to OpenSSH (recommended for servers)apk del dropbearapk add opensshrc-update add sshd defaultrc-service sshd start# OpenSSH configvi /etc/ssh/sshd_config# PermitRootLogin no# PasswordAuthentication no# PubkeyAuthentication yes# Generate SSH key pair (on client)ssh-keygen -t ed25519 -C "myuser@alpine"# Copy public key to serverssh-copy-id myuser@192.168.1.100
Security Features
Alpine’s Security Philosophy
Alpine was designed from the ground up with security as a first-class concern.
Every package is compiled with security hardening flags.
The minimal footprint means fewer packages = fewer CVEs = smaller attack surface.
musl libc Security Benefits
musl libc security advantages over glibc:
1. Cleaner codebase — fewer lines of code = fewer bugs
2. No RUNPATH/RPATH injection vulnerabilities
3. Strict POSIX compliance — no GNU extensions that introduce bugs
4. No NSS (Name Service Switch) complexity — simpler DNS resolution
5. No LD_PRELOAD abuse vectors (limited compared to glibc)
6. Fewer historical CVEs than glibc
7. No locale-related buffer overflows (minimal locale support)
8. Thread-safe by design from the start
Kernel Security — PaX & grsecurity
# Install hardened kernel (PaX/grsecurity patches)apk add linux-hardened linux-hardened-dev# Reboot into hardened kernelreboot# Verify hardened kernel is runninguname -r # Should show -hardened suffix# PaX features enabled:# PAGEEXEC — prevents code execution in data pages (W^X)# MPROTECT — prevents making pages executable after mapping# RANDMMAP — randomizes mmap base address# RANDKSTACK — randomizes kernel stack offset# UDEREF — prevents kernel from dereferencing user pointers
Compiler Hardening Flags
# All Alpine packages are compiled with:# -fstack-protector-strong Stack canaries (SSP)# -fPIE / -pie Position Independent Executable# -Wl,-z,relro Read-only relocations (RELRO)# -Wl,-z,now Full RELRO (resolve all symbols at load)# -D_FORTIFY_SOURCE=2 Buffer overflow detection# -fstack-clash-protection Stack clash protection# Verify a binary's security propertiesapk add pax-utilsscanelf -e /usr/sbin/nginx # Check ELF security propertiespaxctl -v /usr/sbin/nginx # View PaX flags# Check if binary is PIEfile /usr/sbin/nginx # Should say "pie executable"
ASLR — Address Space Layout Randomization
# Check ASLR statuscat /proc/sys/kernel/randomize_va_space# 0 = disabled, 1 = partial, 2 = full (default on Alpine)# Enable full ASLR (should already be 2)echo 2 > /proc/sys/kernel/randomize_va_space# Make permanent via sysctlecho "kernel.randomize_va_space = 2" >> /etc/sysctl.confsysctl -p
doas — Privilege Escalation (Not sudo!)
Alpine uses doas (from OpenBSD) instead of sudo by default.
doas is simpler, smaller, and has a cleaner security model.
# /etc/doas.d/doas.conf syntax:
# Allow user to run any command as root
permit myuser as root
# Allow without password (nopass)
permit nopass myuser as root
# Allow specific command only
permit myuser as root cmd /sbin/reboot
# Allow wheel group
permit :wheel as root
# Keep environment variables
permit keepenv myuser as root
# Deny a user
deny baduser
# Use doasdoas apk update # Run as rootdoas -u otheruser command # Run as specific userdoas -s # Open root shell# Install sudo if you prefer itapk add sudovisudo # Edit sudoers safely
No SUID Binaries by Default
# Alpine minimizes SUID binaries# Find all SUID binaries on the systemfind / -perm -4000 -type f 2>/dev/null# Typical Alpine SUID binaries (very few):# /bin/busybox (some applets need it)# /usr/bin/passwd# /usr/bin/newgrp# Remove unnecessary SUID bitschmod u-s /path/to/binary# Mount filesystems with nosuidmount -o remount,nosuid /tmp
# Check if running in diskless modecat /proc/cmdline | grep -o 'alpine_dev=[^ ]*'# In diskless mode, / is a tmpfsmount | grep "on / "# tmpfs on / type tmpfs ...
lbu — Local Backup Utility
lbu saves the current state of the system to the boot media so changes survive reboots.
## ── lbu COMMANDS ──────────────────────────────────────────lbu status # Show what files have changedlbu diff # Show diff of changed fileslbu commit # Save changes to boot medialbu commit -d # Commit and show diff# lbu saves to an .apkovl file on the boot media# Default: /media/mmcblk0p1/hostname.apkovl.tar.gz# Include extra files/directories in backuplbu include /etc/myapplbu include /var/lib/myapp# Exclude files from backuplbu exclude /etc/bigfile# List included/excluded pathslbu listlbu list -e # Show excluded# Restore from backup (on fresh boot)lbu restore # Restore from default location# Backup to specific locationlbu commit -d /media/usb/
Overlay Filesystem
# Alpine diskless uses overlayfs:# Lower layer: read-only squashfs from boot media# Upper layer: read-write tmpfs in RAM# Merged: appears as normal read-write filesystem# The .apkovl overlay file contains:# - /etc/ changes (config files)# - /var/ changes (service state)# - List of installed packages (world file)# On boot, Alpine:# 1. Mounts boot media# 2. Loads base system into RAM# 3. Installs packages listed in world file# 4. Restores .apkovl overlay (config files)# 5. Starts OpenRC services
Data Disk Setup (data mode)
# In "data" mode: OS in RAM, /var and /home on persistent disk# Useful for: NAS, routers, appliances with persistent data# During setup-alpine, choose "data" install mode# Or manually configure:# 1. Partition data diskfdisk /dev/sda# Create /dev/sda1 for data# 2. Formatmkfs.ext4 /dev/sda1# 3. Mountmkdir -p /media/datamount /dev/sda1 /media/data# 4. Move /var to data diskcp -a /var /media/data/mount --bind /media/data/var /var# 5. Add to /etc/fstab (save with lbu)echo "/dev/sda1 /media/data ext4 defaults 0 2" >> /etc/fstabecho "/media/data/var /var none bind 0 0" >> /etc/fstablbu commit
Alpine as a Router/Firewall
# Enable IP forwardingecho "net.ipv4.ip_forward = 1" >> /etc/sysctl.confsysctl -p# Install routing toolsapk add iptables ip6tables# NAT masquerade (share internet connection)iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADEiptables -A FORWARD -i eth1 -o eth0 -j ACCEPTiptables -A FORWARD -i eth0 -o eth1 -m state --state ESTABLISHED,RELATED -j ACCEPT# Save rules/etc/init.d/iptables saverc-update add iptables boot# Install dnsmasq for DHCP + DNSapk add dnsmasqrc-update add dnsmasq default