# Home Lab

> A small always-on fleet for data backup and coordination, agentic development, network privacy, and keeping old hardware out of the bin

- HTML version: https://robbiepalmer.me/projects/homelab
- Status: in_progress
- Started: 2026-08-02
- Technologies: Tailscale, AdGuard Home, t3-code, Claude Code, Codex, Grok Build, opencode, Ente, DVC, Netdata, NixOS, CUPS, Docker

# Vision

A small, always-on fleet of machines in my home that handles the recurring
infrastructure of my digital life — backups, remote development, network
privacy — so I don't have to remember to do it by hand.

The home lab exists to serve four goals, in priority order:

1. **Data backup and coordination.** Cloud photo libraries, datasets, and
   project files get reliably synced and backed up without manual effort.
   Manual drive synchronisation has failed repeatedly; the point of this
   project is to make it someone else's job.
2. **Agentic development environments.** An always-on machine hosts my coding
   agents (Claude Code, Codex, opencode, Grok Build) behind a mobile-friendly
   GUI, so I can drive real development work from my phone over the tailnet.
3. **Privacy.** Network-wide ad and tracker blocking keeps my devices from
   phoning home to trackers, applied to every device on the LAN regardless of
   what it runs.
4. **Avoiding ewaste.** Old, "unsupported" hardware — a 2011 printer, a
   Pascal-era GPU, and two older phones — gets a second life doing useful work
   instead of filling a landfill.

A secondary goal that runs through the whole project is upskilling on
networking, DNS, and heterogeneous orchestration. The lab is a real system to
learn on, not a toy.

Everything is reachable over my [Tailscale](/projects/homelab/adrs/000-tailscale)
tailnet, so I can inspect and drive the whole lab from any of my devices.

# Problem Statement

The problems the lab solves are the recurring ones that manual effort handles
badly:

**Manual data sync is painful and lossy.** Copying photos and files between
drives by hand is easy to forget, easy to get wrong, and leaves no audit
trail. The cloud photo library has grown into the single source of truth for
family photos, and a single point of failure.

**Agentic development needs a persistent host.** Coding agents are most useful
when they run somewhere always-on with the right repos, credentials, and tools
already prepared. A laptop that sleeps when closed can't drive a session from
a phone. Mobile "cloud" agent environments exist, but they re-bootstrap
context each time, and they're slower, less reliable, and burn more tokens
than a prepared local environment.

**Home devices make a lot of tracking DNS traffic.** Without network-wide
filtering, apps and embedded trackers on phones, TVs, and streaming boxes
resolve ad and analytics domains on every device on the LAN. Fixing this at
the DNS layer covers devices nothing else can be installed on. This adds a
dependency (the resolver), so it has to be built with redundancy from the
start.

**Unsupported hardware is actually still fine.** The Canon MX3100 printer
(2011), the GTX 1060 (2016), and two older phones are past their vendor
support windows, but each still works for a real job if the right software
bridges the gap. Buying new kit to replace them is wasteful when the
constraint is software, not silicon.

# User Stories

* As the owner of thousands of family photos, I want them automatically
  synced from the cloud down to a local 10TB drive, so I have an offline
  backup that doesn't depend on a subscription or the internet.
* As a developer working away from my desk, I want to open the home hub's
  agent GUI on my phone and have working repos, credentials, and a choice of
  agents, so I can keep shipping from the sofa.
* As someone with two Codex subscriptions, I want both managed in one place,
  so I can use each plan's allowance and pick the best-fitting one per task.
* As a household with a home router, I want ad and tracker blocking applied
  network-wide with automatic failover, so every device is protected even if
  one DNS box reboots.
* As someone who owns a 2011 printer, I want to print from my phone remotely
  over CUPS, so I keep using hardware that still works and avoid ewaste.
* As someone running a NixOS box, I want the whole config declared in git, so
  an upgrade can never silently break the GPU and every change is reviewable
  and rollbackable.
