259 lines
12 KiB
Markdown
259 lines
12 KiB
Markdown
# 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**):
|
|
```sh
|
|
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.sh` startet Grafana mit `GF_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 interne `FB_GRAFANA_URL`
|
|
(`http://localhost:3000/grafana`, für die GUI-Passwortänderung) — beides in
|
|
`create_pod_finance.sh` automatisch abgeleitet;
|
|
- alle GUI-Links/iframes bilden sich aus dieser URL (Jinja-Global
|
|
`grafana_public_base`, siehe `app/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`:
|
|
```yaml
|
|
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
|
|
```apache
|
|
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
|
|
```apache
|
|
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)
|
|
|
|
1. DNS `fbwl.creature-go.com` → sv005; Cert via Virtualmin/Let's Encrypt.
|
|
2. Traefik-Router (Teil 2) ablegen — `watch` lädt automatisch.
|
|
3. sv005 Apache (Teil 3) eintragen — Apache reload.
|
|
4. Testen (unten), solange Tool noch im Lokalmodus (`/grafana` kommt erst mit Schritt 5).
|
|
5. `.env`-Cutover (Teil 1) + Redeploy — **`FB_SESSION_COOKIE_SECURE='true'` zuletzt**.
|
|
|
|
## Verifikation
|
|
|
|
```bash
|
|
# 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 via `grafana_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/` mit `entryPoints: ["wghttp"]`, `priority > 1`, Backend
|
|
`http://10.0.2.2:PORT`; an sv005 meist nichts nötig, weil `ProxyPass /` die
|
|
ganze Domain weiterreicht und Traefik nach Pfad trennt.
|
|
- **Neuer Port am Pod**: in `create_pod_finance.sh` als `127.0.0.1:PORT`
|
|
veröffentlichen → Traefik erreicht ihn als `10.0.2.2:PORT`.
|
|
- **Grafana-Sub-Pfad**: `GF_SERVER_ROOT_URL` + `serve_from_sub_path` und die
|
|
präfixierten internen URLs werden in `create_pod_finance.sh` aus
|
|
`FB_GRAFANA_PUBLIC_URL` abgeleitet — den Pfad (`/grafana`) nicht ohne Grund
|
|
ändern; er steckt auch im Health-Check und in `FB_GRAFANA_URL`.
|
|
- **Lokaler Test trotz Live-Proxy**: `.env`-Schalter leeren (echter Lokalmodus)
|
|
ODER mit `curl` testen; ein echter Browser braucht die HTTPS-Domain, weil das
|
|
Session-Cookie `Secure` ist.
|
|
- **Traefik ist geteilt** (User `trf`): dessen Config ist als `wlfb` nicht
|
|
editierbar. Router-/Entrypoint-Änderungen müssen als `trf` erfolgen; den
|
|
Black-Hole-Router und fremde Dienste nicht anfassen.
|