Monday, February 16, 2026

How I Accidentally Built a Homelab - Part 2

It's been a while since I updated the blog on the mini rack.

What started with Jeff Geerling’s Raspberry Pi Kubernetes cluster video quickly turned into something much bigger. First it was self-hosting a media server. Then rebuilding my home network. Then landing a new job in tech. Then taking over management of an entire technology team.

Calling it a journey feels small. The last six months have been rapid change and constant learning.

Planning helped. Persistence helped more. And an unwillingness to quit when something broke helped most of all. That mindset has shaped this entire year.

So where is the rack now?

It has changed.

My old server was a small form factor custom PC I built almost ten years ago. It served me well. But after a string of seemingly random crashes, I traced the problem back to the motherboard.

That was the end of it.

Losing it stung. Some of the parts are still usable, including 32GB of DDR4, which suddenly became precious when RAM prices surged. But the core of the system was done.

So I needed a replacement.

My first instinct was to build again. I planned out a custom build around a MinisForum board and carefully selected components. Then the RAM shortage hit. Prices exploded. What had been a $900 build quickly approached $2,000.

That was not happening.

I explored other options. I considered building a cluster from older desktops at my new job, but none had the GPU power or PCIe connectors to even install a GPU that I needed for media encoding.

I designed hypothetical mini systems that could house a low cost Intel Arc GPU. I searched for PCIe lanes in small chassis. I went down every rabbit hole.

The market was brutal.

Then I got lucky.

While shopping at work for a small desktop to host an imaging application, I came across this:

Lenovo ThinkCentre M90q Gen 6  
Intel Core Ultra 7 265T vPro  
64GB DDR5  
1TB + 2TB storage  
Intel Arc A310 4GB GDDR6

The price was absurdly good. I genuinely thought it might be a mistake listing.

I went home that night and bought it before someone else could.

The CPU was not exactly what I had spec’d in my custom build, but it was close enough. And it cost nearly half of what I had been planning to spend.

It arrived. It was real. And it was perfect for the job.

Learning Docker

This rebuild gave me the excuse to finally learn Docker.

I installed Debian. Installed Docker. Then started spinning things up:

  • Jellyfin
  • Sonarr, twice
  • Radarr
  • Bazarr
  • WireGuard
  • Cloudflared
  • qBittorrent

And it just works.

I should have learned Docker years ago.

The new build feels significantly more stable and more secure than my previous setup. Nothing is directly exposed to the internet. Access is tunneled through Tailscale or Cloudflared. Traffic routes through a jumpbox and a VPN. It is layered and intentional.

Right now it primarily serves as a media server. But it has room to grow.

There was some slight drama with my library self deleting a few times thanks to an obscure setting in Bazarr, but her, you live and learn.

I still have a lot to learn about security. But this feels like a solid foundation.

The Physical Rack

In the middle of all this, I bought a 3D printer. A Bambu P1S.

I chose it because it is simple and I caught it on sale (MicroCenter Black Friday deals may be the only *real* deals the holiday still offers). It has been incredible for learning. I have been printing panels, mounts, airflow components, and experimenting with fit and function.

I even used it to build a temporary cabinet door for the mini rack enclosure. It is not permanent. But it keeps animals and hair out, and that is enough for now.

My Raspberry Pi cluster, which I've dubbed the Pi5x5, is currently only two nodes deep. But I confirmed my custom mounting solution works. Power distribution is solid. When prices settle, I will finish out the remaining Pis.

I also added a JetKVM to the rack. It is not fully integrated yet. I discovered Tailscale a few months ago and it has ruined every other remote access solution for me. JetKVM does not yet support native Tailscale installation in a way I am happy with. There are workarounds. I just do not feel like fighting them yet.

So it waits.

Physically, the rack is close to complete. I need to finish the Pi collection and add a few more airflow control panels. After that, the focus shifts back to software and services.


The rack and cabinet as it currently exists. 

Side Quests

As if this was not enough, I also decided this was the moment to:

  • Remove Windows 11 from my main PC and switch to Bazzite
  • Drop Discord after their announcement around legal identification requirements
  • Begin migrating this blog to a fully self-hosted solution

All of that is in progress.

And somewhere in the chaos, I lost my entire pixel art archive. That one is on me. I did not have proper backups in place. I am actively working on recovery, but it was a hard lesson.

