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
NOTE:
--accept-dns=falseprevents 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>
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)