AGM Studios Alexander G. Myers

Built on my own · 2023 to today

A homelab I run like production

I started with one media server. It is now a four-guest platform with VPN-only administration, monitoring, alerting and daily backups. Every number on this page comes from the system itself.

Context I built it on one physical host, and use it daily for research, documentation and production work. My role Everything: design, build, operations and documentation Tools Proxmox VE, LXC, Docker, ZFS, Nginx Proxy Manager, WireGuard, Prometheus, Grafana, n8n

Why it matters

Hiring managers reasonably ask whether a homelab is real experience. I run this one with the habits a small company needs: every service is a managed stack, private services sit behind a VPN, failures alert a phone, backups run daily, and each incident ends with a written fix and a guard. It is also where I test tools before I recommend them.

How it is built

View diagram full sizeScroll sideways to see all of it
InternetIngressTLS reverse proxy · selectedpublic routesVPNonly way in for admin and privateappsOne physical hypervisor · four guestsService enclaveingress · shared database + cachedocuments · media · DNS filteringcredential vault · researchcrawlermonitoring + dashboardsProductivity enclaveworkflow engine · diagram editordashboards · research crawlerupdate monitor (notify-only)Egress-isolated enclaveall traffic through a VPN tunnelwith a kill-switchStorage applianceZFS mirror, ~11 TBshared to every enclaveObservability · metricsfrom every enclave → dashboardsAlert rail · failures → phoneBackups · daily snapshots,7 / 4 / 3 keptManagement plane · every serviceis a managed stack; admin UIreachable over VPN onlyRoles only: no addresses, hostnames or versions. Counts as of 25 Oct 2026.own VPN tunnel outshared storage
Roles only. The real map has addresses, routes and versions; those stay private.
made with draw.io (self-hosted), exported with the draw.io CLI last committed 2026-10-29 source file ↓

How it grew

  1. Jul – Aug 2023Desktop start

    A Kubuntu desktop running network-wide DNS filtering and a media server, before anything ran in production.

  2. Jun – Aug 2024Lab machine before the hypervisor

    Media streaming and dashboards moved onto a dedicated machine before there was a hypervisor.

  3. Aug – Sep 2024Hypervisor and core stack

    One hypervisor, a container runtime with central management, DNS filtering, a file platform with its database, a reverse proxy with TLS, a VPN for remote access, and a mirrored storage appliance.

  4. May – Sep 2025Persistent services and research tools

    A shared relational database with backups, a self-hosted crawler, a metrics server, and hardware-accelerated media processing.

  5. Mar – Apr 2026Managed application platform

    Workloads split into purpose-built containers, every service redeployed as a managed stack, monitoring with exporters, the VPN moved to a managed panel, and daily backups.

  6. Apr – Jul 2026Research and automation

    Workflow pipelines on top of the crawler, browser automation and a search-visibility harness replaced repeated manual research.

  7. Aug – Sep 2026Reliability and operations

    I added an outbound alert rail, hourly storage checks, an egress-isolated enclave, and an access gate on the management plane.

  8. Oct 2026Production studio

    I consolidated document, diagram, audio-analysis and indexing services into one environment for research, documentation and creative production.

Dated milestones

The dates come from the systems themselves: container creation times, package-manager history and dated configuration records.

compute

Desktop start

A Kubuntu desktop running network-wide DNS filtering and a media server: the first self-hosted services.

compute

Media server moves to the lab

The media server moved off the desktop onto a dedicated machine, before the hypervisor existed.

observability

First dashboards

A dashboard server for the first services.

compute

Hypervisor installed

Base Proxmox host installed; first package upgrade recorded.

storage

Shared storage

A mirrored storage appliance as its own VM; media and files moved onto it in September.

compute

Container runtime and DNS filter

Docker and central container management in the first application container; the DNS filter moved into the lab.

network

Files, ingress and VPN

A self-hosted file platform with its database, a reverse proxy serving everything over TLS, and a WireGuard VPN for remote access.

AI

AI-assisted coding

Started coding with AI through MCP tool servers, beginning with Serena, before agent coding tools were widely available.

backup

Persistent data

Shared PostgreSQL with a scheduled database-backup container.

AI

Self-hosted crawler

A self-hosted web crawler for research, scripted in Python.

observability

Metrics server

Time-series metrics collection added beside the dashboards.

compute

Hardware transcoding

GPU media driver and validation tooling added for hardware-accelerated media.

compute

Second application enclave

A purpose-built container for productivity workloads, managed from one central deployment plane.

compute

Runtime limit found and contained

A container-runtime change broke network namespaces in unprivileged containers; affected stacks moved to host networking and the version boundary was documented.

security

Credentials out of config

Storage credentials moved from a readable mount definition into a root-only credentials file.

observability

Monitoring as a managed stack

Metrics, dashboards and five exporters redeployed as one managed stack, with the configuration kept as a mounted file and hot reload.

network

VPN and DNS rebuilt

The 2024 VPN moved to a managed panel with full-tunnel profiles for travel, and the DNS filter was upgraded; admin interfaces stay VPN-only.

backup

Daily backups

Both application enclaves snapshotted daily to the storage appliance; 7 daily, 4 weekly, 3 monthly kept.

AI

Research workflows

Four workflow-engine pipelines connected to a self-hosted crawler.

storage

Incident: boot-order storage race

After a power-off the shared storage mounted before the storage appliance was ready; dependent services recovered by hand.

