Services
Everything below runs on Lana via Docker Compose,
defined in docker-infra —
one directory per service. See Networking
for what “Access (self-hosted)” / “Access (SSO)” actually mean.
| Service | Hostname | Role | Auth |
|---|---|---|---|
| Gitea | git.spelvin.dev | Git host — docker-infra itself lives here (legacy OpenID 2.0 URL-based sign-in/sign-up now disabled — see below) |
Access (SSO) |
| LiteLLM | litellm.spelvin.dev | LLM proxy — home Ollama models + Claude | Access (SSO), “Only Me” policy |
| Open WebUI | chat.spelvin.dev | Chat frontend for everything in LiteLLM | Access (SSO) |
| Leantime | roadmap.spelvin.dev | Project management — replaced Plane | Access (SSO) |
| FlowViz | flowviz.spelvin.dev | Attack-flow diagramming | Access (self-hosted), “Only Me” policy |
| Windmill | windmill.spelvin.dev | Workflow automation — replaced n8n | Access (self-hosted), “Only Me” policy |
| Authentik | auth.spelvin.dev | Identity provider — passkey login for Access | None — this is an identity provider, see below |
| ntfy | ntfy.spelvin.dev | Push notifications for scripts/automations | None — deliberately not behind Access (see below) |
| knowledge-mcp | mcp.spelvin.dev | Remote MCP server — serves the knowledge repo and the SOC model to every Claude client (phone, web, desktop, Claude Code) |
Its own OAuth, delegating login to Authentik — deliberately not behind Access (see below) |
| forecaster | (no hostname — on-demand) | On-demand InfluxDB prediction jobs, run on Pam via a task scheduler, not a persistent container | N/A |
Every remaining app is behind Cloudflare Tunnel + Access — the
Caddy/Authelia migration is done, not partial — with one deliberate
exception, ntfy (see below). That wasn’t obvious until checked directly: a
full DNS audit turned up that every one of these hostnames already had its
own CNAME straight to the Tunnel, meaning Caddy’s matching Caddyfile blocks
were already unreachable dead code before Caddy itself was even removed.
The only thing still reaching Caddy was auth.spelvin.dev via a catch-all
*.spelvin.dev wildcard A record — and once Outline (the last app with any
Authelia-era dependency) was retired, nothing needed Authelia’s portal
either. Caddy, Authelia, and that wildcard record are gone as of this
writing.
auth.spelvin.dev exists again, but don’t confuse it with the old
Authelia portal — it’s now Authentik,
added afterward for passkey login, unrelated to and unaware of the
Authelia instance that used to sit at the same hostname.
Access itself no longer gates apps by matching a specific email address —
see Networking for the current model
(reusable “Only Me” / household policies matched via an OIDC groups
claim against Authentik group membership, not per-app email rules).
ntfy is the one app that deliberately sits outside Cloudflare Access entirely. Its whole point is accepting authenticated push requests directly from scripts and automations, not interactive browser logins — an Access login page in front of it would break that. It’s reachable straight through the Tunnel, with ntfy’s own token auth as the only gate.
knowledge-mcp is the second deliberate exception, for a different reason
than ntfy. Claude’s hosted connectors are called from Anthropic’s servers,
which can’t get through an Access login page, and Cloudflare’s own “Managed
OAuth” for MCP servers fails against claude.ai on web and mobile (its 401
omits the WWW-Authenticate header those clients need —
claude-ai-mcp#410,
closed as not planned). So the server performs the MCP OAuth handshake itself
(FastMCP’s OIDCProxy) and delegates the actual login to Authentik, with the
same passkey flow as everything else. Who may connect is enforced by the
Authentik application’s policy binding — a direct user binding, the same
single-person pattern as the Grafana and Synology DSM providers — rather than
by an Access policy. Note this means Bot Fight Mode and any WAF rule on the
zone apply to Anthropic’s servers directly; if a connector ever fails with no
login page appearing at all, suspect that first.
forecaster isn’t a Tunnel/Access app at all — it has no hostname. It’s a set of on-demand InfluxDB prediction jobs that run on Pam, invoked by a task scheduler rather than running as a persistent container.
Retired
Section titled “Retired”- Outline (
outline.spelvin.dev, team wiki) — replaced by this wiki site. Had real content (31 documents, 6 collections) at the time of removal; wiped by choice, not migrated. - Caddy — the legacy edge reverse proxy. Removed along with its two
data volumes (
caddy_data/caddy_config- TLS state). - Authelia — the legacy SSO provider. Removed along with its config
directory (bind-mounted, not a named volume, so this was a plain
directory delete rather than a
docker volume rm). - Plane → Leantime: Plane was retired in favor of Leantime. A one-off
migration script (
scripts/migrate-plane-to-leantime.pyindocker-infra) moved projects and modules across before teardown;scripts/migration_state.jsonholds the ID mapping from that run. Plane’s 13 containers, its 4 data volumes, and the vendored upstream source (/opt/plane-selfhost, outside the repo) are all gone.plane-portfolio-timeline(a custom Gantt view over Plane’s API,timeline.mickeystech.com) went with it, since it had nothing left to talk to. That hostname’s DNS lives in a different zone (mickeystech.com, not spelvin.dev) this wiki’s Cloudflare access doesn’t reach — it’s still pointed at the VPS and will just fail now that nothing answers it there. - n8n — replaced by Windmill; nothing was migrated over (n8n’s data was wiped on removal, by choice).
- Jupyter — personal notebook server; its work volume was confirmed empty before teardown, nothing lost. Was the last thing still behind Caddy/Authelia before Outline’s removal made both fully redundant.
Not covered above
Section titled “Not covered above”- Database/cache sidecars for the services above (Postgres, MySQL, Redis)
aren’t listed individually — see each service’s own
docker-compose.yml.