DEV Community

Cover image for Minimal Homelab Server with Alpine Linux
pizidavi
pizidavi

Posted on

Minimal Homelab Server with Alpine Linux

I wanted a minimal homelab server with full control over every component - no bloated NAS distros, no web UIs I didn't ask for, just a lean Linux box with pooled storage, parity protection, VPN access, containers, and automated backups. Here's how I built one with Alpine Linux on my Zimablade server.

⚠️ This isn't a tutorial; this is how I created my system. Yours may be different.

1. Install Alpine Linux

Download the ISO from alpinelinux.org, flash it to a USB drive with Balena Etcher, and boot from it.

Login as root (no password) and launch the installer:

setup-alpine
Enter fullscreen mode Exit fullscreen mode

Walk through the prompts:

  1. Keyboard layout - pick yours
  2. Hostname - whatever you want
  3. Network interface - select your adapter
  4. DNS - leave domain blank, set DNS as 1.1.1.1 8.8.8.8
  5. Root password - set a strong one
  6. Timezone - pick "UTC" or your local timezone
  7. Proxy - none
  8. NTP - busybox
  9. APK mirror - don't skip this one
    • Press c to enable community packages
    • Press f to auto-select the fastest mirror
  10. Create a user - I used admin
  11. SSH server - openssh
  12. Disk - select your drive, choose lvm then sys
    • lvm (Logical Volume Manager) lets you manage disk space flexibly - resize, add, or remove partitions without rebooting
    • sys means a full disk installation

Reboot when it's done.

2. First Boot: Baseline Setup

SSH in from your workstation:

ssh-copy-id -i .ssh/id_rsa.pub admin@192.168.1.X
ssh admin@192.168.1.X
Enter fullscreen mode Exit fullscreen mode

Switch to Bash

Alpine ships with ash by default. Swap it for bash for the admin user:

sudo apk add bash
Enter fullscreen mode Exit fullscreen mode

Edit /etc/passwd and change the admin user's shell from /bin/ash to /bin/bash.

Then create ~/.bash_profile:

# Aliases
alias l="ls -la"
alias sudo="doas"
Enter fullscreen mode Exit fullscreen mode

NOTE: Alpine uses doas instead of sudo. The alias makes the transition painless.

Install Base Packages

sudo apk add util-linux lsblk xfsprogs curl git
Enter fullscreen mode Exit fullscreen mode

Fix APK Repositories

Edit /etc/apk/repositories and make sure you have main, community, and testing:

https://dl-cdn.alpinelinux.org/alpine/<version>/main
https://dl-cdn.alpinelinux.org/alpine/<version>/community
@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing
Enter fullscreen mode Exit fullscreen mode

NOTE: Replace <version> with your current Alpine version (e.g. v3.21). To install testing packages, append @testing like: apk add mergerfs@testing

3. MergerFS + SnapRAID

This is the heart of the homelab. MergerFS pools multiple drives into a single mount point, and SnapRAID provides parity protection - think software RAID without the lock-in. Read more: MergerFS + SnapRAID is the new RAID 5.

Prepare the Disks

List available disks:

lsblk
Enter fullscreen mode Exit fullscreen mode

For each data disk (sda, sdb, sdc, ...), create a partition and filesystem:

sudo fdisk /dev/sda
Enter fullscreen mode Exit fullscreen mode

Inside fdisk:

  • g - create a new GPT partition table
  • n - create a new partition (accept all defaults)
  • w - write changes

Then format with XFS:

sudo mkfs.xfs /dev/sda1
Enter fullscreen mode Exit fullscreen mode

Repeat for every drive. If mkfs.xfs complains about the device being busy, reboot and try again.

Mount the Disks

Get the UUIDs:

blkid
Enter fullscreen mode Exit fullscreen mode

Create mount points:

sudo mkdir /mnt/disk{1,2,3}
sudo mkdir /mnt/parity
sudo mkdir /mnt/storage
Enter fullscreen mode Exit fullscreen mode

Edit /etc/fstab - replace the UUIDs with your own:

# Data drives
UUID="..."    /mnt/disk1    xfs    defaults    0    2
UUID="..."    /mnt/disk2    xfs    defaults    0    2
UUID="..."    /mnt/disk3    xfs    defaults    0    2

# Parity drive
UUID="..."    /mnt/parity    xfs    defaults    0    2
Enter fullscreen mode Exit fullscreen mode

Test it:

sudo mount -a
df -h
Enter fullscreen mode Exit fullscreen mode

Set Up MergerFS

sudo apk add fuse@testing mergerfs@testing

# Enable FUSE
sudo modprobe fuse
echo 'fuse' | sudo tee /etc/modules-load.d/fuse.conf
Enter fullscreen mode Exit fullscreen mode

Add MergerFS to /etc/fstab:

# MergerFS pool
/mnt/disk*    /mnt/storage    fuse.mergerfs    defaults,allow_other,use_ino,cache.files=partial,dropcacheonclose=true,category.create=pfrd    0    0
Enter fullscreen mode Exit fullscreen mode

Mount and verify:

sudo mount -a
df -h
Enter fullscreen mode Exit fullscreen mode

You should see /mnt/storage with the combined capacity of all data drives.

Set Up SnapRAID

sudo apk add snapraid@testing
Enter fullscreen mode Exit fullscreen mode

Edit /etc/snapraid.conf:

# Parity disk location
parity /mnt/parity/snapraid.parity

# Content file locations (one per data disk + one in /var)
content /var/snapraid/snapraid.content
content /mnt/disk1/.snapraid.content
content /mnt/disk2/.snapraid.content
content /mnt/disk3/.snapraid.content

# Data disks
data d1 /mnt/disk1/
data d2 /mnt/disk2/
data d3 /mnt/disk3/

