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 5a26f3d300
commit d9c77e0b46
2 changed files with 23 additions and 5 deletions
+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 \