Backups are not optional.

Perspective

There is a lot happening. And there is still a long list of projects ahead.

But these projects keep me moving. They keep me learning. They keep me growing.

Ten years ago, I was living in a friend’s basement in Chattanooga, preparing for my second year of university. I assumed I would stay there. I did not know what a VLAN was. I probably did not fully understand LAN or WAN either.

Now I manage infrastructure. I run a homelab. I design systems.

Growth happens when you stay curious.

I am grateful to be surrounded by people who push me to keep learning.

Until next time, stay warm and toasty.

Friday, May 30, 2025

A City with Mountains on All Sides

The cities have always been my home. Accessible. Loud. Crowded. A little dirty. I worked there, shopped there, wandered late-night corners and coffee shops with bad lighting and good music. And I loved it.

But somewhere in the middle of all that, I learned to love something more. Something quieter.

Chattanooga had that special blend — a city, yes, but one with mountains on every horizon and ridgelines that whispered to you if you were paying attention. You could finish your shift and be at the river’s edge twenty minutes later. You could spend a weekend in a bookstore and the next in a gorge. It made space for both.

There were nooks and secret crannies scattered all over. The kind of places with no signs. No parking lots. Just a slight thinning of the trees — a hint that someone had been there before you, and you were invited to follow.



One of my favorite places to visit was a secret: just two car-sized dirt pull-offs on the side of a mountain ridge. No trail marker. No name. If you knew where to look, you'd find an overgrown path that some stranger had beaten down years ago. It led to a rope tied to a solid oak, hanging over a fifteen-foot drop. Not exactly welcoming — but reliable.

If you trusted the rope and made your way down, a stream waited at the bottom. No trail followed it. But if you hiked far enough — through three miles of fern-bottomed forest — you'd find a waterfall. No name. No sign. No map. Just mist. Just quiet.

I never took pictures. I only shared it once — passed down from a friend who trusted me with it, and whom I trusted in return. It was a sanctuary. And in a way, I think it still is.

That place is out of reach now. Life changes. Jobs move. Roads bend. But a part of me is still there — still standing in the cold stream, still watching the light filter through leaves older than I’ll ever be.

These are some photos from around that time. Not of the secret place — that’s still sacred — but of the quiets that taught me how to pay attention.


There are places that don’t leave you. They just wait — quietly — for you to remember.


 Until next time, stay warm and toasty.

Sunday, May 18, 2025

Third Spaces, First Loves

There’s something about walking into a coffee shop that feels like stepping sideways out of time.

Maybe it’s the quiet hum of conversation, or the way the scent of freshly ground beans hits you just before the door swings shut. Maybe it’s the chipped mugs behind the bar or the fact that the barista remembers your name — and maybe even your story.

I’ve spent a lot of my life in coffee shops. I worked in them through my teens and early twenties — chain spots, local joints, third-wave dreams. I still stop into one almost every day, even if it’s just for a quick hello and a warm cup. But it’s never really just about the coffee.

Coffee shops were where I grew up — not from a kid into an adult exactly, but from someone going through the motions into someone more aware. Of people. Of ideas. Of myself.

There’s something quietly transformative about being behind the counter — learning to make drinks, yes, but also learning to listen. Learning to ask better questions. I remember those early evenings, the shop glowing softly in warm light as I practiced on the espresso machine. Everything slowed down. I’d sip on my own coffee and dig into the why of the process. The smell of fresh grounds, the hiss of steam — it felt sacred. I can’t reproduce that feeling to this day.

And over time, something subtle and profound happened: the shop became more than a workplace. It became a portal. A place where life cracked open.

I was raised in deeply conservative communities, where the world was small, the rules were clear, and being “different” often meant being feared, or worse, erased. It wasn’t cruelty, exactly — just a kind of handed-down certainty. A worldview that didn’t leave a lot of room for complexity, or curiosity, or deviation from the script.

But in coffee shops, I met people who shattered those scripts.

One of my coworkers, Travis, came in one morning still shaken — his father had screamed hateful things at him that day for being gay, for being different. He bawled before his shift, spent the day trying to keep himself together behind the bar. That moment burned into me. It was so raw, so human. And it revealed something I hadn’t let myself believe before: that the people I was taught to fear were just… people. Hurting, striving, beautiful people.

