Konfigurierbares CORS per ZMB_CORS_ORIGINS + dynamische Frontend-URL

- main.py: CORS-Origins aus ZMB_CORS_ORIGINS (kommagetrennt), Default "*"
- allow_credentials automatisch aktiv bei konkreten Origins, aus bei "*"
- Root-Endpoint liefert Frontend-URL dynamisch via request.base_url
- keine hartkodierten IPs mehr im Anwendungscode
- Doku in CLAUDE.md und systemd-Unit ergaenzt

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-03 09:29:13 +02:00
parent 40259ec93c
commit cd03e2cf9c
3 changed files with 24 additions and 6 deletions
+1 -1
View File
@@ -343,7 +343,7 @@ Useful on weak hardware: ISR pre-computes static pages on rebuild, serving cache
2. **User Persistence**: System users (Linux) and Samba users are stored on disk and survive application updates. No user re-creation needed on redeployment. 2. **User Persistence**: System users (Linux) and Samba users are stored on disk and survive application updates. No user re-creation needed on redeployment.
3. **ZFS Commands**: Require root or proper sudo configuration. Test with `sudo zpool list`. 3. **ZFS Commands**: Require root or proper sudo configuration. Test with `sudo zpool list`.
4. **Frontend Build on Pi**: Node.js build is slow on ARM64 (4-10 min). Build on x86 and copy instead. 4. **Frontend Build on Pi**: Node.js build is slow on ARM64 (4-10 min). Build on x86 and copy instead.
5. **CORS in Production**: Default allows all origins (`["*"]`). Change in `main.py` before exposing. 5. **CORS in Production**: Configurable via the `ZMB_CORS_ORIGINS` environment variable (comma-separated list of allowed origins). Defaults to `["*"]` when unset (development). Set specific origins before exposing, e.g. `ZMB_CORS_ORIGINS=https://<host>:8090`. Note: when concrete origins are set, `allow_credentials` is automatically enabled; with the `"*"` wildcard it is disabled (CORS spec forbids combining the two). Configure it in the systemd unit (`deploy/zfs-manager-backend.service`).
6. **Static Export Mode**: Cannot use dynamic API routes in Next.js. All data fetched client-side. 6. **Static Export Mode**: Cannot use dynamic API routes in Next.js. All data fetched client-side.
7. **Port 8090**: Default for ZMB Webui (HTTPS via nginx). Adjust in nginx/systemd if needed. 7. **Port 8090**: Default for ZMB Webui (HTTPS via nginx). Adjust in nginx/systemd if needed.
+19 -5
View File
@@ -6,6 +6,7 @@ FastAPI backend for ZFS pool management
import asyncio import asyncio
import json import json
import logging import logging
import os
import sys import sys
from pathlib import Path from pathlib import Path
from typing import Set from typing import Set
@@ -35,11 +36,24 @@ app = FastAPI(
version="1.0.0" version="1.0.0"
) )
# CORS middleware (adjust origins for production!) # CORS middleware — configurable via environment variable.
# Set ZMB_CORS_ORIGINS to a comma-separated list of allowed origins
# (e.g. "https://<host>:8090,http://<host>:3000").
# Defaults to "*" for development if unset.
_cors_origins_env = os.getenv("ZMB_CORS_ORIGINS", "*").strip()
cors_origins = (
["*"]
if _cors_origins_env == "*"
else [origin.strip() for origin in _cors_origins_env.split(",") if origin.strip()]
)
# allow_credentials cannot be combined with the "*" wildcard per the CORS spec
allow_credentials = cors_origins != ["*"]
logger.info("CORS allowed origins: %s", cors_origins)
app.add_middleware( app.add_middleware(
CORSMiddleware, CORSMiddleware,
allow_origins=["*"], # Change to specific origins in production allow_origins=cors_origins,
allow_credentials=True, allow_credentials=allow_credentials,
allow_methods=["*"], allow_methods=["*"],
allow_headers=["*"], allow_headers=["*"],
) )
@@ -144,13 +158,13 @@ async def status_check():
# Root endpoint - API info only # Root endpoint - API info only
@app.get("/") @app.get("/")
async def root(): async def root(request: Request):
"""API info""" """API info"""
return { return {
"name": "ZMB Webui API", "name": "ZMB Webui API",
"version": "1.0.0", "version": "1.0.0",
"docs": "/docs", "docs": "/docs",
"frontend": "http://192.168.1.179:3000" "frontend": str(request.base_url)
} }
+4
View File
@@ -9,6 +9,10 @@ WorkingDirectory=/opt/zmb-webui/backend
Environment="PATH=/opt/zmb-webui/venv/bin" Environment="PATH=/opt/zmb-webui/venv/bin"
Environment="PYTHONUNBUFFERED=1" Environment="PYTHONUNBUFFERED=1"
Environment="PYTHONDONTWRITEBYTECODE=1" Environment="PYTHONDONTWRITEBYTECODE=1"
# CORS: comma-separated list of allowed frontend origins.
# Leave unset (or "*") for development. Set to specific origins in production,
# e.g. Environment="ZMB_CORS_ORIGINS=https://<host>:8090"
#Environment="ZMB_CORS_ORIGINS=*"
ExecStart=/opt/zmb-webui/venv/bin/python -m uvicorn main:app \ ExecStart=/opt/zmb-webui/venv/bin/python -m uvicorn main:app \
--host 0.0.0.0 \ --host 0.0.0.0 \