12 KiB
Reverse-Proxy-Betrieb (Ausbaustufe 10) — LIVE
Das Finanzberatungs-Tool ist öffentlich erreichbar unter
https://fbwl.creature-go.com/ (App/GUI) mit Grafana als Unterpfad
https://fbwl.creature-go.com/grafana/. Aktiviert wird das ausschließlich
über zwei .env-Schalter auf sv006; ohne sie läuft der unveränderte
Lokalbetrieb auf 127.0.0.1 weiter (per Live-Redeploy + Sub-Pfad-Smoke belegt).
Die Proxy-Konfiguration (sv005 Apache, sv006 Traefik) liegt außerhalb dieses Repos — dieses Dokument hält den realen Stand fest, damit Änderungen am Tool die Kette nicht brechen.
Kette (Datenfluss)
Browser ──HTTPS──► sv005 (DesTEngSsv005)
Virtualmin/Apache, TLS-Terminierung, WireGuard-IP 10.8.0.1
ServerName fbwl.creature-go.com ──ProxyPass──► http://10.8.0.6:8080
──WireGuard (wg0)──►
sv006 (DesTEngSsv006 — DIESER Rechner)
Traefik: rootless-Podman-Pod "traefik_pod" (User trf),
Entrypoint "wghttp" published auf 10.8.0.6:8080
Router Host(fbwl.creature-go.com) ──► http://10.0.2.2:8096 (App/API)
Router Host(fbwl.creature-go.com) && /grafana ──► http://10.0.2.2:8097 (Grafana)
finance_pod: 127.0.0.1:8096 (App), 127.0.0.1:8097 (Grafana)
Warum 10.0.2.2? Traefik läuft in einem rootless-Podman-Pod mit
slirp4netns:allow_host_loopback=true. Aus Sicht des Traefik-Containers ist
127.0.0.1 der Container selbst; die auf dem Host an 127.0.0.1:8096/8097
veröffentlichten Pod-Ports erreicht er über die slirp4netns-Host-Loopback-Adresse
10.0.2.2. Backend-URLs im Traefik-Router deshalb IMMER 10.0.2.2:PORT,
niemals 127.0.0.1:PORT.
Warum funktioniert X-Forwarded-Proto sauber? sv005 hat die WireGuard-IP
10.8.0.1, und Traefiks Entrypoint wghttp vertraut per
forwardedHeaders.trustedIPs: 10.8.0.1/32 genau dieser Quelle. Das von sv005
gesetzte X-Forwarded-Proto: https wird also übernommen und (via uvicorn
--proxy-headers) bis zur App durchgereicht.
Teil 1 — finance_pod (.env auf sv006)
In ~/.local/share/finance_pod/.env (alle Werte single-quoted):
FB_GRAFANA_PUBLIC_URL='https://fbwl.creature-go.com/grafana/'
FB_SESSION_COOKIE_SECURE='true'
Übernehmen: ./stop_finance_pod.sh → .env editieren → ./create_pod_finance.sh.
Wirkung von FB_GRAFANA_PUBLIC_URL (leer ⇒ Lokalbetrieb, Grafana-Fallback
http://<host>:8097, Grafana an der Wurzel):
create_pod_finance.shstartet Grafana mitGF_SERVER_ROOT_URL+GF_SERVER_SERVE_FROM_SUB_PATH=true;- der Pfadanteil der URL (
/grafana) wird zum Präfix für den internen Grafana-Health-Check UND für die interneFB_GRAFANA_URL(http://localhost:3000/grafana, für die GUI-Passwortänderung) — beides increate_pod_finance.shautomatisch abgeleitet; - alle GUI-Links/iframes bilden sich aus dieser URL (Jinja-Global
grafana_public_base, sieheapp/routers/gui.py).
Achtung Secure-Cookie: Mit FB_SESSION_COOKIE_SECURE='true' akzeptiert ein
Browser das Session-Cookie nur über HTTPS — ein direkter Login über
http://127.0.0.1:8096 funktioniert dann nicht mehr, nur noch über die
HTTPS-Domain. Automatisierte Tests mit curl (-c/-b) laufen weiter, weil curl
das Secure-Flag ignoriert (bewährt bei Redeploy-Smoke-Tests).
Teil 2 — Traefik-Router (sv006, verwaltet als User trf)
Traefik ist ein geteilter rootless-Podman-Pod traefik_pod (User trf,
Config unter /home/trf/.local/share/traefik_pod/; als wlfb NICHT lesbar).
Statik: Entrypoint wghttp auf :8080 (published 10.8.0.6:8080),
forwardedHeaders.trustedIPs: 10.8.0.1/32; File-Provider dynamic/ mit
watch: true (Änderungen laden automatisch, kein Neustart, andere Dienste
unberührt).
Wichtig — Black Hole: Es gibt einen Catch-all-Router
(HostRegexp('{any:.*}'), priority: 1, Middleware ipAllowList 127.0.0.1/32),
der jeden nicht explizit gerouteten Host sofort mit 403 abweist. Jeder
öffentliche Dienst braucht daher einen eigenen Router mit
entryPoints: ["wghttp"] und priority > 1.
Router-Datei dynamic/fbwl.yml:
http:
routers:
finance-grafana:
rule: "Host(`fbwl.creature-go.com`) && PathPrefix(`/grafana`)"
priority: 120 # ueber dem Black Hole (priority 1)
service: finance-grafana
entryPoints: ["wghttp"]
finance-app:
rule: "Host(`fbwl.creature-go.com`)"
priority: 110
service: finance-app
entryPoints: ["wghttp"]
services:
finance-grafana:
loadBalancer:
servers:
- url: "http://10.0.2.2:8097" # slirp4netns-Host-Loopback, NICHT 127.0.0.1
finance-app:
loadBalancer:
servers:
- url: "http://10.0.2.2:8096"
Teil 3 — sv005 Apache (Virtualmin, Domain fbwl.creature-go.com)
Virtualmin → Server fbwl.creature-go.com → „Edit Directives" (bearbeitet
/etc/apache2/sites-available/fbwl.creature-go.com.conf). Aufgebaut nach dem
Muster des bestehenden affine.creature-go.com-vhosts: /.well-known lokal
(ACME/Let's-Encrypt-Erneuerung), HTTP→HTTPS-Redirect, dann Weiterleitung der
ganzen Domain an Traefik (10.8.0.6:8080) mit erhaltenem Host-Header. TLS-Cert
verwaltet Virtualmin/Let's Encrypt.
Port 80
SuexecUserGroup #1015 #1011
ServerName fbwl.creature-go.com
ServerAlias www.fbwl.creature-go.com
ServerAlias mail.fbwl.creature-go.com
ServerAlias webmail.fbwl.creature-go.com
ServerAlias admin.fbwl.creature-go.com
DocumentRoot /home/fbwl/public_html
ErrorLog /var/log/virtualmin/fbwl.creature-go.com_error_log
CustomLog /var/log/virtualmin/fbwl.creature-go.com_access_log combined
ScriptAlias /cgi-bin/ /home/fbwl/cgi-bin/
DirectoryIndex index.php index.htm index.html
<Directory /home/fbwl/public_html>
Options -Indexes +IncludesNOEXEC +SymLinksIfOwnerMatch +ExecCGI
Require all granted
AllowOverride All Options=ExecCGI,Includes,IncludesNOEXEC,Indexes,MultiViews,SymLinksIfOwnerMatch
AddHandler fcgid-script .php
AddHandler fcgid-script .php8.4
FCGIWrapper /home/fbwl/fcgi-bin/php8.4.fcgi .php
FCGIWrapper /home/fbwl/fcgi-bin/php8.4.fcgi .php8.4
</Directory>
<Directory /home/fbwl/cgi-bin>
Require all granted
AllowOverride All Options=ExecCGI,Includes,IncludesNOEXEC,Indexes,MultiViews,SymLinksIfOwnerMatch
</Directory>
ProxyPass /.well-known !
RewriteEngine on
RewriteCond %{HTTP_HOST} =webmail.fbwl.creature-go.com
RewriteRule ^/(?!\.well-known)(.*)$ https://fbwl.creature-go.com:20000/ [R=301,L]
RewriteCond %{HTTP_HOST} =admin.fbwl.creature-go.com
RewriteRule ^/(?!\.well-known)(.*)$ https://fbwl.creature-go.com:10000/ [R=301,L]
# --- Finanzberatungs-Tool: HTTP -> HTTPS (ausser ACME-Challenge) ---
RewriteCond %{HTTPS} off
RewriteCond %{REQUEST_URI} !^/\.well-known/
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
RemoveHandler .php
RemoveHandler .php8.4
FcgidMaxRequestLen 1073741824
Port 443
SuexecUserGroup #1015 #1011
ServerName fbwl.creature-go.com
ServerAlias www.fbwl.creature-go.com
ServerAlias mail.fbwl.creature-go.com
ServerAlias webmail.fbwl.creature-go.com
ServerAlias admin.fbwl.creature-go.com
DocumentRoot /home/fbwl/public_html
ErrorLog /var/log/virtualmin/fbwl.creature-go.com_error_log
CustomLog /var/log/virtualmin/fbwl.creature-go.com_access_log combined
ScriptAlias /cgi-bin/ /home/fbwl/cgi-bin/
DirectoryIndex index.php index.htm index.html
<Directory /home/fbwl/public_html>
Options -Indexes +IncludesNOEXEC +SymLinksIfOwnerMatch +ExecCGI
Require all granted
AllowOverride All Options=ExecCGI,Includes,IncludesNOEXEC,Indexes,MultiViews,SymLinksIfOwnerMatch
AddHandler fcgid-script .php
AddHandler fcgid-script .php8.4
FCGIWrapper /home/fbwl/fcgi-bin/php8.4.fcgi .php
FCGIWrapper /home/fbwl/fcgi-bin/php8.4.fcgi .php8.4
</Directory>
<Directory /home/fbwl/cgi-bin>
Require all granted
AllowOverride All Options=ExecCGI,Includes,IncludesNOEXEC,Indexes,MultiViews,SymLinksIfOwnerMatch
</Directory>
ProxyPass /.well-known !
RewriteEngine on
RewriteCond %{HTTP_HOST} =webmail.fbwl.creature-go.com
RewriteRule ^/(?!\.well-known)(.*)$ https://fbwl.creature-go.com:20000/ [R=301,L]
RewriteCond %{HTTP_HOST} =admin.fbwl.creature-go.com
RewriteRule ^/(?!\.well-known)(.*)$ https://fbwl.creature-go.com:10000/ [R=301,L]
# --- Finanzberatungs-Tool: Weiterleitung an Traefik (sv006, wghttp) ---
ProxyPreserveHost On
RequestHeader set X-Forwarded-Proto "https"
# WebSocket (Grafana Live) an Traefik durchreichen
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule .* ws://10.8.0.6:8080%{REQUEST_URI} [P,L]
# Haupt-Weiterleitung (Traefik trennt App vs. /grafana selbst)
ProxyPass / http://10.8.0.6:8080/
ProxyPassReverse / http://10.8.0.6:8080/
RemoveHandler .php
RemoveHandler .php8.4
FcgidMaxRequestLen 1073741824
SSLEngine on
SSLCertificateFile /etc/ssl/virtualmin/17848735353695059/ssl.cert
SSLCertificateKeyFile /etc/ssl/virtualmin/17848735353695059/ssl.key
SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
SSLCACertificateFile /etc/ssl/virtualmin/17848735353695059/ssl.ca
Hinweis: www./mail.fbwl… gehen (wie bei affine) über den Proxy an Traefik
und landen dort mangels Router im Black Hole (403) — fürs Tool irrelevant.
Cutover-Reihenfolge (falls die Kette neu aufgebaut wird)
- DNS
fbwl.creature-go.com→ sv005; Cert via Virtualmin/Let's Encrypt. - Traefik-Router (Teil 2) ablegen —
watchlädt automatisch. - sv005 Apache (Teil 3) eintragen — Apache reload.
- Testen (unten), solange Tool noch im Lokalmodus (
/grafanakommt erst mit Schritt 5). .env-Cutover (Teil 1) + Redeploy —FB_SESSION_COOKIE_SECURE='true'zuletzt.
Verifikation
# Von aussen:
curl -sI https://fbwl.creature-go.com/login | head -1 # -> 200
curl -sI https://fbwl.creature-go.com/grafana/api/health | head -1 # -> 200
curl -I http://fbwl.creature-go.com/ 2>&1 | head -3 # -> 301 auf https
# Auf sv006 (Kette bis Traefik, Host-Header simuliert):
for p in /login /grafana/api/health; do
curl -sS --max-time 5 -o /dev/null -w "$p -> %{http_code}\n" \
-H 'Host: fbwl.creature-go.com' "http://10.8.0.6:8080$p"
done
Der Grafana-iframe erfordert eine Grafana-Session (Embedding an, anonym aus): in
der GUI einmal „Grafana anmelden" (→ …/grafana) mit dem gemeinsamen Passwort.
Für künftige Claude-Sessions — was das für Änderungen am Tool bedeutet
- Domain/Links des Tools hängen ausschließlich an
FB_GRAFANA_PUBLIC_URL(+ Templates viagrafana_public_base). Kein Hostname im Code/Image — ein Domainwechsel ist eine reine.env-Änderung + Redeploy (plus je ein Eintrag in Traefik-Router und sv005-Apache). - Neuer öffentlicher Pfad/Dienst hinter derselben Domain: Traefik-Router in
dynamic/mitentryPoints: ["wghttp"],priority > 1, Backendhttp://10.0.2.2:PORT; an sv005 meist nichts nötig, weilProxyPass /die ganze Domain weiterreicht und Traefik nach Pfad trennt. - Neuer Port am Pod: in
create_pod_finance.shals127.0.0.1:PORTveröffentlichen → Traefik erreicht ihn als10.0.2.2:PORT. - Grafana-Sub-Pfad:
GF_SERVER_ROOT_URL+serve_from_sub_pathund die präfixierten internen URLs werden increate_pod_finance.shausFB_GRAFANA_PUBLIC_URLabgeleitet — den Pfad (/grafana) nicht ohne Grund ändern; er steckt auch im Health-Check und inFB_GRAFANA_URL. - Lokaler Test trotz Live-Proxy:
.env-Schalter leeren (echter Lokalmodus) ODER mitcurltesten; ein echter Browser braucht die HTTPS-Domain, weil das Session-CookieSecureist. - Traefik ist geteilt (User
trf): dessen Config ist alswlfbnicht editierbar. Router-/Entrypoint-Änderungen müssen alstrferfolgen; den Black-Hole-Router und fremde Dienste nicht anfassen.