And then there was Hannah — vibrant, honest, unapologetically herself in every way. She didn’t wear a mask. She didn’t flinch when she talked about hard things. Her self-reflection and groundedness made me feel like I was living behind glass — like maybe I was a little scared to be known. She helped change that.

These weren’t sermons. They were conversations over clinking mugs and shared shifts. And they shaped me more than years of schooling ever did.

I even met my wife through coffee shop conversations. And I’ve made real friendships — people like Taylor, who remembered small details and always made time to ask how I actually was. I’ve had customers I thought I’d only speak to once come back weeks later and re-engage like we’d known each other forever. I’ve even been offered jobs, just sitting and talking at café tables.

Coffee shops hold space like that. They’re not home, and they’re not work, but they’re still ours. These third places are the quiet, public corners of the world where you can belong without needing to perform — where you can show up with a laptop, or a book, or just a heavy heart. And no one asks you to be anything but present.

That kind of space — where you’re allowed to be instead of do — it’s rare. And so, so needed.

Because third spaces don’t just give us rest. They give us the chance to grow. To change. To hear something unexpected, meet someone new, or glimpse a version of ourselves we didn’t know we were allowed to be.

It might sound lofty, but it’s true.


I think often of cafés in 18th-century France — how they became spaces for writers, philosophers, musicians to gather. Not because of some grand plan, but because the coffee shop was the place that welcomed them. Public houses full of voices. I’m no Robespierre (thank God), but I have had those conversations. The ones that reframe your understanding of the world — or of yourself. That spirit still lives on in good cafés today.


Some of the most meaningful conversations I’ve ever had happened over mugs of coffee. Some of the most surprising friendships. Some of the quietest healing.

There’s a kind of magic in that space. And that’s the kind of magic I dream of creating one day.

I still hold onto a silly little poem I wrote once, sitting in a shop during the quiet early hours. It starts like this:


"deep within the murky depths / of caffeine induced epitaphs…

cups clink and orders spoke / an entire world not yet awoke…

grab a seat / grab a cup / take a sip / grab another cup."


One day — maybe when the timing is right — I’d love to open my own place. A space called Whitecap Coffee. A place with chipped mugs and soft light. Where people feel safe, and seen, and maybe even transformed. A place where the coffee is good, but the possibility is better.


Because the world could always use one more coffee shop —

especially the kind that reminds you who you are.


 Until next time,

 Stay warm and toasty.

Thursday, May 8, 2025

How I Accidentally Built a Homelab - Part 1

First it’s “what’s Kubernetes?” and next thing you know, you’re 3D printing magnetically latched airflow panels for a custom rack build with PoE-fed Pis and a GPU-class server tucked into 12U.

 It started, as these things often do, with a question.

 

“What is Kubernetes?”


Innocent enough. I was curious about how containers scaled across systems, how people ran services in their own homes, and what it would take to dip a toe into infrastructure I could learn from hands-on. The answer — or what should have been a Wikipedia article and a weekend project — spiraled into something else entirely.

Today, I’m building a 12U white-out mini rack that hosts:

  •     A Minisforum Ryzen 9-powered NAS with 64GB of RAM
  •     A 6-bay SSD RAID array
  •     A full Ubiquiti network stack
  •     A Kubernetes cluster running across four Pi 5s with NVMe storage

    And an increasingly ridiculous number of 3D-printed panels, mesh filters, and magnetic faceplates I designed in Tinkercad.

It escalated quickly.

Why a Rack?

Another PC tower didn't suit my goals. I didn’t want loose cables running across a desk. I didn’t want a Pi cluster zip-tied to a shelf like a tech goblin. 

I wanted something compact, clean, and modular. Something that would grow with me.

Enter: the RackMate T2, a 12U 10-inch mini rack case that caught my attention while watching through a Jeff Geerling video. Just small enough to be reasonable. Just big enough to be dangerous.  With it, I could bring together networking, compute, storage, and a dedicated space to tinker without sprawl.

The Rackmate T2, featuring 12 units of space, just over 2 feet tall.

 

The Vision

