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.