homelab-architecture: add Mermaid topology / auth / MCP / data plane diagrams
This commit is contained in:
@@ -378,3 +378,135 @@ must target *exactly these silent-failure classes*.
|
||||
`/mnt/pve/unas` (catches a regression of the tier-1 rule).
|
||||
4. Container unhealthy/restart-looping > 5 m (the gluetun pattern).
|
||||
5. local-zfs `rpool` or NFS pool > 85 %; 6. TLS cert < 14 d.
|
||||
|
||||
## Topology — at a glance
|
||||
|
||||
### Physical / CT layout
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph Host["Proxmox host · 192.168.1.20 · Intel Core Ultra 7 155H · 64 GiB"]
|
||||
direction TB
|
||||
haos["VM 100 · haos<br/>(.60)<br/>Home Assistant"]
|
||||
shepard["CT 101 · shepard<br/>(.49)<br/>Shepard product stack"]
|
||||
dns["CT 102 · dns<br/>(.2)<br/>AdGuard Home"]
|
||||
backrest["CT 103 · backrest<br/>(.3)<br/>Backrest / restic"]
|
||||
docker104["<b>CT 104 · docker</b><br/>(.40) · 16c/48G/200G<br/>~65 containers · Intel Arc passthrough"]
|
||||
nc["CT 105 · nextcloud<br/>(.41)<br/>Nextcloud AIO (CIFS to UNAS)"]
|
||||
zoraxy["CT 108 · zoraxy<br/>(.4)<br/>reverse proxy + ACME"]
|
||||
obs(["CT 109 · observe<br/>(.6) · <i>planned</i><br/>Prom / Graf / Arcane / Homarr / Tinyauth"])
|
||||
id["CT 110 · id<br/>(.5)<br/>Pocket-ID (moved here 2026-05-20)"]
|
||||
dev["CT 111 · dev<br/>(.42) · 12c/32G/60G<br/>Coder + Gitea + workspaces · Intel Arc"]
|
||||
db(["CT 113 · db<br/>(.?) · <i>planned</i><br/>shared Postgres + pgbouncer"])
|
||||
end
|
||||
UNAS[("UNAS<br/>192.168.1.31<br/>NFSv3 + CIFS")]
|
||||
UDM[["UDM-SE · 192.168.1.1<br/>UniFi gateway · DNS → AdGuard"]]
|
||||
Inet([Internet · ACME challenges · jottacloud · LiteLLM upstreams])
|
||||
|
||||
UDM <--> Host
|
||||
UDM <--> Inet
|
||||
UNAS <--> shepard
|
||||
UNAS <--> backrest
|
||||
UNAS <--> docker104
|
||||
UNAS <--> nc
|
||||
UNAS <--> dev
|
||||
|
||||
classDef planned stroke-dasharray:5 5,fill:#222,stroke:#aaa,color:#aaa
|
||||
class obs,db planned
|
||||
```
|
||||
|
||||
### Auth plane — Pocket-ID is the universal IdP
|
||||
|
||||
Every web service that supports OIDC federates against Pocket-ID. Coder/Gitea/Vaultwarden access through Zoraxy; Zoraxy + Tinyauth fronts the non-OIDC-native ones.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
user(["fkrebs · browser / VS Code / Claude"]) --> zx[Zoraxy<br/>CT 108]
|
||||
zx --> coder[Coder · CT 111]
|
||||
zx --> gitea[Gitea · CT 111]
|
||||
zx --> nc2[Nextcloud · CT 105]
|
||||
zx --> immich[Immich · CT 104]
|
||||
zx --> lobe[LobeChat · CT 104]
|
||||
zx --> n8n[n8n · CT 104]
|
||||
zx --> mcp[MCP gateway · CT 104]
|
||||
zx --> vw[Vaultwarden · CT 104]
|
||||
coder --> pid[(Pocket-ID<br/>CT 110)]
|
||||
gitea --> pid
|
||||
nc2 --> pid
|
||||
immich --> pid
|
||||
lobe --> pid
|
||||
n8n --> pid
|
||||
mcp --> pid
|
||||
vw -.->|via Tinyauth<br/>when CT 109 lands| pid
|
||||
classDef pending stroke-dasharray:4 4,color:#888
|
||||
class vw pending
|
||||
```
|
||||
|
||||
### MCP plane — gateway control, child workers
|
||||
|
||||
The MCP gateway on CT 104 is the OIDC-gated front; ~23 child MCP servers run on the same docker network (`ai-internal`). When CT 109 "observe" is built, the gateway moves to CT 109 and reaches CT 104's docker daemon via a socket-proxy; the children stay put.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
client[["Claude Code / Cursor / LobeChat"]]
|
||||
gw["MCP gateway<br/>(CT 104 → CT 109 when 109 lands)<br/>mcp.nuclide.systems"]
|
||||
client -- Bearer / OIDC --> gw
|
||||
subgraph "CT 104 · ai-internal docker net"
|
||||
direction TB
|
||||
coderm[coder-mcp]
|
||||
immm[mcp-immich]
|
||||
n8nm[mcp-n8n]
|
||||
fetch[mcp-fetch]
|
||||
time[mcp-time]
|
||||
cw[mcp-crawl4ai]
|
||||
seq[mcp-sequential-thinking]
|
||||
ham[home-assistant-mcp]
|
||||
kr[kroki-mcp]
|
||||
others[...18 more]
|
||||
end
|
||||
gw --> coderm
|
||||
gw --> immm
|
||||
gw --> n8nm
|
||||
gw --> fetch
|
||||
gw --> time
|
||||
gw --> cw
|
||||
gw --> seq
|
||||
gw --> ham
|
||||
gw --> kr
|
||||
gw --> others
|
||||
coderm -.spawns/controls.-> CoderWS[(Coder workspaces<br/>CT 111)]
|
||||
ham -.bridges to.-> HAOS[(Home Assistant<br/>VM 100)]
|
||||
```
|
||||
|
||||
### Data plane — what lives where
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph Tier1["Tier-1 / latency-sensitive · local NVMe"]
|
||||
pid_d[Pocket-ID sqlite · CT 110]
|
||||
immich_pg[Immich Postgres · CT 104]
|
||||
shared_pg[shared-postgres · CT 104]
|
||||
coder_pg[coder-db · CT 111]
|
||||
gitea_pg[gitea-db · CT 111]
|
||||
garage["Garage S3 · CT 104<br/>(moved off NFS 2026-05-19)"]
|
||||
n8n_local["n8n data · CT 104<br/>(reverted from NFS 2026-05-19)"]
|
||||
end
|
||||
subgraph Bulk["Bulk · UNAS NFSv3"]
|
||||
media["Immich media, Paperless docs,<br/>arr-stack media, audiobooks"]
|
||||
coder_homes[Coder workspace homes · /mnt/pve/unas/services/coder]
|
||||
gitea_data[Gitea repos · /mnt/pve/unas/services/gitea]
|
||||
vw_data["Vaultwarden data<br/>(tier-1 leak — plan to move local)"]
|
||||
end
|
||||
subgraph BulkCIFS["Bulk · UNAS CIFS (Nextcloud only)"]
|
||||
nc_data[Nextcloud user files]
|
||||
end
|
||||
subgraph Backup["Off-host backup"]
|
||||
jottacloud[(jottacloud<br/>via Backrest)]
|
||||
end
|
||||
Tier1 -. WAL-G .-> garage
|
||||
Bulk -. only media/data-dir .-> jottacloud
|
||||
classDef gap fill:#5a2a2a,stroke:#c44,color:#fcc
|
||||
class vw_data,jottacloud gap
|
||||
```
|
||||
|
||||
The red blocks above are gaps: Vaultwarden is on NFS when it shouldn't be; off-host backup currently covers only one UNAS path, not service data. See `stacks/storage.md` for the verified state and the cleanup TODO list.
|
||||
|
||||
Reference in New Issue
Block a user