Architecture
These views map the homelab's machines, workloads, control paths, monitoring, and storage. Versions, ports, mounts, addresses, hostnames, and the live tunnel map remain in configuration or private site data.
Network and access
OPNsense is the network edge. The Debian server runs the live workloads, while the separate Proxmox host provides disposable test machines.
flowchart TB
internet[Internet] --> router[OPNsense router<br/>Firewall · dnsmasq · AdGuard Home · CrowdSec]
router --> network[Home network]
network --> server[Debian 13 server]
network --> proxmox[Proxmox test host]
proxmox --> vms[Disposable VMs]
server --> compose[Docker Compose<br/>Media · Monitoring · Actual]
server --> host[Host services<br/>Storage · systemd jobs]
Remote and trusted clients use different access paths. Exact public tunnel routes are intentionally omitted; see Security boundaries.
| Client | Access path | Destination |
|---|---|---|
| Internet | Caddy | Plex |
| Internet | Encrypted remote ingress through cloudflared | Selected remote-user services |
| LAN or VPN | Caddy | Plex |
| LAN or VPN | Direct private listeners | Operator services |
Applications
The main media path stays linear from request to playback.
flowchart TB
seerr[Seerr] --> managers[Radarr · Radarr Remux<br/>Sonarr · Anime Sonarr]
managers --> search[Prowlarr searches sources]
search --> download[SABnzbd<br/>qBittorrent via VPN]
download --> library[Shared media library]
library --> playback[Plex · Kavita · Audiobookshelf]
Supporting workloads connect to that path without sitting directly in it.
| Service | Role |
|---|---|
| Clonarr | Keeps release profiles aligned across the media managers |
| cross-seed | Finds reusable torrent matches for qBittorrent |
| Kometa | Manages Plex metadata and collections |
| Plex Auto Languages | Keeps Plex language choices consistent |
| AniBridge | Connects anime activity with Plex |
| Audiobookshelf | Streams the audiobook library to LAN and VPN clients |
| Tautulli | Records Plex viewing activity |
| Wizarr | Manages Plex invitations |
| Actual Budget | Runs as a separate personal-service Compose project |
| Authelia | Single sign-on login and TOTP MFA (OpenID Connect provider) |
| lldap | The user directory that Authelia authenticates against |
The media, Actual, monitoring, and identity projects have separate default networks. The external proxy network is their only shared network and is joined only where ingress needs to reach a service.
Authelia is the single sign-on login for Audiobookshelf, Kavita, and Actual Budget; lldap is the shared user directory behind it, and each of those apps keeps a local login as a fallback. Only Authelia is reachable from the internet; lldap and its Redis session cache stay internal. Plex and the request apps keep their own Plex-based sign-in. The identity page explains the trust boundaries in full.
Audiobookshelf is available only on its private LAN/VPN listener. On first run,
create its root account and add /audiobooks as the library. That media mount is
read-only and stays in the replaceable mergerfs/SnapRAID media boundary; its
configuration and metadata stay in appdata and receive the existing local and
offsite restic backups.
Operations and observability
Repository changes are checked in GitHub Actions. Ansible converges the Debian host and deploys the four Compose projects.
flowchart TB
repo[Repository] --> checks[GitHub Actions checks]
repo --> ansible[Ansible]
ansible --> server[Debian host<br/>Configuration · Compose projects · systemd timers]
systemd runs SnapRAID sync and scrub, appdata backup, btrfs scrub, restic checks, the watchdog, and monitoring collectors.
Metrics take one collection path into dashboards and alerts.
flowchart TB
sources[Router · host · disks and GPU<br/>applications · probes · scheduled jobs]
sources --> collectors[Exporters and textfile collectors]
collectors --> prometheus[Prometheus]
prometheus --> outputs[Grafana dashboards<br/>Alertmanager notifications]
The exporters cover Node, SMART, Intel GPU, OPNsense, Radarr, Sonarr, Prowlarr, SABnzbd, qBittorrent, Tautulli, speed tests, and black-box probes. Host collectors report maintenance-job results without waking the parity disk.
Logs take a separate path into Grafana.
flowchart TB
logs[Docker logs through a read-only socket proxy<br/>systemd journal]
logs --> alloy[Alloy]
alloy --> loki[Loki]
loki --> grafana[Grafana]
Storage and backups
Five independent XFS data drives form the mergerfs media pool. SnapRAID parity protects that pool, while incomplete usenet downloads use the NVMe cache.
flowchart TB
drives[5 x XFS data drives] --> pool[mergerfs media pool]
incomplete[NVMe incomplete downloads] --> pool
parity[SnapRAID parity<br/>Normally spun down] -. protects .-> pool
Application data follows a separate backup path.
flowchart TB
appdata[NVMe btrfs appdata] --> snapshot[Read-only btrfs snapshot]
snapshot --> restic[restic]
restic --> copies[Local array backup<br/>Offsite backup]
Media protection and appdata backups solve different failure cases. The full disk layout, staging behavior, and recovery model are documented in Storage and backups.