* As the lab owner, I want Netdata to tell Slack when something is
  overheating or down, so I find out about problems before they matter.

# Topology

```mermaid
flowchart LR
Internet["Internet"] -->|"router DNS"| Router["Home router"]
subgraph hub["Mac mini — home hub"]
  ADG1["AdGuard Home — primary DNS"]
  ENT["Ente sync"]
  NET1["Netdata"]
  T3["t3-code + agents"]
  JEL["Jellyfin — planned"]
end
subgraph pi["Raspberry Pi"]
  ADG2["AdGuard Home — fallback DNS"]
  NET2["Netdata → hub"]
  CUP["CUPS"]
end
subgraph asus["Asus desktop (NixOS) — proposed"]
  GPU["GTX 1060 — CV jobs"]
  DVC["DVC dataset cache"]
end
Router --> ADG1
Router --> ADG2
ADG2 --> ADG1
Phone -->|"photo upload"| Ente["Ente cloud"]
Ente -->|"download backup"| ENT
ENT --> HDD[("10TB HDD")]
NET1 --> Slack["Slack"]
NET2 --> Slack
CUP --> Printer["Canon MX3100 (2011)"]
JEL --> FireStick["Fire TV Stick"]
GitHub["GitHub"]
Phone["Phone"]
Phone -->|"agents"| T3
T3 -->|"repos / PRs"| GitHub
hub -->|"WoL (L2 broadcast)"| asus
```

# Nodes

## Mac mini — the home hub

The primary always-on machine and the heart of the lab. It runs the two most
important jobs: hosting my agentic development environment and owning the
photo backup pipeline.

* **Agentic development hub.** Installs [Claude Code](/projects/homelab/adrs/002-claude-code),
  [Codex](/projects/homelab/adrs/003-codex) (both subscriptions),
  [opencode](/projects/homelab/adrs/005-opencode) and
  [Grok Build](/projects/homelab/adrs/004-grok-build), all orchestrated from
  [t3-code](/projects/homelab/adrs/006-t3-code) so I can drive remote,
  mobile-friendly, agentic development.
* **Photo backup.** Connects to [Ente](/projects/homelab/adrs/007-ente-photo-backup),
  the end-to-end encrypted cloud photo provider, and regularly syncs my
  library down to a connected 10TB HDD as an offline backup.
* **DNS privacy.** Runs [AdGuard Home](/projects/homelab/adrs/001-adguard-home)
  as the primary DNS server that my router points at. It blocks \~33% of all
  requests over my home network. AdGuard is also reachable over the tailnet,
  so the phone keeps blocking trackers and ads on cellular or any other
  network — coverage a router-level setup can't provide.
* **Monitoring.** Runs [Netdata](/projects/homelab/adrs/009-netdata),
  connected to my Slack workspace via a Slack app, to alarm on anything
  going wrong.
* **Media (planned).** Will run [Jellyfin](/projects/homelab/adrs/011-jellyfin)
  to serve TV shows and movies to my Fire TV Stick.

## Raspberry Pi — the resilient sidekick

A secondary node that removes single points of failure from the two things
the whole house depends on: DNS and monitoring.

* **Secondary AdGuard Home.** The home router also points at the Pi, so if
  either DNS box is down (e.g. during reboots) the other keeps the network
  functioning.
* **Netdata child.** Exports metrics to the Mac mini as the main hub, and
  alerts my Slack workspace if its temperature climbs too high.
* **CUPS print server.** Runs CUPS connected to my 2011 Canon MX3100
  printer, which is no longer supported by Canon — but with Gutenprint, the
  open-source driver suite, I can still print to it (and even print remotely
  from my phone), keeping working hardware out of landfill.

## Asus desktop — the NixOS GPU worker (proposed)

A headless wake-on-demand box, to be configured declaratively with
[NixOS](/projects/homelab/adrs/010-nixos-gpu-worker).

* **Old, unsupported 1060 GPU.** The GTX 1060 is Pascal-era (`sm_61`) — CUDA
  13 and the newer driver branches dropped support for it, so the config
  will pin an LTS kernel and the 580 driver branch, the last with Pascal
  support.
