Catching up to now
My first piece of hardware that I could truly consider my homelab was the mainboard for a Framework 13" laptop. I got the first model when they came out in the Intel i5 configuration and that laptop lasted me through university. When the Ryzen model of mainboards came out, I upgraded to them. Because the memory went from DDR4 to DDR5, the old board only needed a drive to be usable. I got the external enclosure and ethernet expansion card and that served as my faithful homelab for a couple years. It hosted my Resonite headless server, ran my Jellyfin and related servers, a Grafana server, my HomeAssistant VM, and a reverse proxy to tie them all together.
In the very beginning though, when all I had to host was a couple Resonite headless servers, I shied away from Docker because I didn't know how it worked and that scared me. I had custom scripts that I'd use to automatically update and manage the server (scripts which broke. Often). At one point, I even created an iOS shortcut which allowed me to directly manage my server's friend list via the macro button on my phone. It was neat and I used it here and there! Eventually though, the hassle became too much and then I decided to try Docker Compose. I saw that it was a reliable way to create containers and do so reliably across systems. This would be useful in the event I wanted to migrate to a new machine down the line. Just one taste of Docker and I was hooked. I basically did the meme with the bird.

Once you add one Docker container, you add another. And another. And another... You just keep collecting them, and eventually you want a better way to manage them. Up until now, I would break out each Docker compose stack into its own file and have one "master" file that points to all of them. On top of this, each stack would have its own folder where all the bind mounts are stored. The idea is that saving this one single folder will theoretically preserve the entire setup and make portability a breeze.
After adding some administrative containers such as copyparty and dozzle I eventually decided that I needed a proper container management interface. Enter: Portainer! Also ran via a Docker container, Portainer provides a web GUI to manage all your containers, update them, attach or open shells in them, make new ones, and much more. I got the free edition since none of the enterprise features came close to being required for my workflow. Things were going alright, but I felt like I needed to test the ultimate premise of why exactly I switched to Docker - the portability. I took a comprehensive backup of my Docker folder, exported my Portainer backup, and used this experiment as a chance to do a fresh reinstall of Ubuntu Desktop on my homelab server. I get Ubuntu installed, launch Portainer, pull the backup...and...nothing. All my containers are gone. Lo and behold, by creating the containers individually, I did the equivalent of "docker run", when I should have been utilizing the "stack" workflow instead.
While this didn't represent a total loss of my homelab up until this point, it did present a major pain of having to figure out how all the containers were configured, where their bind mounts went, and get all the environment variables set properly again. This was such a monumental task that I opted to move away from Portainer entirely (which turned out to be a good idea given their current business direction) to a new Docker management solution. I tried a couple and they all had their issues. That was, until I found Dockhand. It did everything I needed to do in a simple UI. The only small gripe was that there was no way to attach to a currently running container (which has since been added) which I would only rarely need to do, so it was worth shifting over to SSH in directly with a "docker attach".
Besides some basic hardening such as breaking out all containers into individual docker networks that only see the containers they need to see, that is where my setup runs even now, but the hardware itself has certainly changed...

In what I am sure has exhausted all of my luck for the next decade, my workplace was throwing out a fileserver that they had no longer needed, and for ~reasons~, they couldn't sell it. My chill manager was kind enough to let me take it home with me. Pictured above is my current server - a Dell Poweredge R740 with 128gb of RAM and 8x500gb Intel SSDs. This didn't immediately replace my old Framework board though, as that small board had just one thing that my shiny new (old) server didn't - a GPU. Granted it was an iGPU, but it had a GPU nonetheless. If I were to migrate everything over, my Jellyfin and Immich stacks would likely pin CPU usage when needing to run transcoding or ML tasks. Eventually I pulled the trigger on an Intel Arc A380, and after some headaches with PCIe passthrough, cable lengths, and case clearances, I got it working and migrated everything over. My Framework board now sits powered off and resting after its long and faithful service, ready to be rehomed and hopefully instill a similar interest in homelabbing.
That brings us to now. Looking back, so much has changed on both a hardware and software level. I started with a laptop motherboard with hardcoded management scripts to a proper blade, an OS Hypervisor, Docker containers, redundant network links, and even UPS protection against power outages. I look forward to seeing what I do in the future. I'm sure my bank account isn't, however.