AI

Search-visibility harness

Seven iterations to a multi-engine harness with a 318-query bank and parser diagnostics.

automation

Full infrastructure audit

Every service, route and dependency documented in one index; dynamic DNS moved to a host timer.

observability

Alert rail

Failures on five critical paths now send a phone notification; hourly storage-binding checks; update monitoring in notify-only mode.

network

Egress-isolated enclave

A third application container whose traffic is forced through a VPN tunnel with a kill-switch.

automation

Self-hosted diagram editor

Diagram editing and scripted export run on the lab, nothing leaves the network.

AI

AI-assisted operations

Routine maintenance and documentation moved to AI tools working under a documented review process.

security

Password vault

Self-hosted credential vault; tools read secrets through a broker instead of config files.

storage

Fix generalised after a power cut

The post-boot repair now refreshes every storage-bound service on all three enclaves; the management UI moved behind a VPN-only gate.

backup

Incident: stalled backup

A backup hung on a stale storage session; aborted safely, partial snapshot removed, mount set to open fresh sessions.

storage

File platform upgrade

Six major versions upgraded one at a time with a backup before each step; mobile uploads restored.

compute

Today

Four guests, 34 running services, all defined as managed stacks.

Monitoring, from the real dashboards

I exported these four panels from the lab’s own Grafana, using a dashboard made for publication. The data is the same; only the legends are relabelled to roles.

Bar gauge: share of successful metric scrapes per service role over 30 days, from 99.75% to 100%. Bar gauge: share of successful metric scrapes per service role over 30 days, from 99.75% to 100%.
This is the share of 15-second health scrapes that succeeded over the last 30 days. It measures whether each service answered the monitoring server, not end-user uptime. It does include a power cut on 25 September.
made with Grafana, Prometheus data (15 s scrapes, 90-day retention)captured 2026-10-25legends relabelled to roles; no hosts or addresses
Step chart of running containers on the service enclave rising from 19 to 22 over 90 days. Step chart of running containers on the service enclave rising from 19 to 22 over 90 days.
Services I added over three months on the main enclave. The dips are planned upgrades and the September power cut.
made with Grafana, Prometheus data (15 s scrapes, 90-day retention)captured 2026-10-25legends relabelled to roles; no hosts or addresses
Host CPU over 30 days, mostly under 20% with a plateau near 90% from 1 to 5 October and a spike on 23 October. Host CPU over 30 days, mostly under 20% with a plateau near 90% from 1 to 5 October and a spike on 23 October.
The plateau from 1 to 5 October was 28 browser automation tabs left open by test runs. I found it when a nightly backup stalled. The fix was to close every page after use, plus a rule in the runbook. The spike on 23 October was a slow audio render; I found it and rewrote it the same day. Everything else sits under 20%.
made with Grafana, Prometheus data (15 s scrapes, 90-day retention)captured 2026-10-25legends relabelled to roles; no hosts or addresses
Memory used by containers on the service enclave over 30 days, around two gigabytes. Memory used by containers on the service enclave over 30 days, around two gigabytes.
The working memory of every container on the main enclave is usually 2 to 3.5 GB of the 8 GB it is given. The spike on 14 October was the six-step file-platform upgrade.
made with Grafana, Prometheus data (15 s scrapes, 90-day retention)captured 2026-10-25legends relabelled to roles; no hosts or addresses

Incidents, written up

I write every incident up in the same four lines. These are four of them.

Boot-order storage race
Symptom
After a power loss, shared folders looked empty inside running services.
Root cause
The storage appliance is itself a VM. The host tried to mount its share before it had finished booting, and containers kept the empty mount.
Fix
Mount only after the appliance answers, then restart every dependent service.
Guard
Start ordering, a retrying mount, a post-boot repair across all three enclaves, and an hourly check that alerts if a binding goes stale. It held through a real power cut in September.
Runtime update breaks unprivileged containers
Symptom
New stacks failed while creating their network namespace.
Root cause
A newer container runtime writes a kernel setting that unprivileged containers are not allowed to change.
Fix
Moved the affected stacks to host networking and documented the version boundary per enclave.
Guard
A written rule not to upgrade the runtime on the older enclave without a migration plan.
Document editor reports saved, file is not
Symptom
The editor said all changes were saved, but the stored document did not change.
Root cause
An internal service URL was missing a trailing slash, so save callbacks went nowhere.
Fix
Corrected the URL and recovered the edits from the service cache.
Guard
A conversion health check after any configuration change.
Mobile uploads silently blocked
Symptom
Browsing worked from the phone app; uploads did not.
Root cause
The file server had reached end of life and the current app refused to upload to it.
Fix
Upgraded through six major versions, one at a time, with a backup before each.
Guard
Check vendor end-of-life notices before chasing proxy or quota faults.

What I would tell a client from this

  • Put the storage dependency first in the boot order, and check it on a timer, not only at startup.
  • Pin and document anything that can change under you, like a container runtime or an end-of-life file server.
  • Keep admin interfaces off the internet. I reach them over WireGuard, a VPN with no licence fee, so they are never exposed to the public internet.
  • Monitoring is only useful when it reaches a person. An alert to a phone beats a dashboard nobody opens.

Limits

I do not claim an uptime percentage beyond what the scrape data shows. Recoveries happened during real incidents, not as scheduled restore drills. The lab is single-host by design, so it has no high availability.