<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Homelab on ToolGenix — Open-Source AI &amp; Developer Tools: Honest Hands-On Reviews</title>
    <link>https://toolgenix.nxtniche.com/tags/homelab/</link>
    <description>Recent content in Homelab on ToolGenix — Open-Source AI &amp; Developer Tools: Honest Hands-On Reviews</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <lastBuildDate>Sun, 19 Jul 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://toolgenix.nxtniche.com/tags/homelab/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Family Home Server Guide 2026: From &#39;Girlfriend Approved&#39; Desk Setup to Zero-BS Deployment</title>
      <link>https://toolgenix.nxtniche.com/posts/family-homeserver-beginner-guide-2026/</link>
      <pubDate>Sun, 19 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://toolgenix.nxtniche.com/posts/family-homeserver-beginner-guide-2026/</guid>
      <description>How I built a family home server that actually passed the &amp;#39;girlfriend test&amp;#39; — silent, invisible, and useful enough that nobody complains. Hardware picks, real power numbers, and the services my family actually uses.</description>
      <content:encoded><![CDATA[<p>r/selfhosted had a thread this January that stuck with me: &ldquo;Girlfriend approved homeserver setup&rdquo; — a photo of a clean desk, a tiny black box tucked behind a monitor, and a title that got 1,313 upvotes. The top comment: &ldquo;She noticed when Plex went down. That&rsquo;s when I knew it was real.&rdquo;</p>
<p>That thread resonated because it captures the actual bar for a family home server. Not benchmark scores or rack-mounted gear — the bar is <em>does anyone in the house notice it exists, and if they do, is it because something broke or because something useful happened?</em></p>
<p>I built our family server in March 2024. Eighteen months later, my partner uses it daily without knowing its IP address. Here&rsquo;s exactly how that happened — the hardware, the software, the mistakes, and the power bill.</p>
<hr>
<h2 id="the-three-non-negotiables-silence-footprint-and-just-works">The Three Non-Negotiables: Silence, Footprint, and &ldquo;Just Works&rdquo;</h2>
<p>Servers in data centers can sound like jet engines. Servers in living rooms cannot. After my first attempt — a used Dell PowerEdge T320 that idled at 42 dB (roughly a quiet refrigerator) — got vetoed within 72 hours, I established three rules:</p>
<ol>
<li><strong>Under 25 dB at idle.</strong> That&rsquo;s quieter than a whisper from 3 feet away. Fanless or near-fanless only.</li>
<li><strong>Fits behind a monitor or under a TV stand.</strong> No rack. No blinking lights visible from the couch.</li>
<li><strong>Zero manual intervention for core services.</strong> If Immich stops uploading photos, I hear about it. If Pi-hole blocks a shopping site, I hear about it faster.</li>
</ol>
<hr>
<h2 id="hardware-what-i-actually-bought-and-what-i-wish-id-bought-first">Hardware: What I Actually Bought (And What I Wish I&rsquo;d Bought First)</h2>
<p>I tested four configurations over six months. Here&rsquo;s how they compare:</p>
<table>
	<thead>
			<tr>
					<th style="text-align: left">Hardware</th>
					<th style="text-align: center">Price (Used)</th>
					<th style="text-align: center">Idle Power</th>
					<th style="text-align: center">Noise (Idle)</th>
					<th style="text-align: center">RAM Max</th>
					<th style="text-align: left">Verdict</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: left">Raspberry Pi 5 (8 GB)</td>
					<td style="text-align: center">$80</td>
					<td style="text-align: center">5W</td>
					<td style="text-align: center">0 dB (fanless case)</td>
					<td style="text-align: center">8 GB</td>
					<td style="text-align: left">Too weak for multi-service</td>
			</tr>
			<tr>
					<td style="text-align: left">Dell OptiPlex 3070 Micro</td>
					<td style="text-align: center">$130</td>
					<td style="text-align: center">12W</td>
					<td style="text-align: center">19 dB</td>
					<td style="text-align: center">32 GB</td>
					<td style="text-align: left"><strong>Winner</strong> — silent enough, powerful enough</td>
			</tr>
			<tr>
					<td style="text-align: left">Synology DS220+</td>
					<td style="text-align: center">$250</td>
					<td style="text-align: center">18W</td>
					<td style="text-align: center">18 dB</td>
					<td style="text-align: center">6 GB</td>
					<td style="text-align: left">Expensive for the CPU, locked ecosystem</td>
			</tr>
			<tr>
					<td style="text-align: left">Old ThinkPad T480 (repurposed)</td>
					<td style="text-align: center">$0 (had it)</td>
					<td style="text-align: center">8W</td>
					<td style="text-align: center">22 dB</td>
					<td style="text-align: center">32 GB</td>
					<td style="text-align: left">Good starter, ugly on a shelf</td>
			</tr>
	</tbody>
</table>
<p>The OptiPlex 3070 Micro — a 7×7×1.4-inch box with an i5-8500T, 16 GB DDR4, and a 512 GB NVMe — cost $130 on eBay. It&rsquo;s literally smaller than the router it sits next to. I added a 4 TB external USB HDD ($89) for media and backups, bringing total hardware to $219.</p>
<p>What I wish someone had told me: <strong>skip the Raspberry Pi for a multi-service home server.</strong> The Pi 5 is a fantastic single-purpose device (Pi-hole alone, a lightweight NAS, Home Assistant). Attempting Docker Compose with Immich, Nextcloud, and Nginx Proxy Manager on 8 GB of LPDDR4X will teach you the meaning of OOM killer. My Pi 5 swap-thrashed itself into unusability within 40 minutes of Immich&rsquo;s initial library scan.</p>
<hr>
<h2 id="the-software-stack-one-docker-composeyml-to-rule-the-living-room">The Software Stack: One docker-compose.yml to Rule the Living Room</h2>
<p>Everything runs through Docker on Ubuntu Server 24.04 LTS. Here&rsquo;s the core stack my family actually interacts with:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">services</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#75715e"># DNS ad-blocking — invisible, essential</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">pihole</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">pihole/pihole:latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;53:53/tcp&#34;</span> - <span style="color:#e6db74">&#34;53:53/udp&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;8089:80/tcp&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">environment</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">TZ</span>: <span style="color:#e6db74">&#34;America/Chicago&#34;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">WEBPASSWORD</span>: <span style="color:#e6db74">&#34;${PIHOLE_PASSWORD}&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">./pihole/etc:/etc/pihole</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">./pihole/dnsmasq:/etc/dnsmasq.d</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e"># Photo backup — the service my partner actually uses</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">immich</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">ghcr.io/immich-app/immich-server:release</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">/mnt/data/photos:/usr/src/app/upload</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">env_file</span>: <span style="color:#ae81ff">.env</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e"># File sync for documents, tax records, shared folders</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">nextcloud</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">nextcloud:stable</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;8080:80&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">/mnt/data/nextcloud:/var/www/html</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e"># Finance tracking — replaced our Mint/Personal Capital dependency</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">wealthfolio</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">ghcr.io/wealthfolio/wealthfolio:latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;3000:3000&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">/mnt/data/wealthfolio:/app/data</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e"># SSL termination and reverse proxy</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">nginx-proxy-manager</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">jc21/nginx-proxy-manager:latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;80:80&#34;</span> - <span style="color:#e6db74">&#34;443:443&#34;</span> - <span style="color:#e6db74">&#34;81:81&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">./npm/data:/data</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">./npm/letsencrypt:/etc/letsencrypt</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e"># Docker management dashboard</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">portainer</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">portainer/portainer-ce:latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;9443:9443&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">/var/run/docker.sock:/var/run/docker.sock</span>
</span></span></code></pre></div><p>Resource usage on the OptiPlex 3070 at steady state:</p>
<table>
	<thead>
			<tr>
					<th style="text-align: left">Service</th>
					<th style="text-align: center">RAM</th>
					<th style="text-align: center">CPU (Idle)</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: left">Pi-hole</td>
					<td style="text-align: center">32 MB</td>
					<td style="text-align: center">&lt;0.1%</td>
			</tr>
			<tr>
					<td style="text-align: left">Immich (with ML disabled)</td>
					<td style="text-align: center">620 MB</td>
					<td style="text-align: center">0.2%</td>
			</tr>
			<tr>
					<td style="text-align: left">Nextcloud</td>
					<td style="text-align: center">380 MB</td>
					<td style="text-align: center">0.3%</td>
			</tr>
			<tr>
					<td style="text-align: left">Wealthfolio</td>
					<td style="text-align: center">195 MB</td>
					<td style="text-align: center">0.1%</td>
			</tr>
			<tr>
					<td style="text-align: left">Nginx Proxy Manager</td>
					<td style="text-align: center">58 MB</td>
					<td style="text-align: center">&lt;0.1%</td>
			</tr>
			<tr>
					<td style="text-align: left">Portainer</td>
					<td style="text-align: center">72 MB</td>
					<td style="text-align: center">&lt;0.1%</td>
			</tr>
			<tr>
					<td style="text-align: left">PostgreSQL (shared)</td>
					<td style="text-align: center">210 MB</td>
					<td style="text-align: center">0.1%</td>
			</tr>
			<tr>
					<td style="text-align: left"><strong>Total</strong></td>
					<td style="text-align: center"><strong>1,567 MB</strong></td>
					<td style="text-align: center"><strong>~1%</strong></td>
			</tr>
	</tbody>
</table>
<p>Sixteen gigabytes of RAM leaves enormous headroom. The CPU barely registers until Immich runs face detection on a new batch of photos — at which point it spikes to 65% for about 90 seconds and settles back down.</p>
<hr>
<h2 id="the-service-my-family-actually-uses-ranked-by-real-engagement">The Service My Family Actually Uses (Ranked by Real Engagement)</h2>
<p>I deployed twelve services initially. After six months, usage data from Portainer container uptime and my own observation painted a clear picture:</p>
<table>
	<thead>
			<tr>
					<th style="text-align: center">Rank</th>
					<th style="text-align: left">Service</th>
					<th style="text-align: left">Who Uses It</th>
					<th style="text-align: center">Frequency</th>
					<th style="text-align: center">&ldquo;I&rsquo;d Be Mad If It Died&rdquo;</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: center">1</td>
					<td style="text-align: left">Pi-hole</td>
					<td style="text-align: left">Everyone (transparent)</td>
					<td style="text-align: center">Constantly</td>
					<td style="text-align: center">Yes — ads are noticeable</td>
			</tr>
			<tr>
					<td style="text-align: center">2</td>
					<td style="text-align: left">Immich</td>
					<td style="text-align: left">Partner (photo backup)</td>
					<td style="text-align: center">Daily</td>
					<td style="text-align: center">Yes — auto-upload is addicting</td>
			</tr>
			<tr>
					<td style="text-align: center">3</td>
					<td style="text-align: left">Wealthfolio</td>
					<td style="text-align: left">Me (finance tracking)</td>
					<td style="text-align: center">Weekly</td>
					<td style="text-align: center">Moderate</td>
			</tr>
			<tr>
					<td style="text-align: center">4</td>
					<td style="text-align: left">Nextcloud</td>
					<td style="text-align: left">Both (shared docs, taxes)</td>
					<td style="text-align: center">Monthly</td>
					<td style="text-align: center">Low</td>
			</tr>
			<tr>
					<td style="text-align: center">5</td>
					<td style="text-align: left">Jellyfin</td>
					<td style="text-align: left">Both (movie nights)</td>
					<td style="text-align: center">Weekly</td>
					<td style="text-align: center">Only on Friday nights</td>
			</tr>
	</tbody>
</table>
<p>The services that got deleted within two months: Home Assistant (too much tinkering for our simple apartment), Uptime Kuma (paranoia fuel), and Mealie (we already use Paprika). My advice: deploy three services, wait a month, then add one more. The family server you maintain is infinitely better than the one you abandon.</p>
<hr>
<h2 id="the-power-bill-reality-check">The Power Bill Reality Check</h2>
<p>I plugged the OptiPlex into a Kill-A-Watt for 30 days to get real numbers:</p>
<pre tabindex="0"><code>Idle draw:        11.8 W
Average load:     16.3 W (includes nightly backup jobs)
Peak (Immich ML): 38.2 W (roughly 90 seconds per batch)
30-day total:     12.1 kWh
Annual estimate:  145 kWh
Annual cost:      $20.30 (at $0.14/kWh US average)
</code></pre><p>For context, that&rsquo;s less electricity than a single incandescent light bulb left on 24/7. The Synology DS220+ actually drew more at idle (18W) because its Celeron J4025 lacks the efficiency of Intel&rsquo;s mobile T-series. And the old ThinkPad T480, despite sipping 8W at idle, produced a faint but perceptible coil whine that my partner described as &ldquo;a mosquito trapped in the bookshelf.&rdquo;</p>
<hr>
<h2 id="the-two-conversations-that-will-happen">The Two Conversations That Will Happen</h2>
<p><strong>Conversation #1 — &ldquo;Why is X not working?&rdquo;</strong> Happens in the first two weeks. Pi-hole blocks a domain that some app depends on (for us it was <code>app-measurement.com</code>, which Samsung Health apparently can&rsquo;t live without). Fix: open Pi-hole&rsquo;s Query Log, find the blocked domain, whitelist it. Takes 90 seconds. Whichever family member complained will think you&rsquo;re a wizard.</p>
<p><strong>Conversation #2 — &ldquo;Is this costing us money?&rdquo;</strong> In our case the answer was &ldquo;$1.69/month.&rdquo; My partner&rsquo;s response: &ldquo;That&rsquo;s less than the drip coffee I forgot to drink this morning.&rdquo; Your power rate may differ — at European rates (€0.35/kWh), the same hardware costs about $4.25/month. Print the Kill-A-Watt numbers and tape them to the server.</p>
<hr>
<h2 id="where-to-start-if-you-have-zero-experience">Where to Start If You Have Zero Experience</h2>
<p>The OptiPlex Micro route. eBay &ldquo;Dell OptiPlex Micro i5-8500T 16GB&rdquo; — $120-$150. Install Ubuntu Server via USB (the installer holds your hand). Run three commands:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo apt update <span style="color:#f92672">&amp;&amp;</span> sudo apt install docker.io docker-compose-v2 -y
</span></span><span style="display:flex;"><span>mkdir ~/server <span style="color:#f92672">&amp;&amp;</span> cd ~/server
</span></span><span style="display:flex;"><span>nano docker-compose.yml    <span style="color:#75715e"># paste the stack above</span>
</span></span><span style="display:flex;"><span>docker compose up -d
</span></span></code></pre></div><p>Navigate to <code>http://your-server-ip:81</code> — that&rsquo;s Nginx Proxy Manager&rsquo;s admin panel. Add your first domain. You now have a home server.</p>
<p>The OptiPlex sits behind our router, silent, drawing less power than a phone charger. Nobody knows it&rsquo;s there. That&rsquo;s the whole point.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Self-Hosted Beginner&#39;s Guide: 5 &#39;Aha!&#39; Moments That Hooked Me (And a Survival Map)</title>
      <link>https://toolgenix.nxtniche.com/posts/selfhosted-aha-moments-guide-2026/</link>
      <pubDate>Sun, 19 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://toolgenix.nxtniche.com/posts/selfhosted-aha-moments-guide-2026/</guid>
      <description>Five moments where self-hosting went from &amp;#39;why would anyone bother&amp;#39; to &amp;#39;I can&amp;#39;t believe this is free.&amp;#39; Includes real resource usage, a hardware roadmap with prices, and the pitfalls nobody warns you about.</description>
      <content:encoded><![CDATA[<p>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.</p>
<p>February 2024, around 11 PM, an ad played before a YouTube video I&rsquo;d already watched five times. Something snapped. I typed &ldquo;block ads at network level&rdquo; 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.</p>
<p>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&rsquo;re signing up for.</p>
<hr>
<h2 id="moment-1-pi-hole-silences-every-screen-in-the-house">Moment #1: Pi-hole Silences Every Screen in the House</h2>
<p>Pi-hole acts as a DNS sinkhole — every device on your network asks it &ldquo;where is doubleclick.net?&rdquo; and Pi-hole replies &ldquo;nowhere.&rdquo; No per-device app installs, no browser extensions that Chrome eventually kills.</p>
<p>My first deployment took about 20 minutes on a Raspberry Pi 3B I had sitting in a drawer:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>curl -sSL https://install.pi-hole.net | bash
</span></span></code></pre></div><p>The installer walks you through selecting an upstream DNS provider and a few interface choices. What caught me off guard: <strong>resource usage was laughable</strong>. 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&rsquo;d blocked 31,847 queries — nearly 18% of all DNS traffic leaving my house.</p>
<table>
	<thead>
			<tr>
					<th style="text-align: left">Metric</th>
					<th style="text-align: center">Pi-hole on Pi 3B</th>
					<th style="text-align: center">Pi-hole on Mini PC (N100)</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: left">RAM usage</td>
					<td style="text-align: center">28 MB</td>
					<td style="text-align: center">34 MB</td>
			</tr>
			<tr>
					<td style="text-align: left">CPU idle</td>
					<td style="text-align: center">0.3%</td>
					<td style="text-align: center">0.1%</td>
			</tr>
			<tr>
					<td style="text-align: left">Blocked queries (7 days)</td>
					<td style="text-align: center">31,847</td>
					<td style="text-align: center">41,202</td>
			</tr>
			<tr>
					<td style="text-align: left">Block rate</td>
					<td style="text-align: center">18.2%</td>
					<td style="text-align: center">21.7%</td>
			</tr>
			<tr>
					<td style="text-align: left">Devices protected</td>
					<td style="text-align: center">14</td>
					<td style="text-align: center">23</td>
			</tr>
	</tbody>
</table>
<p>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&rsquo;t see in the stats: family members stopped complaining about &ldquo;weird ads following them around&rdquo; within 48 hours. None of them knew I&rsquo;d changed anything.</p>
<hr>
<h2 id="moment-2-immich-replaces-google-photos-and-googles-scanning-your-library">Moment #2: Immich Replaces Google Photos (And Google&rsquo;s Scanning Your Library)</h2>
<p>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&rsquo;t: object detection <strong>on your own hardware</strong>, with zero data leaving your network.</p>
<p>I deployed it with Docker Compose:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">services</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">immich-server</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">ghcr.io/immich-app/immich-server:release</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">/mnt/photos:/usr/src/app/upload</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">env_file</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">.env</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;2283:2283&#34;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">redis</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">redis:alpine</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">database</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">tensorchord/pgvecto-rs:pg14-v0.2.0</span>
</span></span></code></pre></div><p>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 &ldquo;cat on couch 2023&rdquo; returned exact matches faster than Google Photos ever did, all while the dashboard showed exactly zero outbound connections to Google&rsquo;s servers.</p>
<p>Total cost: $160 for a refurbished OptiPlex Micro. Monthly cost: $0.</p>
<hr>
<h2 id="moment-3-nginx-proxy-manager-makes-ssl-embarrassingly-easy">Moment #3: Nginx Proxy Manager Makes SSL Embarrassingly Easy</h2>
<p>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.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker run -d <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span>  --name nginx-proxy-manager <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span>  -p 80:80 -p 443:443 -p 81:81 <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span>  -v npm_data:/data <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span>  -v npm_letsencrypt:/etc/letsencrypt <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span>  jc21/nginx-proxy-manager:latest
</span></span></code></pre></div><p>Port 81 opens the admin panel. You type a domain, check &ldquo;Request SSL Certificate,&rdquo; pick Let&rsquo;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&rsquo;s genuinely nothing to maintain.</p>
<hr>
<h2 id="moment-4-portainer-gives-docker-a-face">Moment #4: Portainer Gives Docker a Face</h2>
<p>Docker&rsquo;s CLI is powerful but unforgiving. One mistyped <code>docker compose down -v</code> and you&rsquo;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.</p>
<p>The moment I knew Portainer was worth it: I&rsquo;d forgotten which mapped ports I&rsquo;d assigned three weeks earlier, and instead of grepping through YAML files I opened the Portainer dashboard, saw every container&rsquo;s port mapping in a grid, and fixed a collision in 30 seconds.</p>
<p>Resource cost sits at roughly 85 MB RAM and negligible CPU — unnoticeable on any hardware from a Pi 4 upward.</p>
<hr>
<h2 id="moment-5-nextcloud-kills-dropbox-and-the-sync-actually-works">Moment #5: Nextcloud Kills Dropbox (And the Sync Actually Works)</h2>
<p>I&rsquo;d been paying Dropbox $120/year for 2 TB I used maybe 300 GB of. Nextcloud&rsquo;s Docker deployment gave me functionally identical file sync — desktop client, mobile app, web UI — pointed at a 1 TB SSD in my OptiPlex.</p>
<p>Two things I didn&rsquo;t expect: <strong>Nextcloud Office</strong> (Collabora Online integration) let me edit spreadsheets and documents in-browser without opening LibreOffice, and the <strong>Talk</strong> 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&rsquo;s camera upload, landing them in the same directory Immich was already watching.</p>
<hr>
<h2 id="the-survival-map-hardware-electricity-and-what-actually-breaks">The Survival Map: Hardware, Electricity, and What Actually Breaks</h2>
<p>After 18 months of running this stack, here&rsquo;s what the hardware journey actually looks like:</p>
<table>
	<thead>
			<tr>
					<th style="text-align: left">Stage</th>
					<th style="text-align: left">Hardware</th>
					<th style="text-align: center">RAM</th>
					<th style="text-align: center">Storage</th>
					<th style="text-align: center">Cost (Used)</th>
					<th style="text-align: center">Monthly Power</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: left">Beginner</td>
					<td style="text-align: left">Raspberry Pi 4 (4 GB)</td>
					<td style="text-align: center">4 GB</td>
					<td style="text-align: center">128 GB SD</td>
					<td style="text-align: center">$55</td>
					<td style="text-align: center">~$3</td>
			</tr>
			<tr>
					<td style="text-align: left">Enthusiast</td>
					<td style="text-align: left">Dell OptiPlex Micro (N100)</td>
					<td style="text-align: center">16 GB</td>
					<td style="text-align: center">1 TB NVMe</td>
					<td style="text-align: center">$160</td>
					<td style="text-align: center">~$6</td>
			</tr>
			<tr>
					<td style="text-align: left">Serious</td>
					<td style="text-align: left">Used Dell R730xd</td>
					<td style="text-align: center">64 GB</td>
					<td style="text-align: center">8×4 TB HDD</td>
					<td style="text-align: center">$450</td>
					<td style="text-align: center">~$30</td>
			</tr>
			<tr>
					<td style="text-align: left">Madman</td>
					<td style="text-align: left">Custom Ryzen build</td>
					<td style="text-align: center">128 GB</td>
					<td style="text-align: center">40 TB ZFS</td>
					<td style="text-align: center">$1,400+</td>
					<td style="text-align: center">~$45</td>
			</tr>
	</tbody>
</table>
<p><strong>The mistake I made at Stage 2:</strong> running everything off a single NVMe drive with no backup. Immich&rsquo;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.</p>
<p><strong>What nobody tells you about electricity:</strong> that &ldquo;silent&rdquo; OptiPlex Micro draws 15W idle. Over 365 days that&rsquo;s roughly 131 kWh — at US average rates ($0.14/kWh), about $18/year. The R730xd at 150W idle hits $184/year. If you&rsquo;re in Europe paying €0.35/kWh, triple those numbers.</p>
<p><strong>The family network conflict:</strong> Pi-hole blocks ads. It also blocks tracking domains that some apps require to function. My partner&rsquo;s shopping app stopped loading product images — Pi-hole was blackholing <code>api.segment.io</code>. Whitelisting that one domain fixed it, but expect 2-3 &ldquo;why is my app broken?&rdquo; conversations in the first month.</p>
<hr>
<h2 id="the-8-gb-ram-box-that-actually-runs">The 8 GB RAM &ldquo;Box&rdquo; That Actually Runs</h2>
<p>If you&rsquo;re starting with a $100 budget, this exact stack runs comfortably on 8 GB:</p>
<pre tabindex="0"><code>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
</code></pre><p>Plenty of headroom for experimenting. Add Immich ML and you&rsquo;ll want 8 GB minimum, but the non-ML stack above idles under 2 GB all day.</p>
<hr>
<p>Self-hosting starts with one &ldquo;why would anyone do this&rdquo; moment and ends with you browsing r/selfhosted at 3 AM wondering whether a used EPYC server is a reasonable purchase. It probably isn&rsquo;t. The OptiPlex Micro definitely is.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