* **Batch GPU CV jobs.** The ambition is to use it for running batch computer
  vision jobs — the exact workload that doesn't need a modern GPU, just many
  GPU-hours.
* **DVC data cache.** It inherits the
  [DVC ADR](/projects/homelab/adrs/008-dvc) and its 1TB connected HDD will
  hold local copies of datasets for the ML pipelines
  (`ml-pipelines/recipe-parsing/`) and any CV work.
* **Wake-on-LAN.** It will sleep when idle and be woken on demand. The WoL magic
  packet is a Layer 2 broadcast, so it can't travel over the tailnet — the
  Mac mini, on the home LAN, sends it when a wake request arrives from a
  remote device.

## Future: the idle 4080 laptop

I have an idle laptop with a 4080 GPU in it. Once the NixOS box proves out
the wake-on-demand pattern, the laptop is a natural candidate for a second,
much faster compute node — particularly for heavier inference or training
that the 1060 can't handle.

## Future: old phones and the iPhone 6s

Two older Android phones (Android 10 and Android 14) and an old iPhone 6s are
still functional. They're candidates for lightweight roles: a spare secondary
DNS node, a status display, a camera, or spare test targets for agentic work.
The Android devices are the more capable candidates; the iPhone 6s is limited
by a locked-down OS. No commitment yet — this is an open question.

# Plan

The lab is being built incrementally, starting from the highest-value
workloads and layering on the rest:

| Phase | Workload                                                      | Status   |
| ----- | ------------------------------------------------------------- | -------- |
| 1     | Photo backup (Ente → 10TB HDD)                                | Live     |
| 2     | Agentic development hub (t3-code + agents)                    | Live     |
| 3     | DNS privacy (AdGuard Home, primary + failover)                | Live     |
| 4     | CUPS printing on the Pi (avoiding printer ewaste)             | Live     |
| 5     | NixOS GPU worker for batch CV jobs, with DVC-managed datasets | Proposed |
| 6     | Jellyfin media server for the Fire TV Stick                   | Proposed |
| 7     | Second compute node (idle 4080 laptop)                        | Idea     |

# What This Is Not

* **Not a public service.** Everything is behind the tailnet. No ports
  forwarded to the internet, no exposed dashboards.
* **Not a data hoard.** Bulk data has a purpose and an owner: the photo
  backup, local dataset copies, and (planned) media library. Backup scope may
  grow to documents, games, movies, TV, and music, but each addition has to
  earn its place.
* **Not a fixed shape.** The lab started as a handful of machines doing
  boring jobs. If it grows past that — a proper NAS, or Kubernetes for the
  compute nodes — that's on the table rather than ruled out.

# Future Direction

Beyond the phases above, there are ideas on the horizon that would lean into
the same four goals:

