Three years ago I was the guy who paid for Google One, Dropbox Pro, and YouTube Premium — and never questioned whether there was another way. The idea of running my own server sounded like something sysadmins did in windowless rooms, not something a frontend developer with a spare Raspberry Pi should even attempt.
February 2024, around 11 PM, an ad played before a YouTube video I’d already watched five times. Something snapped. I typed “block ads at network level” into Google, and 45 minutes later I was staring at a Pi-hole admin dashboard showing 23% of my home traffic was tracking and ad domains. That was Aha! Moment #1.
Here are the five moments that followed — the real ones, with the hardware I actually used, the mistakes I actually made, and the exact resource numbers so you know what you’re signing up for.
Moment #1: Pi-hole Silences Every Screen in the House
Pi-hole acts as a DNS sinkhole — every device on your network asks it “where is doubleclick.net?” and Pi-hole replies “nowhere.” No per-device app installs, no browser extensions that Chrome eventually kills.
My first deployment took about 20 minutes on a Raspberry Pi 3B I had sitting in a drawer:
curl -sSL https://install.pi-hole.net | bash
The installer walks you through selecting an upstream DNS provider and a few interface choices. What caught me off guard: resource usage was laughable. On that ancient Pi 3B with 1 GB RAM, Pi-hole idled at 28 MB of memory and 0.3% CPU. A week later I’d blocked 31,847 queries — nearly 18% of all DNS traffic leaving my house.
| Metric | Pi-hole on Pi 3B | Pi-hole on Mini PC (N100) |
|---|---|---|
| RAM usage | 28 MB | 34 MB |
| CPU idle | 0.3% | 0.1% |
| Blocked queries (7 days) | 31,847 | 41,202 |
| Block rate | 18.2% | 21.7% |
| Devices protected | 14 | 23 |
The Mini PC saw a higher block rate purely because more IoT devices joined the network — smart TVs, voice assistants, all phoning home constantly. What you don’t see in the stats: family members stopped complaining about “weird ads following them around” within 48 hours. None of them knew I’d changed anything.
Moment #2: Immich Replaces Google Photos (And Google’s Scanning Your Library)
Google Photos ended free unlimited storage in June 2021. By early 2024 I was bumping against the 15 GB shared cap across Gmail, Drive, and Photos. Immich — an open-source, self-hosted alternative — caught my attention because it does something Google Photos can’t: object detection on your own hardware, with zero data leaving your network.
I deployed it with Docker Compose:
services:
immich-server:
image: ghcr.io/immich-app/immich-server:release
volumes:
- /mnt/photos:/usr/src/app/upload
env_file:
- .env
ports:
- "2283:2283"
redis:
image: redis:alpine
database:
image: tensorchord/pgvecto-rs:pg14-v0.2.0
The machine-learning container chewed through 4.2 GB of RAM processing my 23,000-photo library — face detection, object recognition, geolocation clustering. Took about 3 hours on an N100 mini PC. The search experience genuinely surprised me: typing “cat on couch 2023” returned exact matches faster than Google Photos ever did, all while the dashboard showed exactly zero outbound connections to Google’s servers.
Total cost: $160 for a refurbished OptiPlex Micro. Monthly cost: $0.
Moment #3: Nginx Proxy Manager Makes SSL Embarrassingly Easy
Before self-hosting, I associated SSL certificates with openssl command-line hell, 90-day expiration panic, and cryptic certbot errors at 2 AM. Nginx Proxy Manager (NPM) wrapped all of that into a web UI that took less time to configure than ordering a pizza.
docker run -d \
--name nginx-proxy-manager \
-p 80:80 -p 443:443 -p 81:81 \
-v npm_data:/data \
-v npm_letsencrypt:/etc/letsencrypt \
jc21/nginx-proxy-manager:latest
Port 81 opens the admin panel. You type a domain, check “Request SSL Certificate,” pick Let’s Encrypt, and hit Save. Forty seconds later you have HTTPS. I set up five subdomains — immich.mydomain.com, nextcloud.mydomain.com, portainer.mydomain.com — in under 10 minutes total. NPM also handles automatic renewal in the background, so there’s genuinely nothing to maintain.
Moment #4: Portainer Gives Docker a Face
Docker’s CLI is powerful but unforgiving. One mistyped docker compose down -v and you’ve nuked your database volumes. Portainer puts a visual layer on top — containers, images, volumes, and networks displayed as cards you can start, stop, inspect, and reconfigure with a click.
The moment I knew Portainer was worth it: I’d forgotten which mapped ports I’d assigned three weeks earlier, and instead of grepping through YAML files I opened the Portainer dashboard, saw every container’s port mapping in a grid, and fixed a collision in 30 seconds.
Resource cost sits at roughly 85 MB RAM and negligible CPU — unnoticeable on any hardware from a Pi 4 upward.
Moment #5: Nextcloud Kills Dropbox (And the Sync Actually Works)
I’d been paying Dropbox $120/year for 2 TB I used maybe 300 GB of. Nextcloud’s Docker deployment gave me functionally identical file sync — desktop client, mobile app, web UI — pointed at a 1 TB SSD in my OptiPlex.
Two things I didn’t expect: Nextcloud Office (Collabora Online integration) let me edit spreadsheets and documents in-browser without opening LibreOffice, and the Talk app gave me self-hosted video calls that worked better than Zoom on my local network. The Android app auto-uploaded photos just like Dropbox’s camera upload, landing them in the same directory Immich was already watching.
The Survival Map: Hardware, Electricity, and What Actually Breaks
After 18 months of running this stack, here’s what the hardware journey actually looks like:
| Stage | Hardware | RAM | Storage | Cost (Used) | Monthly Power |
|---|---|---|---|---|---|
| Beginner | Raspberry Pi 4 (4 GB) | 4 GB | 128 GB SD | $55 | ~$3 |
| Enthusiast | Dell OptiPlex Micro (N100) | 16 GB | 1 TB NVMe | $160 | ~$6 |
| Serious | Used Dell R730xd | 64 GB | 8×4 TB HDD | $450 | ~$30 |
| Madman | Custom Ryzen build | 128 GB | 40 TB ZFS | $1,400+ | ~$45 |
The mistake I made at Stage 2: running everything off a single NVMe drive with no backup. Immich’s database corrupted during a power outage at month 4. I lost zero photos (they were on a separate HDD), but all my albums, face tags, and curated collections evaporated. A $12 USB HDD and a nightly rsync cron job fixed this permanently.
What nobody tells you about electricity: that “silent” OptiPlex Micro draws 15W idle. Over 365 days that’s roughly 131 kWh — at US average rates ($0.14/kWh), about $18/year. The R730xd at 150W idle hits $184/year. If you’re in Europe paying €0.35/kWh, triple those numbers.
The family network conflict: Pi-hole blocks ads. It also blocks tracking domains that some apps require to function. My partner’s shopping app stopped loading product images — Pi-hole was blackholing api.segment.io. Whitelisting that one domain fixed it, but expect 2-3 “why is my app broken?” conversations in the first month.
The 8 GB RAM “Box” That Actually Runs
If you’re starting with a $100 budget, this exact stack runs comfortably on 8 GB:
Pi-hole 28 MB
Immich (no ML) 850 MB
Nextcloud 420 MB
Nginx PM 60 MB
Portainer 85 MB
Redis (shared) 45 MB
PostgreSQL 180 MB
─────────────────────
Total: ~1,668 MB
Plenty of headroom for experimenting. Add Immich ML and you’ll want 8 GB minimum, but the non-ML stack above idles under 2 GB all day.
Self-hosting starts with one “why would anyone do this” moment and ends with you browsing r/selfhosted at 3 AM wondering whether a used EPYC server is a reasonable purchase. It probably isn’t. The OptiPlex Micro definitely is.