<?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>Self-Hosting on GaruGaru Blog</title><link>https://blog.garu.me/tags/self-hosting/</link><description>Recent content in Self-Hosting on GaruGaru Blog</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><managingEditor>garuglieritommaso@gmail.com (Tommaso Garuglieri)</managingEditor><webMaster>garuglieritommaso@gmail.com (Tommaso Garuglieri)</webMaster><lastBuildDate>Fri, 01 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.garu.me/tags/self-hosting/index.xml" rel="self" type="application/rss+xml"/><item><title>How I run my homelab</title><link>https://blog.garu.me/posts/homelab/</link><pubDate>Fri, 01 May 2026 00:00:00 +0000</pubDate><author>garuglieritommaso@gmail.com (Tommaso Garuglieri)</author><guid>https://blog.garu.me/posts/homelab/</guid><description>&lt;p&gt;I&amp;rsquo;ve been using my homelab for a year now, and I&amp;rsquo;m starting to feel pretty happy about it. By &amp;ldquo;happy&amp;rdquo;, I mean I can stop tinkering and firefighting, and actually start using it.&lt;/p&gt;
&lt;p&gt;As the sole (happy) user and maintainer, I’m writing this blog post to describe the ideas and steps behind the creation of my small lab.&lt;/p&gt;
&lt;h1 id="hardware"&gt;Hardware&lt;/h1&gt;
&lt;p&gt;The main drivers behind my hardware choices were the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ease of replacement&lt;/strong&gt;: No fancy enterprise-level or obscure hardware, everything has to be standard and easily replaceable in case of failures.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Power consumption&lt;/strong&gt;: Since it runs in my home, I wanted low power usage, which also translates to lower temperatures and less noise.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Form factor&lt;/strong&gt;: I wanted everything to fit in a small, portable setup that doesn’t take up an entire room.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Given those principles, the hardware I&amp;rsquo;m currently using is:&lt;/p&gt;</description><content:encoded><![CDATA[<p>I&rsquo;ve been using my homelab for a year now, and I&rsquo;m starting to feel pretty happy about it. By &ldquo;happy&rdquo;, I mean I can stop tinkering and firefighting, and actually start using it.</p>
<p>As the sole (happy) user and maintainer, I’m writing this blog post to describe the ideas and steps behind the creation of my small lab.</p>
<h1 id="hardware">Hardware</h1>
<p>The main drivers behind my hardware choices were the following:</p>
<ul>
<li><strong>Ease of replacement</strong>: No fancy enterprise-level or obscure hardware, everything has to be standard and easily replaceable in case of failures.</li>
<li><strong>Power consumption</strong>: Since it runs in my home, I wanted low power usage, which also translates to lower temperatures and less noise.</li>
<li><strong>Form factor</strong>: I wanted everything to fit in a small, portable setup that doesn’t take up an entire room.</li>
</ul>
<p>Given those principles, the hardware I&rsquo;m currently using is:</p>
<ul>
<li>2x Raspberry Pi 5 - 8 GB memory</li>
<li>1x Raspberry Pi 3 - 1 GB memory</li>
<li>1x Mini ITX - Intel N100 - 8 GB memory - 3x 512 GB SSD</li>
<li>1x TP-Link TL-SF1005D</li>
</ul>
<h2 id="rack">Rack</h2>
<p><img src="rack-0.jpg" alt="Rack"></p>
<p>Online you can find many pre-built racks in all shapes and sizes, but as tinkerers we’re never 100% satisfied with something that comes with all the bells and whistles. So of course, I&rsquo;ve decided to build my own.</p>
<p>I started by designing a 3D rack to fit everything in the smallest space possible while keeping a modular design.
It took a while (and more wasted filament than I’d like to admit) but in the end, it turned out pretty nice.</p>
<p>I’m using a BambuLab A1 Mini, which is a great printer but has a small build volume (18x18x18 cm). This added an extra challenge, since everything had to be modular as I physically couldn’t print large parts in one go.</p>
<p>I ended up with a simple yet modular design (I’m not a 3D designer, please forgive me): stackable layers. Each layer has vertical columns and interchangeable front plates (masks) that can expose I/O ports, hold fans, or mount components easily.</p>
<p><img src="rack-1.png" alt="Rack"></p>
<h2 id="power-consumption-and-thermals">Power consumption and thermals.</h2>
<p>The entire setup consumes about <strong>~20W</strong>:</p>
<ul>
<li>12W from the 3 RPIs</li>
<li>8W from the NAS + 3 SSDs</li>
</ul>
<p>Under full load both disks and cpu running ~80% it can reach 30–40W, but this rarely happens in real-world usage, so overall I’m very happy with it.</p>
<p>The RPIs are cooled by a single 80mm Noctua fan and maintain temperatures around 40–50°C. The NAS runs completely fanless for now, although I’ve already designed a mount for a fan if needed in the future.</p>
<h2 id="software">Software</h2>
<p>So what’s actually running in the homelab, and how do I manage it?</p>
<p>Every machine runs the same Ubuntu LTS version configured using ansible.</p>
<p>I tried more &ldquo;fancy&rdquo; solutions like NixOS, CoreOS, pre-baked images, or cloud-init/ignition, but I ultimately wanted something simple and stable, not something prone to breaking changes or deprecations.</p>
<p>In the end, since I just install the same common packages with very minimal configuration I want to be able to run the same commands in 5–10 years and bring everything back up without surprises.</p>
<h3 id="kubernetes">Kubernetes</h3>
<p>I chose to run Kubernetes (using k3s), even though it goes against the goal of simplicity. The main reasons for this decision were my existing experience with running Kubernetes clusters, as well as the wide range of tooling and deployment options available for the software I wanted to use, also see <a href="https://ergaster.org/posts/2025/07/09-kubernetes-black-friday">kubernetes is not just for black friday</a></p>
<p>I’m running a two-node cluster: 1 master and 1 worker, both on RPIs. The master node uses an NVMe disk because Kubernetes state store tends to generate high disk I/O which already killed a few SD cards during the first year.</p>
<p>Cluster bootstrap is handled by a simple Ansible playbook that installs dependencies and configures both the OS and Kubernetes.</p>
<h4 id="gitops">Gitops</h4>
<p>Once the cluster is running, I use <a href="https://fluxcd.io/">fluxcd</a> for GitOps. It keeps all Kubernetes resources in sync with the desired state stored in Git.</p>
<p>This way, I can update, install, and maintain dependencies simply by pushing to a Git repository. Flux handles the deployment rollout without requiring direct access to the cluster and helps prevent state drift. It’s also useful if I ever need to recreate the cluster from scratch, since I don’t have to worry about forgetting dependencies between services and resources.</p>
<p>The cluster configuration is stored in a <a href="https://github.com/garugaru/garu-kube">public github repository</a>, most of the application are deployment using the provided helm chart, but I&rsquo;m trying to migrate as much as possible to <a href="https://kustomize.io/">kustomize</a> because I find it simpler.</p>
<h4 id="secrets-management">Secrets management</h4>
<p>Since the repository is public but I run sensitive services (like Immich and databases), secrets are encrypted using <a href="https://github.com/bitnami-labs/sealed-secrets">sealed secrets</a>.</p>
<p>The encryption key is generated during cluster bootstrap and used to decrypt secrets across services.</p>
<h4 id="persistence">Persistence</h4>
<p>My home lab runs many stateful applications, some of which also require relatively high-performance storage, such as PostgreSQL databases, Immich for photo storage, and Navidrome for music streaming.</p>
<p>There are many storage solutions that run on top of Kubernetes, but I wanted to <strong>separate compute from storage</strong> as much as possible so that I can experiment with, scale, or even completely destroy the “compute” side of my homelab without losing important data.</p>
<p>The final solution was to use my ZFS NAS as storage provider: exposing ISCSI volumes to my kubernetes cluster which support <a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/">mounting NFS / ISCSI volumes natively</a>. This also enables transparent storage mounting, allowing stateful workloads to move seamlessly between nodes without issues.</p>
<p>This way, I can store and persist data using high-performance, redundant NAS disks while keeping volume management simple by integrating directly with the Kubernetes APIs.</p>
<p>Using iSCSI disks instead of NFS not only provides better performance, but is also a safer way to run PostgreSQL, SQLite, and other systems that expect block-level I/O rather than file-level access.</p>
<h3 id="nas">NAS</h3>
<p>The NAS, which sits at the top of my rack, is based on an Intel N100 Mini-ITX board with three SSDs attached: one for the OS, and the other two mirrored as part of a ZFS pool</p>
<p>Since I wanted simplicity and full control over the storage, I’m not using solutions like TrueNAS or Unraid, just plain ZFS configured via an Ansible playbook.</p>
<p>ZFS mirrors the two SSDs and exposes volumes via an iSCSI interface to the Kubernetes cluster.</p>
<h4 id="backups">Backups</h4>
<p>Having redundant copies of your data is good, but keeping those copies physically in the same location and on the same machine isn’t ideal.
For this reason, I also maintain daily incremental backups of the ZFS volumes, which are pushed to <a href="https://www.backblaze.com/">blackbaze storage</a>, it is relatively inexpensive and provides an S3-compatible API.</p>
<p>To perform the backups I wrote a small go program that runs in the NAS, it leverages the <a href="https://docs.oracle.com/cd/E19253-01/819-5461/gbchx/index.html">ZFS incremental snapshot + send</a> features to take the backup and stream them directly to s3.</p>
<p>To avoid having too many incremental parts in case of restore I also take a new full backup every 6 months, removing the older incremental backups to save storage costs and headaches.</p>
<h3 id="what-im-running">What I&rsquo;m Running</h3>
<p>Here&rsquo;s a brief list of what I&rsquo;m running in my homelab:</p>
<ul>
<li>
<p><a href="https://immich.app/">immich</a>: photo manager, good google photo alternative with many nice features, good UI and native mobile app, very stable so far.</p>
</li>
<li>
<p><a href="https://www.navidrome.org/">navidrome</a>: simple and small audio streaming service, I use it to stream my music collection to multiple devices.</p>
</li>
<li>
<p>home assistant: (see below for more details)</p>
</li>
<li>
<p>eink display api: small api which provide images for my DIY smart frame built using and ESP32 and Eink display</p>
</li>
</ul>
<p><img src="eink-0.jpg" alt="frame"></p>
<ul>
<li>
<p>Adguard: DNS level ad blocker for all devices in my LAN.</p>
</li>
<li>
<p>surf condition bot: Telegram bot which detect good surf conditions and send me short webcam videos from surf spots nearby me.</p>
</li>
<li>
<p>cert-manager / external dns: automatically generates ssl certficates and updates DNS records when exposing new services.</p>
</li>
</ul>
<h3 id="home-assistant">Home assistant</h3>
<p>The lone RPI 3 is running home assistant installed directly as OS, using a zigbee dongle it is able to control zigbee devices in my home which are mainly smart switches / light bulbs.</p>
<p>I decided to go for zigbee as I didn&rsquo;t want to rely on third-party APIs or proprietary solutions to control my home devices. Zigbee offers a standard protocol supported by many vendors which doesn&rsquo;t require internet or LAN connection to work.</p>
<h4 id="valetudo">Valetudo</h4>
<p><img src="roomba-0.png" alt="Roomba"></p>
<p>I&rsquo;ve also modified my smart vacuum cleaner, which apparently runs Tina Linux, by installing <a href="https://valetudo.cloud/">valetudo</a> on it.
Valetudo is a nice software which allows you to disconnect your smart vacuum from the internet while keeping the original navigation capabilities.
Using the MQTT plugin I&rsquo;m able to control the vacuum cleaner directly from home assistant automations which is pretty handy.</p>
<h3 id="future-ideas">Future ideas</h3>
<ul>
<li>Since I&rsquo;m using FluxCD only to apply kustomize/helm resource I may be able to use a simpler gitops solution.</li>
<li>Experiment with immutable OS on all nodes.</li>
<li>I&rsquo;m building my own small metrics database as prometheus is too resource heavy for my small setup.</li>
</ul>
<h2 id="conclusions">Conclusions</h2>
<p>This is pretty much what I&rsquo;ve done so far to build and maintain my homelab. I&rsquo;ll try to keep this article updated, as I&rsquo;ll be using it as a sort of brain dump. Thank you for reading this far!</p>
]]></content:encoded></item></channel></rss>