Compare commits

60 Commits

Author SHA1 Message Date
900e46c667 add VPS Traefik dynamic config — hubris.network fallback routes
All services use certResolver: letsencrypt (TLS-ALPN-01).
Patterns:
  HTTP backends: blog, artifacto, trmnl, matrix, house, sso, media, paperless
  HTTPS+SNI: mcp, oikos (via caddy-hubris serversTransport)
  HTTPS+insecure: proxmox (via proxmox serversTransport)
Static config: --serverstransport.insecureskipverify=true

Config lives at /opt/traefik-dynamic.yaml on VPS.
Auto-deploy: webhook receiver on :8082 -> git pull + docker kill -s HUP netbird-traefik
2026-08-12 18:26:43 +02:00
root
6e6bfe3aa0 Revert "test: end-to-end deploy pipeline (both hosts)"
This reverts commit 28543e1662.
2026-08-12 14:52:48 +02:00
root
28543e1662 test: end-to-end deploy pipeline (both hosts) 2026-08-12 14:52:29 +02:00
root
3d52e9d1c1 Revert "test: debug sig v3"
This reverts commit fa1dff62c6.
2026-08-12 14:51:25 +02:00
root
fa1dff62c6 test: debug sig v3 2026-08-12 14:50:27 +02:00
root
2faea41d3e Revert "test: debug webhook signature v2"
This reverts commit 3cebb8fd11.
2026-08-12 14:49:40 +02:00
root
3cebb8fd11 test: debug webhook signature v2 2026-08-12 14:48:29 +02:00
root
4635001feb Revert "test: verify auto-deploy pipeline"
This reverts commit 1ea60a9aca.
2026-08-12 14:47:53 +02:00
root
1ea60a9aca test: verify auto-deploy pipeline 2026-08-12 14:45:11 +02:00
root
e7bf4f9d93 fix: clean shared/authentik (fix tab escaping) + add :8080 webhook endpoint 2026-08-12 14:42:40 +02:00
root
2c418d395d refactor: split Caddyfile into per-host configs with shared snippets
Structure:
  shared/authentik  - forward-auth proxy + authentik snippet (both hosts)
  hosts/hubris/      - git, mcp, oikos, paperless, cloud, photos, etc.
  hosts/strong/      - media, books, roms, jellyseerr, qbit, sab, matrix, etc.