* **Offsite backup.** The 10TB drive is a second copy, but it's in the same
  house. A cheap offsite target (a friend's tailnet node, or cold storage)
  for the photo library would close the last gap in the backup story.
* **Expanded backup scope.** Documents, game saves, movies, TV, and music
  are candidates for the same sync-and-verify pipeline as the photos.
* **Dashboards on this site.** Netdata graphs and lab status could be
  surfaced as a page on this site, so the lab is visible to anyone looking.
* **Heterogeneous orchestration.** As the lab grows past one or two compute
  nodes, scheduling GPU work across the 1060 box and the 4080 laptop becomes
  a genuine upskilling exercise in heterogeneous clusters — possibly growing
  into Kubernetes.
* **Old phones in the cluster.** The Android phones and iPhone 6s as
  lightweight nodes (see above).

# Risks

## DNS is a single point of failure for the whole house

Running a local resolver adds a dependency that didn't exist before: if both
AdGuard Home instances go down, every device in the house loses DNS and the
internet "stops working."

**Mitigation:** Two independent DNS nodes on separate hardware with the
router configured to fail over. The Pi keeps working during Mac mini reboots
and vice versa.

## Photo backup silently failing

A sync pipeline that fails quietly means the library quietly isn't backed up.
Catching that late is only slightly better than not having a backup at all —
but the risk is real, so it's monitored.

**Mitigation:** Netdata monitors the sync process and alerts Slack on
failure or when the HDD fills up. The backup is treated as a system to be
monitored, not a script to be forgotten.

## Agent blast radius

The Mac mini holds credentials, plugins, and browser state for remote agent
sessions, and it also holds personal photos and the backup drive. A broad
permission profile on any one agent could expose unrelated personal data, and
an agent acting wrongly could delete things as easily as read them.

**Mitigation:** The [Codex ADR](/projects/homelab/adrs/003-codex) already
documents the need for least-privilege filesystem rules and sandboxing on
the connected host. This stays a first-class concern as more agents land on
the hub, with backups covering the "wrong deletion" case.

## Pascal never comes back

The 1060's driver support is a moving target that NixOS upgrades could
silently break.

**Mitigation:** The whole point of the declarative NixOS config is that the
driver, kernel, and CUDA container versions are pinned in git. No surprise
upgrade can break the GPU without a reviewable, rollbackable diff.

## Media server scope creep

Jellyfin is the most consumer-facing thing on the roadmap and the easiest to
over-invest in.

**Mitigation:** It's explicitly a Phase 6 "nice to have." It only gets built
after the higher-priority workloads are solid, and it stays behind the
tailnet with a simple client story.

## Architecture Decision Records

- [ADR 000: Tailscale](https://robbiepalmer.me/projects/homelab/adrs/000-tailscale.md) — Accepted, 2026-08-02
- [ADR 001: AdGuard Home for DNS](https://robbiepalmer.me/projects/homelab/adrs/001-adguard-home.md) — Accepted, 2026-08-02
- [ADR 012: Claude Code](https://robbiepalmer.me/projects/homelab/adrs/002-claude-code.md) — Accepted, 2025-10-19 (inherited from personal-site)
- [ADR 043: Codex](https://robbiepalmer.me/projects/homelab/adrs/003-codex.md) — Accepted, 2026-06-21 (inherited from personal-site)
- [ADR 004: Grok Build](https://robbiepalmer.me/projects/homelab/adrs/004-grok-build.md) — Accepted, 2026-08-02
- [ADR 005: opencode](https://robbiepalmer.me/projects/homelab/adrs/005-opencode.md) — Accepted, 2026-08-02
- [ADR 006: t3-code as the agent orchestrator](https://robbiepalmer.me/projects/homelab/adrs/006-t3-code.md) — Accepted, 2026-08-02
- [ADR 007: Ente for photo backup](https://robbiepalmer.me/projects/homelab/adrs/007-ente-photo-backup.md) — Accepted, 2026-08-02
- [ADR 029: DVC](https://robbiepalmer.me/projects/homelab/adrs/008-dvc.md) — Accepted, 2026-02-21 (inherited from recipe-site)
- [ADR 009: Netdata for monitoring](https://robbiepalmer.me/projects/homelab/adrs/009-netdata.md) — Accepted, 2026-08-02
- [ADR 010: NixOS GPU worker](https://robbiepalmer.me/projects/homelab/adrs/010-nixos-gpu-worker.md) — Proposed, 2026-08-02
- [ADR 011: Jellyfin media server](https://robbiepalmer.me/projects/homelab/adrs/011-jellyfin.md) — Proposed, 2026-08-02
- [ADR 012: CUPS for the unsupported printer](https://robbiepalmer.me/projects/homelab/adrs/012-cups.md) — Accepted, 2026-08-02
- [ADR 013: Resurrecting the first-gen Amazon Echo](https://robbiepalmer.me/projects/homelab/adrs/013-amazon-echo.md) — Rejected, 2026-08-02

---

Markdown index of this site: https://robbiepalmer.me/llms.txt