# Exclude patterns
exclude *.unrecoverable
exclude /tmp/
exclude /lost+found/
exclude .AppleDouble
exclude ._*
exclude .DS_Store
exclude Thumbs.db
exclude desktop.ini
exclude *.tmp
exclude *.temp
exclude .fseventsd/
exclude .Spotlight-V100/
exclude .Trash-1000/
exclude */.Trash-1000/
exclude .recycling/

# Auto-save content every 100 changes
autosave 100
Enter fullscreen mode Exit fullscreen mode

Create the content directory and run the first sync:

sudo mkdir -p /var/snapraid
sudo snapraid sync
Enter fullscreen mode Exit fullscreen mode

NOTE: The first sync can take a while depending on how much data you have.

Automate SnapRAID with Cron

[IMPORTANT] SnapRAID is not a real-time RAID solution. It only protects against disk failures when you run snapraid sync. You should run it daily or more frequently depending on your data change rate.

sudo crontab -e
Enter fullscreen mode Exit fullscreen mode
0 1 * * * snapraid sync && snapraid scrub -p 4
Enter fullscreen mode Exit fullscreen mode

The scrub -p 4 checks 4% of your data each day for bit rot - this means a full check completes roughly once a month.

4. Tailscale

Tailscale gives you a private VPN to access your homelab from anywhere - no port forwarding, no dynamic DNS headaches.

curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up --accept-dns=false
Enter fullscreen mode Exit fullscreen mode

NOTE: --accept-dns=false prevents Tailscale from overriding your DNS settings, which can break local resolution.

Authenticate with the link it prints, then you're in.

Tailscale Serve

Expose local services over your Tailscale network with a clean HTTPS URL. Read more: Tailscale Serve

sudo tailscale serve --service=svc:<service-name> --https=443 <local-port>
Enter fullscreen mode Exit fullscreen mode

For example, to expose a web app running on port 8080:

sudo tailscale serve --service=svc:webapp --https=443 8080
Enter fullscreen mode Exit fullscreen mode

Access it at https://webapp.<your-machine>.ts.net.

5. Docker

sudo apk add docker docker-cli-compose
Enter fullscreen mode Exit fullscreen mode

Enable and start the Docker service:

sudo rc-update add docker default
sudo service docker start
Enter fullscreen mode Exit fullscreen mode

Verify:

sudo docker ps
Enter fullscreen mode Exit fullscreen mode

Create stack directories for your containers:

mkdir -p /mnt/storage/stacks # This is where the compose.yml files will live
mkdir -p /mnt/storage/data # This is where the container data will be stored
Enter fullscreen mode Exit fullscreen mode

6. Backup with Backrest

I use Backrest, a web UI for Restic, to back up to Backblaze B2. Everything runs in Docker.

Create a Backblaze B2 Bucket

  1. Create a Backblaze account
  2. Go to B2 Cloud StorageCreate a Bucket (e.g. homelab-backup)
  3. Go to App KeysCreate New Application Key
    • Give it a name (e.g. backrest)
    • Note down the KeyID and Application Key - you won't see the key again

Docker Compose

Create a directory for Backrest:

mkdir -p /mnt/storage/data/backrest
mkdir -p /mnt/storage/stacks/backrest
cd /mnt/storage/stacks/backrest
Enter fullscreen mode Exit fullscreen mode

Create compose.yml:

services:
  backrest:
    image: garethgeorge/backrest:latest
    container_name: backrest
    hostname: backrest
    restart: always
    ports:
      - "9898:9898"
    volumes:
      - /mnt/storage/data/backrest/data:/data
      - /mnt/storage/data/backrest/config:/config
      - /mnt/storage/data/backrest/cache:/cache
      - /mnt/storage/data/backrest/tmp:/tmp
      - /mnt/storage/data/backrest/rclone:/root/.config/rclone # Mount for rclone config (needed when using rclone remotes)

      - /mnt/storage/stacks:/stacks  # Mount local paths to backup
      # - /path/to/local/repos:/repos     # Mount local repos (optional for remote storage)
    environment:
      - TZ=UTC # Set your timezone, e.g. "UTC"
      - BACKREST_DATA=/data
      - BACKREST_CONFIG=/config/config.json
      - XDG_CACHE_HOME=/cache
      - TMPDIR=/tmp
Enter fullscreen mode Exit fullscreen mode

Start it up:

sudo docker compose up -d
Enter fullscreen mode Exit fullscreen mode

Configure Backrest

  1. Open http://<your-server-ip>:9898 in your browser
  2. Go to Add Repository and fill in:
  • Type: S3
  • Repo URL: s3:<region>.backblazeb2.com/<bucket-name> - check your bucket's endpoint in the Backblaze dashboard (e.g. s3:eu-central-003.backblazeb2.com/homelab-backup)
  • Password: choose a strong Restic repo password
  1. Under Environment Variables, add:
   AWS_ACCESS_KEY_ID=<your-key-id>
   AWS_SECRET_ACCESS_KEY=<your-application-key>
Enter fullscreen mode Exit fullscreen mode
  1. Go to Add Plan:
    • Repository: select the one you just created
    • Paths: the directories to back up (e.g. /mnt/storage/stacks)
    • Schedule: set a backup frequency (e.g. daily at 2 AM)
    • Retention: configure how many snapshots to keep

Final Checklist

At this point you should have:

  • Alpine Linux installed and hardened with SSH key access
  • A pooled storage filesystem via MergerFS with parity protection from SnapRAID
  • Automated daily SnapRAID sync and scrub
  • VPN access to your homelab via Tailscale
  • Docker running with your user in the docker group
  • Automated backups to Backblaze B2 via Backrest

References

Top comments (0)