- Shell 100%
| docs | ||
| files/sauron | ||
| memory | ||
| project-memory | ||
| scripts | ||
| .gitignore | ||
| CONTEXT.md | ||
| README.md | ||
| ROADMAP.md | ||
Raymer Homelab
Authoritative documentation, architecture notes, and operational runbooks for Raymer — a multi-machine self-hosted home lab.
This repository is the source of truth for how the lab is wired together: machines, services, network topology, recovery procedures, and the decisions behind them. The infrastructure itself lives on the physical machines below; this repo captures the map.
Overview
Raymer is a small home lab built around five machines (three bare-metal, one KVM VM, one VPS) plus a custom RPi5 router. It self-hosts the day-to-day services I would otherwise rent — media (Jellyfin), photos (Immich), files (Nextcloud), a media-acquisition pipeline (the *Arr stack), a private git server (Forgejo on top of bare repos), and a remote-access exit node (WireGuard + Tailscale).
The lab prioritises three things, in order:
- Reliability — uptime over feature velocity; updates are deliberate, not automatic
- Documentation as code — every config is git-tracked and every decision is captured in
docs/orproject-memory/ - Defense in depth — VLAN segmentation, VPN kill switch on torrent traffic, OAuth2 forward-auth on internet-facing services, encrypted backups
Architecture
Machines
| Name | Role | Hardware | Network |
|---|---|---|---|
sweetpea |
DNS/DHCP, reverse proxy, git server, VM host | Dell OptiPlex 7050 Micro | 10.0.50.47 |
qwerty |
Docker host — Jellyfin, Immich, Nextcloud, NAS | HP EliteDesk 800 G4 Mini | 10.0.50.83 |
arrs-vm |
*Arr stack, download clients, VPN kill switch | KVM VM on sweetpea | 192.168.30.40 (VLAN 30) |
sauron |
AI workloads, local LLM inference | HP Z640 Workstation | 10.0.50.213 (Wake-on-LAN) |
oreos |
WireGuard exit node, Borg backup target | Contabo VPS | public |
| RPi5 router | LAN routing, firewall, port forwards | Raspberry Pi 5 + UE300 USB-Ethernet | 10.0.50.1 (OpenWrt) |
Network topology
Internet (Spectrum DOCSIS)
│
▼
[ ET2251 modem ] ── [ RPi5 / OpenWrt router ] ── [ TL-SG108E managed switch ]
│
┌────────────────────┬───────────────┼────────────┬──────────────┐
▼ ▼ ▼ ▼ ▼
sweetpea qwerty sauron Deco AP MoCA bridge
(10.0.50.47) (10.0.50.83) (10.0.50.213) (WiFi) (bedroom coax)
│
├── VLAN 30 (br-vlan30) ──► arrs-vm (192.168.30.40)
│ └── Gluetun VPN kill switch
│ └── qBittorrent + NZBGet
│
└── DNS (.home zone) / DHCP (dnsmasq) / nginx + OAuth2
LAN-side DNS resolves *.home to local services via split-DNS on sweetpea. The *Arr stack is air-gapped on VLAN 30; all download traffic exits through a Gluetun VPN container with kill-switch enabled.
Services
Media
- Jellyfin — media server on
qwerty, reads directly from a mergerfs + SnapRAID NAS pool - Seerr — request UI on top of Jellyfin/Sonarr/Radarr (formerly Jellyseerr, migrated to the maintained fork)
- Sonarr / Radarr / Lidarr / Readarr — TV, movie, music, and book managers on
arrs-vm - Prowlarr — unified indexer manager feeding the *Arrs
- Bazarr — subtitle automation
- qBittorrent + NZBGet — download clients, both routed through Gluetun
- Calibre-Web / LazyLibrarian — book library UIs
- Navidrome — music streaming (Subsonic-compatible), on
qwerty - Audiobookshelf — audiobooks and podcasts, on
qwerty
Files and photos
- Nextcloud (FPM + Postgres + Redis) — files, calendars, contacts, notes, deck
- Immich — photo backup and library, with automatic mobile sync
- Samba — local SMB shares for ad-hoc transfers
Networking and access
- dnsmasq — DNS + DHCP for the LAN, with the
.homezone for local services - nginx + OAuth2-Proxy — reverse proxy on
sweetpeafronting all public services, GitHub OAuth as the auth provider - WireGuard — two tunnels: one for routing all
arrs-vmegress through the VPS, one for selective remote access - Tailscale — peer-to-peer remote access overlay
- Forgejo — self-hosted git web UI mirrored from bare repos via post-receive hooks
- Borg — encrypted backups to the VPS
Compute and AI
- Ollama on
sauron— local LLM inference (Llama 3, Mistral, etc.) - FastAPI summariser — Python service wrapping Ollama for content summarisation
- Watchtower — auto-updates *Arr stack containers nightly (scoped to
arrs-vmonly)
Monitoring and dashboards
- LANtern — self-hosted network-observability stack on
sweetpea(lantern.home): device inventory, DNS / DHCP / NetFlow ingest into SQLite, an activity oracle for idle-gated maintenance, and an SSH / fail2ban security view. React UI + FastAPI; local-LLM query layer planned. Also public on GitHub. - Uptime Kuma — service + host uptime monitoring at
status.home(LAN + Tailscale), Pushbullet alerts, plus shareable status pages. - homepage — two gethomepage.dev launcher instances:
home.home(internal, all services; LAN + Tailscale) andjanovitch.com(public, the public*.janovitch.comservices). One config per instance. - fail2ban — SSH brute-force protection on
sweetpea, using the systemd-journal backend + aggressive filter (catches low-and-slow scanners). Seedocs/sweetpea.md.
Notable patterns
A few design choices that distinguish this lab from a typical home setup:
- VLAN-segregated VPN kill switch. The *Arr stack runs in its own VLAN with all egress forced through Gluetun. Any VPN drop fails the container's network — no torrent traffic ever leaks to the LAN's WAN.
- mergerfs + SnapRAID NAS. A union filesystem of independent drives with snapshot-style parity, giving JBOD flexibility with single-disk-loss tolerance. No striping, no RAID rebuild penalty.
- Custom OpenWrt router on RPi5. Replaced a vendor mesh router with a Raspberry Pi 5 + USB-Ethernet adapter, running OpenWrt for full control of routing, firewall, static routes between VLANs, and DNS overrides.
- Self-hosted git, bare repos as source of truth. Bare repos on
sweetpea(accessed viagit@sweetpea-git:) push to Forgejo for web UI via a shared post-receive hook. No vendor lock-in to the web frontend. - Split-DNS with local TLS.
*.homedomains resolve to LAN IPs internally and to the public address externally, with separate certificate handling for each path. - Documentation discipline. Every machine has a
docs/<host>.md; every non-trivial decision has aproject-memory/writeup; every session has amemory/YYYY-MM-DD.mdrunbook. The lab is reproducible from this repo plus the bare repos onsweetpea. - OAuth2 forward-auth on the reverse proxy. Internet-exposed services sit behind a single OAuth2-Proxy instance using GitHub as the provider, so authentication is centralised rather than per-service.
Tech stack
OpenWrt · Docker · Docker Compose · KVM/libvirt · Ubuntu Server · NixOS (laptop client) · dnsmasq · nginx · OAuth2-Proxy · WireGuard · Tailscale · mergerfs · SnapRAID · Postgres · Redis · Forgejo · Borg · systemd · sops-nix (secrets)
Repository layout
CONTEXT.md— agent entry point and routing map for the whole repoROADMAP.md— deferred bugs and future workdocs/— authoritative per-machine documentationdocs/network.md— physical layer (ISP, switches, WiFi, MoCA)docs/sweetpea.md— reverse proxy, DNS, git server, VM hostdocs/qwerty.md— NAS storage layout, Docker servicesdocs/arrs-vm.md— *Arr stack, NFS mounts, download pipelinedocs/sauron.md— AI workloads, WOL, power managementdocs/oreos.md— VPS, WireGuard tunnels, Borg backups
memory/— session notes (YYYY-MM-DD.md), append-onlyproject-memory/— durable project-level notes, e.g.:
The memory/ files are session-level runbooks: each one captures what happened, what was tried, and what was learned during a particular work session. The project-memory/ files are the distilled, durable record — architecture decisions, multi-day initiatives, incident write-ups.
Related repositories
The Raymer documentation references and depends on several other tracked repos:
| Repo | Lives on | Purpose |
|---|---|---|
sweetpea-nginx-config |
sweetpea | nginx vhosts, snippets, upstreams |
sweetpea-reverse-proxy |
sweetpea | nginx + OAuth2-Proxy Docker Compose |
dnsmasq-config |
sweetpea | DNS / DHCP configuration |
sweetpea-scripts |
sweetpea | fail2ban jail, logrotate configs, deco-reboot script |
lantern |
sweetpea | LANtern network-observability stack (also public on GitHub) |
uptime-kuma |
sweetpea | uptime-kuma monitor (compose) |
homepage |
sweetpea | internal home.home launcher (compose + config) |
homepage-public |
sweetpea | public janovitch.com launcher (compose + config) |
arr-stack |
arrs-vm | *Arr stack Docker Compose |
nixos-config |
laptop | NixOS system config for the client machine |
Each tracked repo is the source of truth for its machine's configuration; this docs repo describes how they fit together.
Status
The lab is in continuous use as my primary home server. Major recent work:
- 2026-05 — replaced the Orbi mesh with a custom RPi5 + OpenWrt router (Phase 1), then a TP-Link Deco AP mesh (Phase 1.5). Phase 2 (managed APs with VLAN-per-SSID) is on the roadmap.
- 2026-05 — re-numbered the LAN from
192.168.x.xto10.0.50.0/24to make room for proper VLAN segmentation. - 2026-07 —
LANternwent operational (device inventory, DNS/DHCP/NetFlow ingest, an idle-detection activity oracle, and an SSH/fail2ban security view atlantern.home). Added uptime-kuma monitoring (status.home) and homepage launchers (internalhome.home+ publicjanovitch.com), and hardened fail2ban (systemd-journal backend + aggressive filter) to catch low-and-slow SSH brute-forcers. - 2026-09 — repaired Jellyfin fallout from the media-normalize batch: 18 movie collections had lost members (Twilight fully empty) because BoxSet membership is pinned by file path and the pipeline had changed extensions
.mp4→.mkv; re-added the 36 members and rewrote eachcollection.xmlto current paths. Also fixed 168 movies displaying raw release names (junkmovie.nfo<title>) via a TMDB metadata refresh. Root cause (normalize pipeline not collection-/NFO-aware) is on the roadmap — it will recur until the pipeline is fixed. - 2026-09 — found and shut down a 10+ day live RCE exploitation attempt against Nextcloud (new fail2ban jail + a Cloudflare real-IP fix), and fixed a 2-month blind spot in LANtern's own security monitoring (a logrotate/Docker bind-mount gotcha — see
Raymer/memory/2026-09-20.md). AddedLANtern's Services page (Jellyfin watch history, its first cross-host data source: a small pusher script on qwerty rather than a colocated ingest container — seeRaymer/memory/2026-09-26.md). - Ongoing — extending
LANterntoward its local-LLM query layer and dynamic SnapRAID sync (currently validating thresholds in shadow mode; the Deco reboot side of idle-gated maintenance has been live since 2026-08-29), plus Phase 2 managed APs with VLAN-per-SSID.
See ROADMAP.md for the active and deferred work list.