I had a few key goals going into this:
  •     Quiet operation — nothing louder than a gentle fan hum
  •     Low power draw — something I could leave running 24/7 without guilt
  •     Room to experiment — containers, ZFS, Kubernetes, media, dev work, all of it
  •     Total control — no cloud dependency, no vendor lock-in
But it also had to look good. Not flashy, just intentional. I wanted clean lines, tidy cables, white PLA panels, and magnetic filters — something subtle and satisfying to build.

I planned out my goals for the rack:


 

Needless to say, I got pretty invested. I started planning first - a spreadsheet of parts, sizes, prices and links. I spent hours trawling through the GitHub page for Project Mini Rack (or the more readable webpage version) taking notes on other builds and slightly dreading having finally commit to learning how to do some 3D modeling for the sake of the customization I knew I wanted. Thankfully, I've got a friend with a printer available to me (though I did seriously consider buying one for this project).

So the spreadsheet - I broke it up into 4 parts: The Rack and Networking Gear, the Kubernetes cluster, the Server, and the NAS.

The sheet got long enough that I couldn't capture the full list.

 

Each section went through countless adjustments as I discovered new parts or solutions that would fit the build. I considered building my own case several times, scrapping the Kubernetes cluster, tossing out my ITX server plans and just re-using my current device (which is on its last legs), and the NAS went through almost a dozen different iterations of plans. 

I was constantly thinking "Should I go with HDD's or SSD's?" "Which parts can I replace to increase power efficiency?" "Should I keep a GPU on the ITX board in the server for video encoding? Or can I use an Intel CPU for encoding? Can AMD do that now?"

The back and forth gave me whiplash. But now it's all ironed out and I've committed! Probably.

I've drawn up a general plan for the placement of the equipment in the rack:

 

2U's of space left over!


3D Modeling

After looking at the price of panels for the Rackmate T2 I decided that I had to go ahead and commit myself to some 3D modeling if I was going to achieve an aesthetic that I was comfortable with being visible in my home. So, I researched some software and dove into Autodesk Fusion360's...

..and was immediately overwhelmed. 

Rather than do the reasonable thing and watch some videos on how to get started, I jumped ship over to their baby CAD: TinkerCAD. A browser based solution for learning the basics. From there I drew up a 1U panel for the server rack:

I thought it was a decent start! There were plenty of models out there for the 1U panel though, so this was just a learning experience for me to get used to the dimensional tools of the software.

I took the 1U panel over to a new project to start making the first custom panel that I was interested in: a dust filtering 3 fan panel for air intake in the rack. I went through several iterations of this model.



This was a learning experience! The first print out made it obvious that the model was too thin to support three fans:

So I made the panels a millimeter thicker on each side and added a bracing support each side that would also act as a shelf for the panels to rest on. My plan to adhere them together is some magnets in these slots:

 

I'll have to give you an update on whether or not that works! Between the movement and the weight of the fans - I may need a different solution. There should be plenty of room for 3x40 mm fans. Here's the new version with a piece of paper sandwiched between the panels as an example of where the dust filter will live:
 


This version will also need some very slight tolerance adjustments. Version 3 will be printed in a white PLA, when it arrives.

Where It’s Going

At the time of writing this, I’ve:

  • Committed to the RackMate T2

  • Ordered the Ubiquiti switch, gateway, and the Arris modem

  • Designed and printed a custom honeycomb 1U fan panel that sandwiches a mesh screen between two magnet-held layers

  • Pivoted away from traditional Mini-ITX builds in favor of a Minisforum BD795i SE for its size and performance

  • And begun building out the dream: a full-featured homelab that fits in a rack I can actually live with.

This blog is where I’ll document the process — design choices, print files, wiring strategies, thermal wins, and occasional mistakes. Because if I’m going to go overboard, I may as well leave a map for the next person who asks, “Hey… what’s Kubernetes?”

Until next time,

Stay warm and toasty.

Tuesday, April 22, 2025

Down the Raspberry Pi Rabbit Hole

The world of microcomputers like the Raspberry Pi or the ESP32 is broad and ever-expanding. I've only had the chance to work with an original Raspberry Pi way back in school, and I just began a small project with an ESP32 today (more on that to come). Needless to say, my experience is limited. But last year, I was presented with a challenge at work: get a video stream from a Ubiquiti security camera to display on a Raspberry Pi so we could monitor part of the store. An update had broken the functionality of their previous setup, and now it was on me to fix it.

