↓ Skip to main content
>_
Homelab Journal // Network Security Engineer

Infrastructure

Meet Gilfoyle: I Hired a Sarcastic AI to Watch My Homelab 24/7

Update, October 14, 2026. The patrols, capabilities, and trust ladder below describe Gilfoyle’s April rollout. A Level 4 policy now defines bounded authority for single-service repairs with a known rollback and fault-specific checks. The unattended controller remains inactive. Verification showed that a fresh session on the Discord route loaded the October 14 policy; already-warm sessions can retain their older prompts. The next chapter explains what changed and what still needs verification.

One MCP Server to Rule Them All: Unifying Homelab Services

Correction, September 2026. This post originally described the server as wrapping 9 services with 32 tools, including a confirmation-gated write surface and plans for an SSE transport. The maintained server is simpler and stricter than that: local stdio plus a CLI, up to 25 read-only tools across 10 configured backends, and 15 documentation resources. There are no write tools and no remote transport. Lifecycle changes (provisioning, DNS records, container updates) are owned by Semaphore automation, and the IPAM backend is now Nautobot — NetBox is retained rollback-only. The sections below have been rewritten to describe the current architecture; the original narrative is preserved where it explains the design decisions that still hold.

Building a Safe Auto-Update System for Docker After a 2 AM Outage

The 2 AM Wake-Up Call # I woke up to find my CI/CD platform had been down for 8 hours. Semaphore, the Ansible automation engine that manages my entire homelab, was stuck in a crash loop: 1 2 3 /usr/local/bin/server-wrapper: line 295: syntax error: unexpected "&&" /usr/local/bin/server-wrapper: line 295: syntax error: unexpected "&&" /usr/local/bin/server-wrapper: line 295: syntax error: unexpected "&&" The same error, repeating every few seconds. The container would start, hit the broken entrypoint script, crash, and restart. Endlessly.

Eliminating Config Drift: GitOps Auto-Deploy for Caddy HA with Semaphore

The Problem # My Caddy reverse proxy runs as an HA pair – two nodes behind a keepalived VIP. Every service in the homelab gets its traffic through this pair. The setup works great, except for one recurring failure mode: config drift. The deployment process was manual: edit the Caddy site config in git, SCP it to both nodes, validate, reload. The “both nodes” part is where things break down. It’s easy to deploy to caddy1, test it, see it working, and then forget caddy2 exists. Until keepalived fails over and suddenly half your sites return 502s because the backup node has last week’s config.

Consolidating PAN-OS Certificate Management with Caddy + Semaphore

The Problem # My PAN-OS firewall (GlobalProtect VPN portal at vpn.mareoxlan.com) needs a valid TLS certificate. I had a dedicated LXC (30122) running acme.sh with a Cloudflare DNS-01 challenge to issue a wildcard cert, then a PAN-OS deploy hook to push it to the firewall via the XML API. It worked, but it was a single-purpose VM doing the same job my Caddy reverse proxy already does – Caddy auto-renews *.mareoxlan.com via the same Cloudflare DNS-01 mechanism.

Lesson Learned: Why I Replaced Watchtower with WUD Across My Homelab

Update, September 2026. Neither Watchtower nor WUD is the current update controller. Both were fully decommissioned in March 2026 after update-related outages; container updates are now Semaphore-managed (safe-update.sh, health-gated with soak and auto-rollback). This post is preserved as the historical migration account — including its NetBox dashboard walk-through, which reflects the IPAM tool of that era, not a current deployment. The Problem # Watchtower had been my go-to for automatic Docker container updates across 8+ services. It worked… mostly. But I kept running into issues:

Migrating from Speedtest Tracker to MySpeed

Overview # I migrated my internet speed monitoring from Speedtest Tracker to MySpeed after learning that Speedtest Tracker was deprecating native Discord notifications. Rather than adding an Apprise sidecar container for notifications, I opted for MySpeed which has built-in Discord support. Why Migrate? # Factor Speedtest Tracker MySpeed Stack Laravel/PHP Node.js Discord Deprecated (needs Apprise) Native support Complexity nginx + php-fpm + SQLite Single Docker container Updates Manual WUD opt-in monitoring Architecture Comparison #

Infrastructure

My homelab runs on a 4-node Proxmox VE cluster hosting 50+ LXC containers and VMs. This wiki documents the architecture, conventions, and lessons learned. Proxmox Cluster Architecture # Cluster Specifications # Node Storage Type CPU RAM Primary Workloads Node 2 ssd-data LVM-thin 4 cores 16 GB PBS, Development Node 3 zdata ZFS 4 cores 32 GB Databases, DNS-Primary Node 5 ssd-data LVM-thin 4 cores 16 GB Graylog VM, DNS-Secondary Node 6 zdata ZFS 4 cores 32 GB Docker-Main, HA services Total Resources: