Admin-Zugriff & Split-Container¶
Der Admin-Bereich (alles unter /admin) kann zusätzlich vom User-Portal getrennt werden, damit ein gestohlener Super-Admin-Account allein nicht reicht — der Angreifer muss zusätzlich Netzwerkzugang zur Admin-Topologie haben.
Drei Modi¶
| Modus | Wer kommt rein | Aufwand | Wann sinnvoll |
|---|---|---|---|
unrestricted (Default) |
Jeder mit Login | keiner | Single-Person-Setup, kein erhöhter Threat |
ip_allowlist |
Nur IPs aus deiner CIDR-Liste | 1 Setting | Office-IP / VPN-Subnet — ausreichend für die meisten Self-Hoster |
split_container |
Nur wer den Admin-Hostname / VPN / SSH-Tunnel erreicht | hoch | IT-Firmen mit vielen Endkunden |
unrestricted und ip_allowlist werden direkt unter Admin → System → Zugriff umgeschaltet. split_container braucht Compose-Setup-Arbeit — dafür ist der Setup-Wizard.
Split-Container — die drei Setup-Profile¶
Wenn du split_container aktivierst, läuft Vesana mit zwei API-Containern (public + admin). Wie der Traffic zu denen kommt, hängt davon ab, wer bei dir TLS terminiert. Dafür gibt es drei Profile:
stack-only — Stack-internes nginx terminiert TLS¶
Standard-Self-Hoster. Der nginx-Container im Compose-Stack hört direkt auf Port 443 des Hosts und macht selbst TLS.
So erkennst du das:
# Es gibt einen nginx-Container im Compose-Stack:
docker ps | grep nginx
# → vesana-nginx-1 ... 0.0.0.0:443->443/tcp ...
# Auf dem Host läuft kein zusätzliches nginx:
systemctl status nginx 2>/dev/null | head -1
# → Unit nginx.service could not be found. ODER inactive (dead)
Was der Wizard macht: schreibt den Admin-Vhost ins Volume /etc/vesana/nginx-overrides/admin-vhost.conf, das Stack-nginx liest ihn beim Restart über das include. Compose-Skript publiziert ggf. den zusätzlichen Admin-Port und macht restart nginx selbst.
Was du machst: Skript pasten, fertig.
vor-nginx — nginx (oder Caddy/Traefik) auf dem Host terminiert TLS¶
Du hast einen Reverse-Proxy außerhalb des Compose-Stacks. Der hört auf Port 443 und reicht HTTP an den Stack durch — entweder an den Stack-internen nginx oder direkt an die API. Häufig bei Setups mit mehreren Diensten auf einem Host (Vesana plus andere Apps), oder wenn der Reverse-Proxy schon vor Vesana da war.
So erkennst du das:
# Auf dem Host läuft ein nginx (oder Caddy/Traefik) als Service:
systemctl status nginx
# → active (running)
# Der hört auf Port 443:
ss -tlnp | grep ':443 '
# → LISTEN ... users:(("nginx", ...))
# Im Compose-Stack ist nginx nicht auf 443 gemappt:
docker ps | grep nginx
# → 0.0.0.0:8181->443/tcp ODER gar nicht 443 sondern z.B. 8180->80
Caddy / Traefik / HAProxy zählen genauso als „vor-nginx" — der Wizard generiert nginx-Vhost-Snippets, aber das Konzept (Reverse-Proxy auf Host, Backend im Container) ist identisch. Bei Caddy/Traefik musst du den generierten nginx-Vhost in deine eigene Config übersetzen.
Was der Wizard macht: generiert ein Skript, das die Vhost-Datei nach /etc/nginx/sites-available/<host>-admin legt, in sites-enabled verlinkt und nginx reloaded. Plus Compose-Skript, das den api-admin-Container auf 127.0.0.1:8082 published.
Was du machst: Vhost-Skript als root pasten, dann Compose-Skript pasten. Bei Caddy/Traefik den Vhost manuell übersetzen.
bare-metal — kein Compose-Stack¶
Du betreibst Vesana direkt via systemd auf dem Host (kein Docker). Selten, aber gibt's. Hier kann der Wizard wenig automatisieren — du startest den zweiten API-Prozess selbst.
So erkennst du das:
# Es gibt KEINEN api-Container:
docker ps | grep vesana-api
# Stattdessen: systemd-Service:
systemctl status vesana-api
# → active (running)
Was du machst: zweite systemd-Unit für api-admin mit VESANA_API_MODE=admin auf einem zweiten Port, Public-API auf VESANA_API_MODE=public umstellen, Reverse-Proxy auf admin-Port routen. Plan-Referenz: docs/admin-isolation-plan.md §6.8 Variante A.
Welche Wahl für mich?¶
Frage 1 — Läuft Vesana in Docker Compose?
Nein → bare-metal
Ja → Frage 2
Frage 2 — Hast du AUSSERHALB des Compose-Stacks einen
Reverse-Proxy (nginx / Caddy / Traefik) der auf
Port 443 hört?
Nein → stack-only
Ja → vor-nginx
Der Wizard im Admin-Portal hat eine Auto-Detection, die in den meisten Fällen richtig liegt. Bei Misdetection kannst du das Profil in Schritt 1 manuell überschreiben.
Konflikte & Sicherheits-Hinweise¶
- Cookie-Domain: Der Admin-Hostname und der User-Hostname sollten dieselbe Parent-Domain teilen, sonst geht das Session-Cookie verloren beim Wechsel. Wizard schlägt automatisch
.example.comvor wenn beide auf*.example.comliegen. - Custom-Port ≠ Subdomain: Browser isolieren Cookies nicht per Port. Port-Mode (z.B.
:8443) macht den Admin-Bereich nur per Permission-Check sicher, nicht per Browser-Origin. Wenn dir das wichtig ist → Subdomain-Mode + eigenes Cert. - Notfall-Bypass: Wenn du dich aussperrst (Setting
split_containeraber Compose-Override noch nicht aktiv), greift der Drift-Fallback: ADMIN-Routen sind nur noch über Localhost erreichbar. PlusVESANA_ADMIN_BYPASS=trueals Env-Var (30 min Override) oderpython -m api.app.cli.admin_recovery reset-mode unrestricted.
Weiterführend¶
- Operator-Runbook (im Repo):
docs/split-container-setup.md— Schritt-für-Schritt für eine Variante-A-Aktivierung, inkl. nginx-Templates und Recovery-Pfaden. - Plan:
docs/admin-isolation-plan.md§6.8 — Architektur-Entscheidungen (Variante A/B/C, Cookie-Scope, Drift-Fallback). - Permissions: Rollen & Permissions — wie
audit_log.view_*undtrash.*_*_scopemit den Modi zusammenwirken.