So why not just use a Viewport?

Viewport is Ubiquiti’s all-in-one camera monitoring hub. It’s plug-and-play, purpose-built for their surveillance systems, and ideal for monitoring multiple streams with ease.

But the downside? The price tag: $200. Compare that to “free” (minus my many hours of labor, which probably exceeded $200, but hey). We already had the Raspberry Pi—may as well use it, right?

My first objective was to investigate the previous setup and figure out what broke.

The device ran RPIsurv, a neat little program that turned a Raspberry Pi into a dedicated video or image streaming device. It could display up to four separate streams at once. The video output ran through omxplayer, which—surprise—had been deprecated in the update that broke the setup.

Enter VLC, the new video king on Raspberry Pi.

I wasn’t upset to discover that VLC checks all the boxes: versatile, open-source, widely supported, and capable of handling nearly any media format. Unsurprisingly, VLC supports the same media stream format used by many live video feeds: RTSP (Real-Time Streaming Protocol).

My mission was now clear: use VLC to stream the camera feed.

Simple, right? Hah.

The Hacky Solution

I should mention—I did all this on Raspberry Pi OS (with Desktop), not Lite as I probably should have. (More on that later.)

I started by grabbing the RTSP link from the camera’s settings in the UniFi dashboard. But something looked off:

rtsps://192.168.1.1:7441/example_stream_id?enableSrtp

RTSPS? That wasn’t going to work. I tried anyway. No dice—stream error.

After a bit of digging, I learned that a few key changes were needed to make the link work. This was likely obfuscated for security reasons (or just to make my life harder). Either way, I’m just a dude playing with tech at the mercy of its creators.

Here’s what I had to change:

  1. Change rtsps to rtsp
  2. Change the port from 7441 to 7447  
  3. Remove ?enableSrtp

A couple of quick edits, and—voilà! VLC successfully streamed the live camera feed.

Cue self-congratulations, back-patting, and a well-earned lunch.

Except... when I got back, the stream had died.

Crashing Streams & Band-Aids

I rebooted VLC to make sure it wasn’t a fluke. It worked, but not for long. Turns out, VLC isn’t built for 24/7 streaming. Over time, memory leaks or resource exhaustion cause it to crash or hang. You can tweak VLC’s buffer settings or enable keep-alive packets, but even with those adjustments, the stream still crashed every few hours.

If you need to tweak those settings, they’re here:

  • Caching: Tools > Preferences > Show Settings (All) > Input/Codecs > Network Caching (ms) > Increase to 3000ms or more.
  • Keep-Alive: Preferences > All > Input/Codecs > Demuxers > RTP/RTSP > Enable "Use RTP over RTSP (TCP)" and set keep-alive.

Neither helped.

So I asked myself: why not just reboot VLC?

It wasn’t pretty, but the stream didn’t need elegance. It just needed to work most of the time.

The Auto-Reboot Workaround

(Before you recreate this solution, just know—it’s hacky and lame. There’s a better one below.)

First, VLC setup:

  1. Tools > Preferences > Check "Fullscreen"
  2. Audio > Uncheck "Enable Audio" (especially important for two-party consent states)
  3. Input/Codecs > Demuxers > RTP/RTSP > Enable "Use RTP over RTSP (TCP)"

Then, I made sure the stream restarted on boot:

  1. Navigate to /home/username/.config
  2. Create a folder named autostart
  3. In autostart, create a file called autovlc.desktop with the following:
[Desktop Entry]
Type=Application
Exec=vlc rtsp://192.168.0.1:7447/streamlink

Reboot to confirm it worked.

Now, to handle VLC crashing, I wrote a script to kill and relaunch it:

On the desktop, create close-launch-vlc.sh:

#!/bin/sh
killall vlc
wait
gio launch /home/username/.config/autostart/autovlc.desktop

Then, in the terminal, make it executable :

chmod +x /home/username/Desktop/close-launch-vlc.sh

To automate this script every two hours, I used cron. First I had to check the display number:

echo $DISPLAY

For me, it was "0", then I opened up crontab:

sudo nano /etc/crontab

At the top:

DISPLAY=:0

At the bottom:

