wiki: document homelab-context distribution system
Adds infrastructure/homelab-context.md as the architecture reference for the cross-client context + MCP + secrets-issuance system. Updates: - 105-apps.md: two new ## Stacks sections (homelab-mcp, secrets-issuance) with their deploy pipelines + a row each in the public-hostname table; changelog entry. - auto-deploy.md: both new pipelines added to the table (one repo, two webhooks, same push); per-pipeline notes covering the clone-per-service pattern and the deploy.sh self-restart caveat; changelog entry. - README.md: link to the new infrastructure page. Operational walkthrough already lives at operations/agent-enrollment.md; this commit is the architecture side of the same story. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# 105 — `apps`
|
||||
|
||||
Docker host for everything that doesn't justify its own LXC. Currently runs Artifacto, Booklore, PlantUML server, Portainer (and historically WriteFreely / blog).
|
||||
Docker host for everything that doesn't justify its own LXC. Currently runs Artifacto, Booklore, PlantUML server, Portainer (and historically WriteFreely / blog), plus the [homelab-context distribution services](../infrastructure/homelab-context.md) (MCP + secrets-issuance) since 2026-05-20.
|
||||
|
||||
## At a glance
|
||||
- **Hostname:** `apps`
|
||||
@@ -19,6 +19,8 @@ Docker host for everything that doesn't justify its own LXC. Currently runs Arti
|
||||
| `artifacto.hubris.network` | Artifacto | `:3100` | Public `/p/*`, `/static/*`, `/healthz` exposed via [VPS traefik](../infrastructure/ingress.md). |
|
||||
| `blog.hubris.network` | WriteFreely | `:8080` | Native OIDC via `[oauth.generic]`. |
|
||||
| `git.hubris.network/_plantuml/*` | PlantUML server | `:8079` | Same-origin route from [gitea (104)](104-gitea.md). |
|
||||
| `mcp.hubris.network` | homelab-mcp | `:9810` | MCP server over SSE. No SSO — agent-facing, gated at source-IP layer. See [homelab-context](../infrastructure/homelab-context.md). |
|
||||
| `secrets.hubris.network` | secrets-issuance | `:9820` | Per-client age-key issuance. Mesh+LAN source-IP gated (`MESH_SUBNETS`). |
|
||||
|
||||
## Stacks
|
||||
|
||||
@@ -49,6 +51,51 @@ Native OIDC via Authentik (Settings → OIDC). Redirect URI `/oauth2-callback` (
|
||||
|
||||
> ⚠️ **Never `docker compose up` Portainer-managed stacks from the host shell.** Portainer's compose state lives at `/var/lib/docker/volumes/portainer_data/_data/compose/<N>/`. Running `docker compose up -d <svc>` from the host triggers recreates of OTHER services in the stack and silently destroys bind-mounted data. **This wiped Booklore's mariadb data on 2026-04-22.** Use the Portainer UI editor for compose changes. See [mesh migration](../infrastructure/mesh.md#critical-never-docker-compose-up-portainer-managed-stacks) for the full warning.
|
||||
|
||||
### homelab-mcp (`/opt/homelab-mcp/`)
|
||||
FastMCP server (Python venv at `/opt/homelab-mcp/.venv`). Reads from
|
||||
`/opt/homelab-context/` (this LXC is itself an enrolled
|
||||
[homelab-context](../infrastructure/homelab-context.md) client). Source
|
||||
is `dtoro/Homelab-Docs/mcp/server.py`; service unit
|
||||
`homelab-mcp.service` binds `0.0.0.0:9810`. DNS-rebinding protection
|
||||
disabled at the FastMCP layer because mesh+LAN gating is the actual
|
||||
trust boundary.
|
||||
|
||||
- Endpoint: `https://mcp.hubris.network/sse` (Caddy → `:9810`).
|
||||
- 14 tools registered: `get_host`, `list_services`, `find_service`,
|
||||
`get_topology`, `search_docs`, `get_page`, `get_changelog`, `whoami`,
|
||||
`list_my_secrets` (context); `get_service_status`, `tail_log`,
|
||||
`list_lxcs`, `get_lxc_state`, `ping_service` (read-only management).
|
||||
- Management tools shell out via SSH using a dedicated `mcp-reader` key
|
||||
(planned; not provisioned yet — management tools fail until then).
|
||||
|
||||
#### Auto-deploy pipeline (homelab-mcp)
|
||||
Receiver at `/opt/homelab-mcp/mcp/deploy/webhook/` (in-tree alongside
|
||||
the server code). Listens on `0.0.0.0:9811`, secret in
|
||||
`/etc/homelab-mcp-deploy/secret`, systemd unit
|
||||
`homelab-mcp-deploy.service`. Gitea webhook id 10 on
|
||||
`dtoro/Homelab-Docs`. Deploy script reinstalls the service unit and
|
||||
restarts on push.
|
||||
|
||||
### secrets-issuance (`/opt/secrets-issuance/`)
|
||||
Tiny HTTP service that issues per-client age keypairs the first time
|
||||
each client calls `/issue`. Idempotent: subsequent calls return the
|
||||
same key. Mesh+LAN source-IP gated via the `MESH_SUBNETS` env in
|
||||
`secrets-issuance.service`. State (per-client keys + denylist) lives at
|
||||
`/var/lib/secrets-issuance/` (NOT in the repo).
|
||||
|
||||
- Endpoint: `https://secrets.hubris.network/issue` (Caddy → `:9820`).
|
||||
- `/revoke` is admin-token-gated by `/etc/secrets-issuance/admin-token`;
|
||||
shreds the local key file and adds the hostname to the denylist.
|
||||
Called by `homelab client remove`.
|
||||
- Trust subnets today: `100.122.0.0/16` (Netbird), `100.64.0.0/10`
|
||||
(Tailscale), `192.168.8.0/24` (LAN). Tighten if the LAN gets
|
||||
untrusted devices.
|
||||
|
||||
#### Auto-deploy pipeline (secrets-issuance)
|
||||
Receiver at `/opt/secrets-issuance/secrets-issuance/deploy/webhook/`,
|
||||
port `9821`, secret in `/etc/secrets-issuance-deploy/secret`, unit
|
||||
`secrets-issuance-deploy.service`. Gitea webhook id 11.
|
||||
|
||||
### WriteFreely (`/opt/writefreely-docker/`)
|
||||
Native OIDC via `[oauth.generic]` in `config/config.ini`. `host = https://auth.hubris.network`, scope `openid profile email`, `map_user_id = sub`. Redirect URI in Authentik: `https://blog.hubris.network/oauth/callback/generic`. Container has `extra_hosts: auth.hubris.network:192.168.8.175`. First-time users with a local WF account must connect SSO via Customize/Settings → Linked Accounts.
|
||||
|
||||
@@ -66,6 +113,16 @@ Native OIDC via `[oauth.generic]` in `config/config.ini`. `host = https://auth.h
|
||||
|
||||
## Changelog
|
||||
|
||||
### 2026-05-20 — homelab-mcp + secrets-issuance live
|
||||
Two new services from the [homelab-context distribution plan](../infrastructure/homelab-context.md):
|
||||
`homelab-mcp.service` on `:9810` (MCP read+management surface) and
|
||||
`secrets-issuance.service` on `:9820` (per-client age-key provisioning).
|
||||
Caddy fronts both with Let's Encrypt; new vhosts on
|
||||
[caddy](121-caddy.md), split-horizon DNS entries on
|
||||
[authentik (124)](124-authentik.md). Gitea webhook ids 10 + 11 wire
|
||||
auto-deploy. LXC is itself an enrolled context client
|
||||
(`/opt/homelab-context/`).
|
||||
|
||||
### 2026-04-28 — wiki entry created
|
||||
Initial documentation.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user