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
Walk through the prompts:
- Keyboard layout - pick yours
- Hostname - whatever you want
- Network interface - select your adapter
-
DNS - leave domain blank, set DNS as
1.1.1.1 8.8.8.8 - Root password - set a strong one
- Timezone - pick "UTC" or your local timezone
-
Proxy -
none -
NTP -
busybox -
APK mirror - don't skip this one
- Press
cto enable community packages - Press
fto auto-select the fastest mirror
- Press
-
Create a user - I used
admin -
SSH server -
openssh -
Disk - select your drive, choose
lvmthensys- 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
Switch to Bash
Alpine ships with ash by default. Swap it for bash for the admin user:
sudo apk add bash
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"
NOTE: Alpine uses
doasinstead ofsudo. The alias makes the transition painless.
Install Base Packages
sudo apk add util-linux lsblk xfsprogs curl git
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
NOTE: Replace
<version>with your current Alpine version (e.g.v3.21). To install testing packages, append@testinglike: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
For each data disk (sda, sdb, sdc, ...), create a partition and filesystem:
sudo fdisk /dev/sda
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
Repeat for every drive. If mkfs.xfs complains about the device being busy, reboot and try again.
Mount the Disks
Get the UUIDs:
blkid
Create mount points:
sudo mkdir /mnt/disk{1,2,3}
sudo mkdir /mnt/parity
sudo mkdir /mnt/storage
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
Test it:
sudo mount -a
df -h
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
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
Mount and verify:
sudo mount -a
df -h
You should see /mnt/storage with the combined capacity of all data drives.
Set Up SnapRAID
sudo apk add snapraid@testing
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
Create the content directory and run the first sync:
sudo mkdir -p /var/snapraid
sudo snapraid sync
NOTE: The first
synccan 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
0 1 * * * snapraid sync && snapraid scrub -p 4
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
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>
For example, to expose a web app running on port 8080:
sudo tailscale serve --service=svc:webapp --https=443 8080
Access it at https://webapp.<your-machine>.ts.net.
5. Docker
sudo apk add docker docker-cli-compose
Enable and start the Docker service:
sudo rc-update add docker default
sudo service docker start
Verify:
sudo docker ps
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
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
- Create a Backblaze account
- Go to B2 Cloud Storage → Create a Bucket (e.g.
homelab-backup) - Go to App Keys → Create New Application Key
- Give it a name (e.g.
backrest) - Note down the KeyID and Application Key - you won't see the key again
- Give it a name (e.g.
Docker Compose
Create a directory for Backrest:
mkdir -p /mnt/storage/data/backrest
mkdir -p /mnt/storage/stacks/backrest
cd /mnt/storage/stacks/backrest
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
Start it up:
sudo docker compose up -d
Configure Backrest
- Open
http://<your-server-ip>:9898in your browser - 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
- Under Environment Variables, add:
AWS_ACCESS_KEY_ID=<your-key-id>
AWS_SECRET_ACCESS_KEY=<your-application-key>
- 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
Top comments (0)