0 */2 * * * username /home/username/Desktop/close-launch-vlc.sh

Save and exit. Now, the stream rebooted every two hours.

It wasn’t ideal, but it kept the stream alive.

The Actual Fix

Until it didn’t.

The guy sitting near the monitor got tired of fullscreen hangs and reboot hiccups. He demanded a real fix.

Fine. Fine.

So, I decided that Raspberry Pi Desktop was too resource heavy for the little 1GB Raspberry Pi 3 that I was building this on. I installed the lite version and SSH'd into the thing. VLC wasn't ideal for this purpose. I tried a few other options.

My fiddling led to the RPi refusing to boot twice, one accidental reboot when I ran the reboot command in my own laptop's terminal instead of within the SSH session, and lots of cursing. Several attempts with several tools later, I landed on ffplay

After a lot of trial and error (I'm not much of a scripter to be honest) this is the code block I ended up with:

#!/bin/bash

# === 1. Update system ===
sudo apt update && sudo apt upgrade -y

# === 2. Force HDMI output & resolution ===
sudo sed -i '/^#*hdmi_force_hotplug/d' /boot/firmware/config.txt
sudo sed -i '/^#*hdmi_group/d' /boot/firmware/config.txt
sudo sed -i '/^#*hdmi_mode/d' /boot/firmware/config.txt
sudo sed -i '/^#*config_hdmi_boost/d' /boot/firmware/config.txt

echo "hdmi_force_hotplug=1" | sudo tee -a /boot/firmware/config.txt
echo "hdmi_group=1" | sudo tee -a /boot/firmware/config.txt
echo "hdmi_mode=82" | sudo tee -a /boot/firmware/config.txt   # 1080p
echo "config_hdmi_boost=7" | sudo tee -a /boot/firmware/config.txt

# === 3. Install lightweight X server and ffmpeg ===
sudo apt install --no-install-recommends xserver-xorg xinit openbox ffmpeg -y

# === 4. Create .xinitrc with placeholder RTSP stream ===
cat <<EOF > ~/.xinitrc
#!/bin/bash

# Replace the RTSP_URL below with your own stream.
RTSP_URL="rtsp://YOUR_CAMERA_URL_HERE"

if [[ "\$RTSP_URL" == "rtsp://YOUR_CAMERA_URL_HERE" ]]; then
  echo "❌ Please edit ~/.xinitrc and set your RTSP stream URL before using startx."
  sleep 5
  exit 1
fi

ffplay -fs -noborder -an -fflags nobuffer -flags low_delay "\$RTSP_URL" > ~/ffplay.log 2>&1
EOF

chmod +x ~/.xinitrc

# === 5. Enable console auto-login ===
sudo raspi-config nonint do_boot_behaviour B2

# === 6. Add startx to bashrc only for TTY1 ===
if ! grep -q 'startx' ~/.bashrc; then
  echo '' >> ~/.bashrc
  echo 'if [ "\$(tty)" = "/dev/tty1" ]; then' >> ~/.bashrc
  echo '  startx' >> ~/.bashrc
  echo 'fi' >> ~/.bashrc
fi

echo ""
echo "✅ Setup complete!"
echo "👉 To finish setup, edit ~/.xinitrc and paste in your RTSP stream URL."
echo ""
echo "Rebooting in 5 seconds..."
sleep 5
sudo reboot

 The script can be found over on my github. The beauty of this is that its one command to replicate it now. It just requires entering in the RTSP stream.

It took some learning and fiddling, but the stream is now up 24/7 without the need for reboots or hangups. Plug and play. Without the hackiness.

If you're interested, I used a few different videos while learning how to set this up: Eugene Tkachenko sets up a stream using a camera module directly on the Raspberry Pi itself. That Project created a wireless camera very similarly to Eugene, but had some code snippets in his video that I found very useful.

A Raspberry Pi and other Internet of Things devices are powerful tools, when in the right hands. It took a while for my hands to be the right ones here. 

I've got some more projects with IoT devices coming up, one focused on my love of Pokemon, of all things! 

Until then.

Stay warm and toasty.

 

How I Accidentally Built a Homelab - Part 2

It's been a while since I updated the blog on the mini rack. What started with Jeff Geerling’s Raspberry Pi Kubernetes cluster video qui...