Each host imports /etc/caddy/shared/* at the top of its Caddyfile.
Systemd overrides point to hosts/<hostname>/Caddyfile.

Deploy workflow: git push → webhook → caddy reload
2026-08-12 14:37:30 +02:00
root
86e727255b chore: add .gitignore for backup and env files 2026-08-12 14:33:33 +02:00
root
2b8bddc488 split: move 10 strong-hosted services to dedicated Caddy on CT 140 (.250)
Moved media, books, roms, jellyseerr, qbit, sab, matrix, element,
house, seanime to strong Caddy (192.168.8.250). These services
backends live on strong LXCs — co-locating Caddy removes cross-host
proxy dependency.

Remaining on hubris (.175): git, mcp, oikos, paperless, cloud, photos,
proxmox, secrets, home, trmnl, auth.
2026-08-12 14:33:03 +02:00
4238adb81c fix: zimaos.hubris.network reverse_proxy target IP .102→.195 (VM serving at original .195) 2026-08-06 22:05:17 +02:00
f266f0605f add matrix.hubris.network reverse proxy to Synapse (192.168.8.242:8008) 2026-08-05 17:11:34 +02:00
48549d0072 fix(zimaos): update reverse_proxy to 192.168.8.102:80 (correct ZimaOS VM IP) 2026-08-04 21:28:00 +02:00
root
d17ee47ce5 add pascal.hubris.network → 192.168.8.100:3001 2026-08-04 14:39:23 +02:00
25b81b2dce Add /oidc-callback to enroll bypass for desktop OIDC flow 2026-07-13 23:21:41 +02:00
root
a3d9368a54 Merge branch 'master' of http://192.168.8.121:3000/dtoro/caddy-conf 2026-07-12 23:15:18 +02:00
root
89ff86e36e add tube.hubris.network -> 192.168.178.44:8082 2026-07-12 23:11:13 +02:00
e026ba867a oikos: split SPA off to its own :8091 container
api no longer embeds the SPA (it's compose/web/Dockerfile's `web`
service in the oikos repo now) — route the catch-all handle to :8091
instead of :8090, and restore the /api/v1/*, /mcp, /agent/* matcher so
those keep hitting api directly rather than falling through to the
static file server.
2026-07-12 23:03:46 +02:00
8e48911e1f fix: close mcp.hubris.network block properly, remove dangling comment 2026-07-08 11:59:24 +02:00
fc50aa3bda oikos: remove old mcp+secrets blocks pointing to decommissioned apps/105 2026-07-08 11:58:12 +02:00
5401d77bab oikos: remove duplicate block, switch to mac-mini :8090, bypass Authentik for /api/v1/clients/enroll 2026-07-08 11:56:53 +02:00
ed20908d34 dns: add oikos/mcp/hermes → mac-mini Docker (Go Phase 6 cutover) 2026-07-07 19:15:39 +02:00
c195142827 Add oikos.hubris.network -> Oikos Console on apps (105:8091)
Authentik-gated (matches paperless.hubris.network's pattern) since the
console handles real mutation actions (signal ack/resolve, approval
approve/deny) and doesn't implement its own network-level gating the
way mcp.hubris.network/secrets.hubris.network do.

See dtoro/Homelab-Docs oikos/console/ for the app itself.
2026-07-06 13:26:24 +02:00
205cbf00f3 roms.hubris.network → .249 (fixed IP conflict with seanime) 2026-07-05 17:19:49 +02:00
c937c03da3 Add roms.hubris.network → 192.168.8.248:80 (RomM LXC 134 on strong) 2026-07-05 17:12:21 +02:00
root
9dcac60a08 add seanime.hubris.network proxy to seanime LXC 133 on strong :43211 2026-07-05 16:56:46 +02:00
root
dfe4e7bf80 migrate grimmory (130) to strong - update books backend 2026-07-05 15:03:34 +02:00
root
468c2e7d93 migrate arriman (122) and jellyfin (101) to strong - update backends 2026-07-05 14:37:32 +02:00
root
9b99dbb641 update house+teddy backends after LXC 129 migration to strong + teddycloud static IP 2026-07-05 13:18:03 +02:00
root
0b703fa192 update house.hubris.network backend to strong (192.168.8.244) after LXC 129 migration 2026-07-05 13:04:16 +02:00
root
751feefe4c update element.hubris.network backend to strong (192.168.8.242) after migrating LXC 118 2026-07-05 12:06:03 +02:00
root
8c92428b42 fix: remove forward-auth gate for jellyfin, use SSO plugin OIDC flow instead 2026-07-04 21:24:51 +02:00
root
ae854e563d fix: add /sso/* and /SSO-Auth/* to jellyfin api bypass for SSO plugin 2026-07-04 20:24:54 +02:00
root
acc5af8477 feat: add authentik forward-auth gate for media.hubris.network (API bypass for apps) 2026-07-04 19:45:14 +02:00
root
e01a39175f teddy.hubris.network: fix backend to https://192.168.8.243:8443 2026-06-29 22:11:21 +02:00
root
3824faf11c add teddy.hubris.network for TeddyCloud LXC 131 2026-06-29 21:52:04 +02:00
root
06d9452741 books.hubris.network: migrate backend to grimmory LXC 130 (192.168.8.213) 2026-06-29 01:20:11 +02:00
root
e0973bfeeb add house.hubris.network for Yuvomi 2026-06-26 17:24:33 +02:00
root
85e9a92059 remove matrix.hubris.network — moved to VPS traefik 2026-06-25 10:38:49 +02:00
dtoro
d2d9ef8da0 add trmnl.hubris.network -> 192.168.8.211:9851 (TRMNL plugins LXC 128) 2026-06-24 17:14:08 +02:00
root
6786f07c76 Add element.hubris.network (Element Web client) 2026-06-23 23:30:09 +02:00
root
0f472e9088 remove papers.hubris.network (zimaos paperless removed) 2026-06-21 23:29:17 +02:00
root
f9783571a1 revert paperless.hubris.network to LXC 103 2026-06-21 23:18:08 +02:00
root
b3e7385754 add papers.hubris.network for paperless on zimaos 2026-06-21 21:58:57 +02:00
root
8d14ef80fa point paperless to zimaos (192.168.8.195:8000) 2026-06-21 21:14:40 +02:00
root
d49a844941 feat: gate sab.hubris.network with Authentik forward-auth 2026-06-13 11:15:04 +02:00
root
32575ce73f fix: sab.hubris.network reverse proxy port 8081 -> 8082
SABnzbd is configured with SABNZBD__PORT=8082 in docker compose.
Previous value 8081 was a dead port; 8080 would route to qBittorrent.
2026-06-06 14:13:42 +02:00
1b977aabfa photos: clean up routing for Mulimage 2.0, add prism subdomain
Update the photos.hubris.network block to match the current stack
(PhotoPrism API + Go sidecar + SvelteKit). Add prism.hubris.network
as a dedicated PhotoPrism vhost for the Prismatic mobile client.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-06 12:38:41 +02:00
root
408a11c856 fix: add internal HTTP proxy for forward-auth (avoids TLS routing issues) 2026-06-04 23:43:48 +02:00
root
fec102895f fmt: clean up sso.hubris.network block formatting 2026-06-04 22:51:58 +02:00
root
2962a6e485 cleanup: point authentik forward-auth and sso to VPS 2026-06-04 22:47:28 +02:00
root
f520afad60 fix: proxy auth.hubris.network to VPS (82.165.190.79), strip port from Host header 2026-06-04 22:37:45 +02:00
c906a5acc7 authentik: add sso.hubris.network site for LAN forward-auth outpost callback
Domain-level proxy providers (Paperless, qBit) need an external_host that
routes to the LAN outpost (192.168.8.6), not auth.hubris.network (now the VPS
core). New site sso.hubris.network -> reverse_proxy 192.168.8.6:9000.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 00:41:55 +02:00
6ea8e727d4 authentik: point forward-auth snippet at LAN outpost (192.168.8.6)
Forward-auth now validates against the VPS Authentik core via a dedicated
LAN outpost (auth-outpost LXC 106), not LXC 124's frozen embedded outpost.
Resolves the post-migration split-brain. 192.168.8.180:9000 -> 192.168.8.6:9000.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 00:31:08 +02:00
db7f8fbf4e photos: revert /library/login proxy — OIDC starts at /api/v1/oidc/login
Earlier commits (e535f93 + a52cf68) proxied /library/login through to
PhotoPrism to fix what I thought was the OIDC initiation path. Wrong:
the SvelteKit SPA initiates OIDC by navigating to /api/v1/oidc/login
(already routed via @pp). The /library/login URL is what PhotoPrism's
UI uses POST-OIDC for the localStorage handoff back to the SPA — it
MUST bounce to / via the caddy redir, otherwise the SPA never picks
up the session and the user lands in PhotoPrism's own UI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 01:08:10 +02:00
a52cf68d0f photos: wrap site block in route{} to force literal directive order
Without an explicit route{} block, caddy auto-hoists `redir` ahead of
`reverse_proxy`. That meant /library/* still redirected to / even
though I'd placed an @pp_login reverse_proxy above the redirs in the
file. Wrap the whole site in route{} so directives run in source order
and the more-specific /library/login matcher wins before the broader
/library/* redir.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 01:02:11 +02:00
e535f93dcc photos: stop caddy from eating /library/login (OIDC initiation)
The /library/* catch-all redir bounced /library/login (PhotoPrism's
OIDC login surface) back to / before the user could click "Sign in
with Authentik". Add a specific @pp_login matcher above the redir
so /library/login + /library/login/* reach PhotoPrism, while the
post-login /library/browse target still bounces back to the SvelteKit
SPA.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 01:01:21 +02:00
7 changed files with 781 additions and 61 deletions

9
.gitignore vendored
View File

@@ -1,5 +1,4 @@
# Environment variables
.env
.env.local
.env.*.local
!.env.example
# Backup files
Caddyfile.bak*
caddy.env
*.env

158
Caddyfile
View File

@@ -1,9 +1,20 @@
# Internal forward-auth upstream proxy (no TLS between Caddy handlers)
:8099 {
@outpost path /outpost.goauthentik.io/*
reverse_proxy @outpost https://auth.hubris.network:443 {
transport http {
tls_server_name auth.hubris.network
}
header_up Host auth.hubris.network
}
}
# Authentik forward-auth snippet (domain-level mode).
# Usage: add "import authentik" inside any site block to gate it.
(authentik) {
route {
reverse_proxy /outpost.goauthentik.io/* http://192.168.8.180:9000
forward_auth http://192.168.8.180:9000 {
reverse_proxy /outpost.goauthentik.io/* https://auth.hubris.network:443
forward_auth http://127.0.0.1:8099 {
uri /outpost.goauthentik.io/auth/caddy
copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Email X-Authentik-Name X-Authentik-Uid X-Authentik-Jwt X-Authentik-Meta-Jwks X-Authentik-Meta-Outpost X-Authentik-Meta-Provider X-Authentik-Meta-App X-Authentik-Meta-Version
trusted_proxies private_ranges
@@ -24,12 +35,6 @@
# this machine's public IP, then replace ":80" below with your
# domain name.
media.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy 192.168.8.206:8096
}
git.hubris.network {
tls {
@@ -58,11 +63,12 @@ paperless.hubris.network {
}
}
books.hubris.network {
pascal.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy 192.168.8.205:6060
reverse_proxy 192.168.8.100:3001
}
home.hubris.network {
@@ -79,12 +85,6 @@ cloud.hubris.network {
reverse_proxy 192.168.8.224:80
}
matrix.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy 192.168.8.239:8008
}
proxmox.hubris.network {
tls {
@@ -108,33 +108,8 @@ docker.hubris.network {
}
}
jellyseerr.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy 192.168.8.132:5056
}
qbit.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
@api path /api/*
handle @api {
reverse_proxy 192.168.8.132:8080
}
handle {
import authentik
reverse_proxy 192.168.8.132:8080
}
}
sab.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy 192.168.8.132:8081
}
blog.hubris.network {
tls {
@@ -144,30 +119,44 @@ blog.hubris.network {
}
photos.hubris.network {
# mule-image — PhotoPrism + Go sidecar + SvelteKit (post-Mulimage 2.0)
# Mulimage 2.0 — PhotoPrism + Go sidecar + SvelteKit (LXC 120)
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
encode zstd gzip
# PhotoPrism API + OIDC callback first (matched before static catch-all)
# PhotoPrism API + static assets + share links
@pp path /api/v1/* /api/v1 /static/* /share/*
reverse_proxy @pp 192.168.8.136:2342
# PhotoPrism redirects to /library/browse after OIDC. Bounce back to
# the SvelteKit SPA; mule-image is the only user-facing frontend.
# OIDC hand-off: PhotoPrism redirects to /library/login after SSO;
# bounce back to / so the SvelteKit SPA picks up the session.
redir /library / 302
redir /library/* / 302
# mule-sidecar (Go) — keeps the /api/sidecar/ prefix
# Go sidecar — marks, folder mutations, duplicates, heap convert
@sc path /api/sidecar/*
reverse_proxy @sc 192.168.8.136:8000
# Catch-all → nginx-on-120 serving the SvelteKit static bundle (no Vite in prod)
# SvelteKit frontend (catch-all)
reverse_proxy 192.168.8.136:3000
}
prism.hubris.network {
# PhotoPrism — direct access for Prismatic mobile client (LXC 120)
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
encode zstd gzip
reverse_proxy 192.168.8.136:2342
}
auth.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy 192.168.8.180:9000
reverse_proxy https://auth.hubris.network:443 {
transport http {
tls_server_name auth.hubris.network
}
header_up Host auth.hubris.network
}
}
artifacto.hubris.network {
@@ -200,23 +189,82 @@ zimaos.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy 192.168.8.195
reverse_proxy 192.168.8.195:80
}
# Homelab MCP server (read-only context + management tools).
# Mesh+LAN-gated by the service itself + nftables; no SSO so agent clients work.
mcp.hubris.network {
sso.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy 192.168.8.205:9810
reverse_proxy https://auth.hubris.network:443 {
transport http {
tls_server_name auth.hubris.network
}
header_up Host auth.hubris.network
}
}
# Per-client age-key issuance (mesh-only via source-IP gating in the service).
# No SSO — agents call this during bootstrap; identity is mesh peer + hostname.
secrets.hubris.network {
# Matrix Synapse federation + client API.
# No authentik gate — Synapse handles its own auth.
trmnl.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy 192.168.8.205:9820
reverse_proxy 192.168.8.211:9851
}
teddy.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy https://192.168.8.150:8443 {
transport http {
tls_insecure_skip_verify
}
}
}
# ─── Oikos (Go rewrite, Docker on mac-mini) ───
# Phase 6 cutover — replaces apps/105 Python MCP + console.
# /api/v1/clients/enroll bypasses Authentik (IP-gated in the API handler).
# The SPA is its own container (:8091, compose/web/Dockerfile in the oikos
# repo) — not served by api itself, which no longer embeds it.
oikos.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
@enroll path /api/v1/clients/enroll /oidc-callback
handle @enroll {
reverse_proxy 192.168.178.182:8090
}
@api path /api/v1/* /mcp /agent/*
handle @api {
reverse_proxy 192.168.178.182:8090
}
handle {
import authentik
reverse_proxy 192.168.178.182:8091
}
}
mcp.hubris.network {
reverse_proxy 192.168.178.182:8090
}
hermes.hubris.network {
reverse_proxy 192.168.178.182:8092
}
tube.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy 192.168.178.44:8082
}

1
caddy.env.example Normal file
View File

@@ -0,0 +1 @@
IONOS_AUTH_API_TOKEN=your_token_here

234
hosts/hubris/Caddyfile Normal file
View File

@@ -0,0 +1,234 @@
import /etc/caddy/shared/*
git.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
handle_path /_plantuml/* {
rewrite * /plantuml{uri}
reverse_proxy 192.168.8.205:8079
}
handle {
reverse_proxy 192.168.8.121:3000
}
}
paperless.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
@api path /api/*
handle @api {
reverse_proxy 192.168.8.130:8000
}
handle {
import authentik
reverse_proxy 192.168.8.130:8000
}
}
pascal.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy 192.168.8.100:3001
}
home.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy 192.168.8.101:8123
}
cloud.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy 192.168.8.224:80
}
proxmox.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy https://192.168.8.77:8006 {
transport http {
tls_insecure_skip_verify
}
}
}
docker.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy https://192.168.8.205:9443 {
transport http {
tls_insecure_skip_verify
}
}
}
blog.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy 192.168.8.205:8080
}
photos.hubris.network {
# Mulimage 2.0 — PhotoPrism + Go sidecar + SvelteKit (LXC 120)
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
encode zstd gzip
# PhotoPrism API + static assets + share links
@pp path /api/v1/* /api/v1 /static/* /share/*
reverse_proxy @pp 192.168.8.136:2342
# OIDC hand-off: PhotoPrism redirects to /library/login after SSO;
# bounce back to / so the SvelteKit SPA picks up the session.
redir /library / 302
redir /library/* / 302
# Go sidecar — marks, folder mutations, duplicates, heap convert
@sc path /api/sidecar/*
reverse_proxy @sc 192.168.8.136:8000
# SvelteKit frontend (catch-all)
reverse_proxy 192.168.8.136:3000
}
prism.hubris.network {
# PhotoPrism — direct access for Prismatic mobile client (LXC 120)
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
encode zstd gzip
reverse_proxy 192.168.8.136:2342
}
auth.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy https://auth.hubris.network:443 {
transport http {
tls_server_name auth.hubris.network
}
header_up Host auth.hubris.network
}
}
artifacto.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
# Public paths: share URLs, static assets, health — no SSO
@public path /p/* /static/* /healthz
handle @public {
reverse_proxy 192.168.8.205:3100
}
# Admin + login surface: Authentik forward-auth + shared-secret header
# so the app can auto-login an Authentik-authenticated user.
handle {
import authentik
reverse_proxy 192.168.8.205:3100 {
header_up X-Artifacto-Gateway {env.ARTIFACTO_GATEWAY_SECRET}
}
}
}
plato.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy 192.168.8.190:8080
}
zimaos.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy 192.168.8.195:80
}
# Homelab MCP server (read-only context + management tools).
# Mesh+LAN-gated by the service itself + nftables; no SSO so agent clients work.
sso.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy https://auth.hubris.network:443 {
transport http {
tls_server_name auth.hubris.network
}
header_up Host auth.hubris.network
}
}
# Matrix Synapse federation + client API.
# No authentik gate — Synapse handles its own auth.
trmnl.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy 192.168.8.211:9851
}
teddy.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy https://192.168.8.150:8443 {
transport http {
tls_insecure_skip_verify
}
}
}
# ─── Oikos (Go rewrite, Docker on mac-mini) ───
# Phase 6 cutover — replaces apps/105 Python MCP + console.
# /api/v1/clients/enroll bypasses Authentik (IP-gated in the API handler).
# The SPA is its own container (:8091, compose/web/Dockerfile in the oikos
# repo) — not served by api itself, which no longer embeds it.
oikos.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
@enroll path /api/v1/clients/enroll /oidc-callback
handle @enroll {
reverse_proxy 192.168.178.182:8090
}
@api path /api/v1/* /mcp /agent/*
handle @api {
reverse_proxy 192.168.178.182:8090
}
handle {
import authentik
reverse_proxy 192.168.178.182:8091
}
}
mcp.hubris.network {
reverse_proxy 192.168.178.182:8090
}
hermes.hubris.network {
reverse_proxy 192.168.178.182:8092
}
tube.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy 192.168.178.44:8082
}

83
hosts/strong/Caddyfile Normal file
View File

@@ -0,0 +1,83 @@
import /etc/caddy/shared/*
media.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
# SSO plugin handles auth via OIDC redirect to Authentik.
# No forward-auth gate — Jellyfin login page shows SSO button directly.
reverse_proxy 192.168.8.246:8096
}
books.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy 192.168.8.247:6060
}
roms.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy 192.168.8.249:80
}
jellyseerr.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy 192.168.8.245:5056
}
qbit.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
@api path /api/*
handle @api {
reverse_proxy 192.168.8.245:8080
}
handle {
import authentik
reverse_proxy 192.168.8.245:8080
}
}
sab.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
handle {
import authentik
reverse_proxy 192.168.8.245:8082
}
}
matrix.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy 192.168.8.242:8008
}
element.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy 192.168.8.242:8080
}
house.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy 192.168.8.244:3000
}
seanime.hubris.network {
tls {
dns ionos {env.IONOS_AUTH_API_TOKEN}
}
reverse_proxy 192.168.8.248:43211
}

View File

@@ -0,0 +1,324 @@
tcp:
serversTransports:
pp-v2:
proxyProtocol:
version: 2
tls:
certificates:
- certFile: /letsencrypt/fullchain.crt
keyFile: /letsencrypt/privkey.key
- certFile: /letsencrypt/blog.fullchain.crt
keyFile: /letsencrypt/blog.privkey.key
- certFile: /letsencrypt/trmnl.fullchain.crt
keyFile: /letsencrypt/trmnl.privkey.key
- certFile: /letsencrypt/sso.fullchain.crt
keyFile: /letsencrypt/sso.privkey.key
- certFile: /letsencrypt/media.fullchain.crt
keyFile: /letsencrypt/media.privkey.key
- certFile: /letsencrypt/paperless.fullchain.crt
keyFile: /letsencrypt/paperless.privkey.key
http:
serversTransports:
caddy-hubris:
serverName: mcp.hubris.network
proxmox:
serverName: proxmox.hubris.network
insecureSkipVerify: true
routers:
artifacto-public:
rule: 'Host(`artifacto.hubris.network`) && (PathPrefix(`/p/`) || PathPrefix(`/static/`) || Path(`/healthz`))'
entryPoints:
- websecure
priority: 10
tls:
certResolver: letsencrypt
middlewares:
- artifacto-strip-sso
- artifacto-ratelimit
service: artifacto-public
blog-public:
rule: 'Host(`blog.hubris.network`)'
entryPoints:
- websecure
priority: 10
tls:
certResolver: letsencrypt
middlewares:
- blog-ratelimit
service: blog-public
trmnl-public:
rule: 'Host(`trmnl.hubris.network`)'
entryPoints:
- websecure
priority: 10
tls:
certResolver: letsencrypt
middlewares:
- trmnl-ratelimit
service: trmnl-public
matrix-public:
rule: 'Host(`matrix.hubris.network`) && !PathPrefix(`/.well-known/matrix/`)'
entryPoints:
- websecure
priority: 10
tls:
certResolver: letsencrypt
middlewares:
- matrix-ratelimit
service: matrix-public
matrix-wellknown:
rule: 'Host(`matrix.hubris.network`) && (PathPrefix(`/.well-known/matrix/`) || PathPrefix(`/.well-known/acme-challenge/`))'
entryPoints:
- websecure
priority: 20
tls:
certResolver: letsencrypt
service: matrix-wellknown-svc
house-public:
rule: 'Host(`house.hubris.network`)'
entryPoints:
- websecure
priority: 10
tls:
certResolver: letsencrypt
middlewares:
- house-ratelimit
service: house-public
sso-public:
rule: 'Host(`sso.hubris.network`)'
entryPoints:
- websecure
priority: 10
tls:
certResolver: letsencrypt
middlewares:
- sso-ratelimit
service: sso-public
media-public:
rule: 'Host(`media.hubris.network`)'
entryPoints:
- websecure
priority: 10
tls:
certResolver: letsencrypt
middlewares:
- media-ratelimit
service: media-public
paperless-api-public:
rule: 'Host(`paperless.hubris.network`) && PathPrefix(`/api/`)'
entryPoints:
- websecure
priority: 20
tls:
certResolver: letsencrypt
middlewares:
- paperless-ratelimit
service: paperless-public
paperless-public:
rule: 'Host(`paperless.hubris.network`)'
entryPoints:
- websecure
priority: 10
tls:
certResolver: letsencrypt
middlewares:
- authentik-forwardauth
- paperless-ratelimit
service: paperless-public
git-public:
rule: 'Host(`git.hubris.network`)'
entryPoints:
- websecure
priority: 10
tls:
certResolver: letsencrypt
middlewares:
- git-ratelimit
service: git-public
mcp-public:
rule: 'Host(`mcp.hubris.network`)'
entryPoints:
- websecure
priority: 10
tls:
certResolver: letsencrypt
middlewares:
- mcp-ratelimit
service: mcp-public
oikos-public:
rule: 'Host(`oikos.hubris.network`)'
entryPoints:
- websecure
priority: 10
tls:
certResolver: letsencrypt
middlewares:
- oikos-ratelimit
service: oikos-public
proxmox-public:
rule: 'Host(`proxmox.hubris.network`)'
entryPoints:
- websecure
priority: 10
tls:
certResolver: letsencrypt
middlewares:
- proxmox-ratelimit
service: proxmox-public
middlewares:
admin-allowlist:
ipAllowList:
sourceRange:
- "5.61.168.0/24"
artifacto-strip-sso:
headers:
customRequestHeaders:
X-Artifacto-Gateway: ""
X-Authentik-Username: ""
X-Authentik-Groups: ""
X-Authentik-Email: ""
X-Authentik-Name: ""
X-Authentik-Uid: ""
X-Authentik-Jwt: ""
X-Authentik-Meta-Jwks: ""
X-Authentik-Meta-Outpost: ""
X-Authentik-Meta-Provider: ""
X-Authentik-Meta-App: ""
X-Authentik-Meta-Version: ""
artifacto-ratelimit:
rateLimit:
average: 50
period: 1s
burst: 100
blog-ratelimit:
rateLimit:
average: 100
period: 1s
burst: 200
trmnl-ratelimit:
rateLimit:
average: 20
period: 1s
burst: 40
matrix-ratelimit:
rateLimit:
average: 30
period: 1s
burst: 60
house-ratelimit:
rateLimit:
average: 30
period: 1s
burst: 60
sso-ratelimit:
rateLimit:
average: 30
period: 1s
burst: 60
media-ratelimit:
rateLimit:
average: 30
period: 1s
burst: 60
paperless-ratelimit:
rateLimit:
average: 20
period: 1s
burst: 40
authentik-forwardauth:
forwardAuth:
address: "http://192.168.8.6:9000/outpost.goauthentik.io/auth/traefik"
trustForwardHeader: true
authResponseHeaders:
- X-authentik-username
- X-authentik-groups
- X-authentik-email
- X-authentik-name
- X-authentik-uid
- X-authentik-jwt
- X-authentik-meta-jwks
- X-authentik-meta-outpost
- X-authentik-meta-provider
- X-authentik-meta-app
- X-authentik-meta-version
git-ratelimit:
rateLimit:
average: 30
period: 1s
burst: 60
mcp-ratelimit:
rateLimit:
average: 30
period: 1s
burst: 60
oikos-ratelimit:
rateLimit:
average: 30
period: 1s
burst: 60
proxmox-ratelimit:
rateLimit:
average: 20
period: 1s
burst: 40
services:
artifacto-public:
loadBalancer:
servers:
- url: 'http://192.168.8.205:3100'
blog-public:
loadBalancer:
servers:
- url: 'http://192.168.8.205:8080'
trmnl-public:
loadBalancer:
servers:
- url: 'http://192.168.8.211:9851'
matrix-public:
loadBalancer:
servers:
- url: 'http://192.168.8.242:8008'
matrix-wellknown-svc:
loadBalancer:
servers:
- url: 'http://matrix-wellknown:80'
house-public:
loadBalancer:
servers:
- url: 'http://192.168.8.244:3000'
sso-public:
loadBalancer:
servers:
- url: 'http://192.168.8.6:9000'
media-public:
loadBalancer:
servers:
- url: 'http://192.168.8.246:8096'
paperless-public:
loadBalancer:
servers:
- url: 'http://192.168.8.130:8000'
git-public:
loadBalancer:
servers:
- url: 'http://192.168.8.121:3000'
mcp-public:
loadBalancer:
serversTransport: caddy-hubris
servers:
- url: 'https://192.168.8.175:443'
oikos-public:
loadBalancer:
serversTransport: caddy-hubris
servers:
- url: 'https://192.168.8.175:443'
proxmox-public:
loadBalancer:
serversTransport: proxmox
servers:
- url: 'https://192.168.8.77:8006'

31
shared/authentik Normal file
View File

@@ -0,0 +1,31 @@
# Internal forward-auth upstream proxy (no TLS between Caddy handlers)
:8099 {
@outpost path /outpost.goauthentik.io/*
reverse_proxy @outpost https://auth.hubris.network:443 {
transport http {
tls_server_name auth.hubris.network
}
header_up Host auth.hubris.network
}
}
# Authentik forward-auth snippet (domain-level mode).
# Usage: add "import authentik" inside any site block to gate it.
(authentik) {
route {
reverse_proxy /outpost.goauthentik.io/* https://auth.hubris.network:443
forward_auth http://127.0.0.1:8099 {
uri /outpost.goauthentik.io/auth/caddy
copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Email X-Authentik-Name X-Authentik-Uid X-Authentik-Jwt X-Authentik-Meta-Jwks X-Authentik-Meta-Outpost X-Authentik-Meta-Provider X-Authentik-Meta-App X-Authentik-Meta-Version
trusted_proxies private_ranges
header_up X-Forwarded-Host {host}
header_up X-Forwarded-Proto {scheme}
header_up X-Forwarded-Uri {uri}
}
}
}
# Internal webhook receiver for auto-deploy from Gitea
:8080 {
reverse_proxy 127.0.0.1:8081
}