What I Learned Automating My Home Server with AI

What I Learned Automating My Home Server with AI

There are plenty of places to land on the AI trend: doomerism, enthusiasm, skepticism, overreliance, etc. My personal relationship with AI has ebbed and flowed. Every time I see a new model I feel a bit of panic, a small identity crisis. Will my job still involve writing code? Will I still find my work fulfilling without coding? Will my job be displaced? I have a lingering fear that calls out, "please don't take from me this thing I love". Some people may resonate with that, some people may call me old fashioned.

That being said, I've never been one to shy away from using AI for taking care of my toil for me. Write an automated test, make a dataclass with these attributes, autocomplete this line for me, save me from googling "how to get the current directory in python" for the dozenth time, and the times I think "hey I've solved this problem in this other repo" and go copy and paste what I did. Remove the tedium and allow me to focus on problem solving.

Then Claude Opus 4.6 came out, friends were sending me doomer blogs, I had to check it out. What we have now seems different. I had to see for myself what was at risk and if it was worth all the hype. I got Claude Code installed, paid for the cheap tier, and tried to think of a project. I thought of the home server I built that was collecting dust. About what was keeping me from working on that. While there was so much fun tinkering to do with the server and some fun project ideas in mind, the next parts were that tedium: configuring Linux, installing software, and writing Kubernetes manifests. So I thought, let me throw this tedious unit of work, bigger than what I'd normally use an AI for, at Claude and see what it does.

Step 1 - Critiquing the Plan

I had Claude Code craft the plan (which is committed in the k8s-infra github repo). I combed through the plan with optimistic skepticism. There was a lot to like here from the initial read: the directory structure looked nice, the implementation phases made sense, and the Key Design Decisions section was a great summary of some of the choices that were about to be made.

There were a few things that gave me pause, the first one was that I don't know anything at all about Ansible and SOPS. I know from the 1000-foot view what Ansible is, but had never heard of SOPS. I knew that if I was going to let AI cook with this one, I'd be deploying something I didn't understand and couldn't support with my existing skillset. Ultimately, I decided to roll with it for now, see what AI does and then come back around for understanding later. I felt like that's what an AI embracer would do, I think?

Another choice that gave me pause was the decision to call the namespace ghost rather than blog. I just thought it was a bit strange to name the namespace after the technology in it vs. the product that will live in the namespace. The cloudflared namespace seemed OK to me since it's just a pod running the cloudflare daemon. This was a minor thing but I can be pedantic about naming. I shrugged it off for the time being and decided to let it build the repo as planned.

Step 2 - Giving the Green Light

I selected "Yes, clear context and auto-accept edits". I don't know how long exactly it took but I had Cursor open watching the files get created and was reading them as they populated. They were populating much faster than I could read. Though the Ansible and the SOPS stuff was a bit of a black box, I do have experience with K8s manifests so mainly focused on reading those for the first while. The structure and content looked right. I also love and create makefiles for most of my repos that I work with for developer productivity/convenience, and saw this Makefile had all the commands I'd need nice and packaged for me to run. Overall was happy at first glance.

But I still had to read the ansible directory which required me to do research on Ansible. There's just a bit of irony that I used to deploy to on-prem servers that were managed with Ansible but never once cared to know about it as I always wanted the infra teams to manage infra and me to focus on application development and software engineering. Now I was working with an AI wanting the same "hey Claude Code, you're my infra team, manage the infra for me", only this team is not trustworthy, should not operate without supervision, and has high stakes as it's setting up a server I'm going to host public facing stuff on. I reached enough understanding to be comfortable deploying.

Step 3 - Supervision and critiquing

After considering the .gitignore, I could see a few security risks in the repo:

  1. Anyone who reads it knows exact versions of K3s, Ghost, and cloudflared I'm running. If a CVE vulnerability gets published to the specific versions I'm running for any of these, the whole world knows I'm running that version and can potentially exploit that vulnerability.
  2. It publishes my SSH username, charlie.
  3. The fail2ban config in the ansible task file gives an attacker knowledge about brute force cadence

A combination of the VLAN isolation, firewall rules, and key-based SSH auth made the attack surface "has access to my SSH key and is inside my home network" and that's pretty acceptable to me.

Step 4 - Provisioning, Deployment, and Testing

I went through the scripts one by one. There were errors. There would have been errors had I made the scripts. Each time I encountered an error, I did what an AI embracer would do: tell AI about the error and then supervise its correction.

There was a big gotcha I noticed in the back and forth, which was Claude was overly-laser focused on making this work. One example in particular was a point where Claude Code wanted me to turn off the deny-all firewall rule on my home network to the home lab so that we could test if that's why SSH wasn't working after running make provision. I would never let that happen in a production system, and in fact I said nah let's see what else it could be first. I went and got a keyboard and monitor plugged into one of the server nodes to circumvent SSH being broken and saw the misconfiguration on the UFW rules on the server (it put its own VLAN's IP instead of the VLAN that I'd be SSHing in from). Claude was so focused on having a deployed product, that it was willing to risk security. Without informed supervision someone could have listened, and possibly never be told to turn that FW rule back on. It also didn't think about the fact that make provision had executed only because SSH was functional. If SSH stopped working afterward, that strongly implied a server side misconfiguration, not a network firewall issue.

After several back and forths, I connected to the K8s server with Lens and saw the pods spun up. The blog had been deployed, and was reachable. I played around with the blog. I had done it, beyond just research I had deployed a functional blog to the internet without any toil. There were a few cleanup things I did after the fact including adding MFA to my ghost login and changing that namespace name that bothered me earlier in plan phase.

The pods are up as seen in Lens

Step 5 - Verifying Understanding

I wanted to be sure that I had a pretty good understanding of this. I don't want to blindly run whatever to have my home server up, I did this whole project to learn and to learn for fun. So, I asked Claude Code to write me a test to verify understanding. I got a 20/23 on the test, solid enough for me to feel like I understood enough to post this thing and call the infra automation a success. So I got to work on blogging.

Takeaways

I learned about SOPS and age, both are much more interesting to me than Ansible and I intend to use the pair in future projects. I learned a bit about Ansible, and got to flex my Kubernetes muscles again

The result was a functional blog on the internet with a security model that I'm comfortable with that didn't require any toil or tedium. No copying and pasting an old K8s manifest and making slight modifications.

So where does this resolve my fears of AI? Where does it amplify them? Honestly, I'm not sure either happened. I want to be a software engineer until I retire, I love this craft. Maybe some day that doesn't involve coding, but for now AI is a major productivity win and a remover of tedium, but it clearly still requires supervision. Claude optimized for productivity. I optimized for risk.