DEV Community

Cover image for Minimal Homelab Server with Alpine Linux
pizidavi
pizidavi

Posted on Edited 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

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)