7.6 KiB
Infrastructure Documentation — gharbeia.net
Architecture
Hosts
-
production-1(10.10.10.201) - Docker host, runs all services
- Hermes Agent
- Management/automation host
Network
- Docker network
networking(172.28.10.0/24) - Proxmox VLANs: 1/10/20/30/40/50
- Services VLAN: 10.10.10.0/24
- Domain: gharbeia.net via Cloudflare (orange cloud/proxied)
External Access Architecture
Cloudflare (edge, orange cloud) └─ Cloudflare Tunnel "home" (cloudflared on production-1) └─ Traefik (entrypoint=tunnel, port 8081) ├─ Authentik Forward Auth (external routers) ├─ gharbeia-site (nginx) ├─ jellyfin (SSO via plugin + OIDC) ├─ gitea (native OIDC) └─ *.gharbeia.net services
Internal Access Architecture
LAN client (browser) └─ Traefik (entrypoint=secureweb, port 443) ├─ Authentik Forward Auth (internal.yaml routers) ├─ gharbeia-site (public, no auth) ├─ jellyfin (SSO via plugin) └─ *.gharbeia.net services
Service-to-service / automation / cross-VLAN
└─ Traefik (entrypoint=internal, port 8083 — NO auth)
└─ Same routing as secureweb, from traefik-internal-noauth.yaml
Key distinction: :443 = browsers/humans with Authentik auth.
:8083 = runners, automated tooling, services on other VLANs.
Services
gharbeia-site (Static Website)
- Container:
gharbeia-site(nginx:stable-alpine3.17-perl) - Purpose: Landing page for gharbeia.net
- Docroot:
/docker/appdata/gharbeia-site/html - Nginx config:
/docker/appdata/gharbeia-site/nginx.conf - Traefik router:
gharbeia-siteon entrypointstunnelandsecureweb
www.gharbeia.net → 301 redirect → gharbeia.net (handled by nginx)
Both domains in Traefik router rule: Host(\`gharbeia.net\`) || Host(\`www.gharbeia.net\`)
Cloudflare Tunnel "home"
- Container:
cloudflared(cloudflare/cloudflared:latest) - Config:
/docker/compose/cloudflared-config.yml(local, unused at runtime) - Runtime:
docker compose up -d cloudflaredwith--token(remote config from dashboard) - Local config is IGNORED when running with
--token— ingress rules come from Cloudflare Zero Trust dashboard's public hostname configuration - DNS CNAME records must point to
<tunnel-uuid>.cfargotunnel.com - Tunnel UUID:
c29295c5-946a-4ddf-bdfe-7eafcd74faa3
Public Hostnames (Cloudflare Dashboard)
These must be added in Cloudflare Zero Trust > Networks > Tunnels > home > Public Hostnames:
- *.gharbeia.net → https://traefik:443
- gharbeia.net → https://traefik:443 (must be explicit, wildcard doesn't cover root)
- www.gharbeia.net → https://traefik:443
DNS Records
gharbeia.net:
- CNAME → c29295c5-946a-4ddf-bdfe-7eafcd74faa3.cfargotunnel.com (proxied)
- MX → in1-smtp.messagingengine.com
- MX → in2-smtp.messagingengine.com
- TXT → v=spf1 include:spf.messagingengine.com ?all
www.gharbeia.net:
- CNAME → c29295c5-946a-4ddf-bdfe-7eafcd74faa3.cfargotunnel.com (proxied)
Authentication
Authentik (IdP)
- Provides SSO for all services
- Two modes: Forward Auth (proxy-level) and OIDC (service-level)
- External tunnel traffic: Forward Auth on all routers in compose labels
- Internal LAN: Forward Auth on all routers in internal.yaml
- Exceptions: Jellyfin (SSO plugin), Gitea (native OIDC)
Gitea — Native OIDC
- Configured in Gitea → Site Administration → Authentication Sources
- Authentik OIDC provider registered
- Works with native Gitea clients (no browser redirect needed)
Jellyfin — SSO-Auth Plugin v4.0.0.4
- Plugin: SSO-Auth (via Jellyfin plugin catalog)
- Authentik OIDC provider created, redirect URI:
https://jellyfin.gharbeia.net/sso/OID/redirect/Authentik - Scope mapping sends
groupsclaim in OpenID token - Plugin configured via API (
docker cpXML into container) - SSO button added to login page via Jellyfin branding config
- No Forward Auth — Jellyfin handles auth itself via plugin
Traefik Configuration
Source of Truth
- Compose labels:
/docker/compose/docker-compose.yamland companion files - Internal routers (auth):
/docker/compose/traefik-internal.yaml - Internal routers (noauth):
/docker/compose/traefik-internal-noauth.yaml - Runtime copy:
/docker/appdata/traefik/internal.yamlandinternal-noauth.yaml - Deploy:
restart.shcopies all yaml files to/docker/appdata/traefik/thendocker compose up -d traefik
Entrypoints
-
tunnel(port 8081) - Cloudflare Tunnel traffic (external)
-
secureweb(port 443) - Internal LAN traffic, TLS, with Authentik Forward Auth
-
internal(port 8083) - Internal service-to-service, NO Authentik auth, HTTP only
External Routers (tunnel entrypoint)
- Defined in compose labels
- All behind Authentik Forward Auth middleware (except Jellyfin, Gitea)
Internal Routers — Authenticated
Defined in traefik-internal.yaml (internal.yaml at runtime)
All on entrypoint secureweb (port 443, TLS)
All behind Authentik Forward Auth middleware
Common middleware chain: auth@file, security-headers@file, traefik-bouncer@file
Internal Routers — Authless
Defined in traefik-internal-noauth.yaml (internal-noauth.yaml at runtime)
All on entrypoint internal (port 8083, HTTP)
No Authentik Forward Auth (no authentik-forwardauth@file middleware)
Same services as the authenticated routers, same backend URLs
Common middleware chain: security-headers@file, traefik-bouncer@file
Used for: runners, cross-VLAN tooling, service-to-service API calls
Services already authless on secureweb (Gitea, gharbeia-site) also have noauth copies for consistency.
LOGBOOK
[2026-05-15 Thu 06:10] Static site launched
- Setup gharbeia.net and www.gharbeia.net with nginx container
- Tunnel + Traefik wiring
- www → root 301 redirect in nginx config
- Traefik router on both tunnel and secureweb entrypoints
[2026-05-15 Thu 06:38] Internal authless entrypoint + domain migration
- Added Traefik `internal` entrypoint (port 8083) for authless service-to-service traffic
- Created `/docker/compose/traefik-internal-noauth.yaml` with 28 router copies
- Copied to runtime: `/docker/appdata/traefik/internal-noauth.yaml`
- Exposed port 8083 on traefik container (`INTERNAL_PORT_TRAEFIK=8083`)
- Added to restart.sh deployment: `sudo cp traefik-internal-noauth.yaml $FOLDER_FOR_DATA/traefik/internal-noauth.yaml`
- Unbound already resolves `*.gharbeia.net` → `10.10.10.201` via `local-zone redirect` — no changes needed
- Docker containers already inherit this DNS through embedded DNS (127.0.0.11) → host DNS → Unbound
- Updated Gitea runner: `GITEA_INSTANCE_URL: http://10.10.10.201:3001` → `http://git.gharbeia.net:8083`
- Verified: runner registers and communicates through domain-based URL
- Gitea config already used domains: `ROOT_URL = https://git.gharbeia.net/`
- Gluetun extra_hosts kept as-is (safety net for VPN namespace DNS leaks)
- Architecture: browsers use
:443(secureweb, with auth); services/automation use:8083(internal, no auth)
[2026-05-15 Thu 06:18] Error 1033 on gharbeia.net
- Problem: CNAME for
gharbeia.netpointed to old tunnel (2cd53dc4-…), not "home" tunnel (c29295c5-…) - www.gharbeia.net worked because its CNAME was correct
- www → root redirect → Cloudflare tried old tunnel → 1033
- Fix: Updated CNAME DNS record via Cloudflare API (DNS token)
- Config.yml on disk had correct entries but ISN'T used at runtime (tunnel runs with
--token) - Lesson: Bare domain DNS must point to the same tunnel UUID as subdomains
- Lesson: The local cloudflared-config.yml is decorative when running with
--token