Back to index
01Infrastructure

Homelab

A 2-node Proxmox lab I'm building from the ground up to actually understand hypervisors, storage and networking — not just following a video. It blocks ads and adult content network-wide with Pi-hole, backs up photos through Immich, and surfaces everything through a Homepage dashboard; VPN, a second node, Jellyfin, a Minecraft server, and Home Assistant are still on the wishlist.

RoleDesign, build, ops
Started2026
Nodes2 — desktop + laptop
StatusPi-hole, Immich, Homepage live

Timeline

Click a stop to open the chapter
2026

First boot

The main node is an i5-10400F desktop (hostname mohammad-pve) with Proxmox VE 9.2.11 installed — my first real hands-on with a hypervisor instead of just reading about one.

~15GB RAM, confirmed live over SSH
Learning VMs vs. containers by actually running both
Everything driven from the command line, no GUI shortcuts
2026

Storage layout

Split the node's disks into two ZFS pools: a fast SSD pool for VM and container state (the "brains" of services), and a striped HDD pool for bulk data like media and files. Some of that storage didn't come from a store — I stripped an SSD and a 2.5" HDD out of an old laptop and installed them straight into the node.

ssd-pool — fast tier for app databases and container disks
hdd-pool — two drives striped for capacity, ~1.35TB usable
The SSD and one of the hdd-pool drives were salvaged from a dead laptop instead of bought new
Striped means no redundancy — fine for replaceable media, not for anything I can't lose
2026

Ad-blocking, take one

Stood up AdGuard Home as the network's first DNS-level ad blocker — the first real wishlist item checked off.

First taste of running a service other people in the house actually depend on
Wanted more than ad-blocking eventually: adult content too
Sep 2026

Pi-hole migration

We ran into some issues with parental controls and similar filtering on AdGuard, so I fully destroyed that container and rebuilt DNS filtering on Pi-hole instead, reusing the exact same static IP so nothing else on the network needed to change.

~4.4 million domains loaded into gravity across ad, malware, tracking and adult-content lists
Verified live: ad and adult domains resolve to 0.0.0.0, normal sites resolve fine
Confirmed working from my phone by manually pointing its Wi-Fi DNS at the Pi-hole
Now

Immich + Homepage

Deployed Immich for photo and video backup — the real answer to the backup problem the striped hdd-pool created — plus Homepage as a single dashboard for finding and jumping into every service running on the node.

Immich replaces ad-hoc phone-photo backups with something self-hosted
Homepage is the first thing that opens when I need to check on the lab
Next

Second node & VPN

The second node — an older laptop — isn't set up yet. Planned role is a reverse proxy plus a backup target for the main node's data. WireGuard is installed on the main node but not configured, and the router still isn't pointed at Pi-hole by default.

Next: WireGuard VPN for remote access
Next: router-wide DNS so filtering doesn't require manual per-device setup
Still on the list: Jellyfin, a Minecraft server, Home Assistant

Milestones

What broke

Striped storage has no redundancy
hdd-pool stripes two drives for capacity. If either one dies, everything on it is gone — fine for replaceable media, but that's exactly why photos now live behind Immich instead of just a folder on the striped pool. Immich itself still needs a real backup plan, since striping isn't redundancy.
AdGuard didn't cover parental controls well
Rather than trying to bolt extra blocklists onto AdGuard, I fully destroyed the container and rebuilt DNS filtering on Pi-hole, which handled ad blocking and parental-control filtering cleanly in one place.
The router still doesn't know Pi-hole exists
I don't have admin access to the router yet, so filtering only applies to devices I've manually pointed at the Pi-hole IP — getting the whole network covered automatically is still open.

From the repo

proxmox/storage-setup.sh
# fast tier — VM/container state
zpool create ssd-pool /dev/sda

# bulk tier — striped for capacity, no redundancy
zpool create hdd-pool /dev/sdb /dev/sdd
zfs set compression=lz4 hdd-pool

# cap ARC so it doesn't starve VMs
echo "options zfs zfs_arc_max=4294967296" \
  > /etc/modprobe.d/zfs.conf
HypervisorProxmox VE 9.2.11
StorageZFS — ssd-pool + hdd-pool
DNSPi-hole v6, ~4.4M domains blocked
PhotosImmich
DashboardHomepage
NextWireGuard VPN, reverse-proxy node
Next project
Jarvis
Open →