From cd03e2cf9cc4c3e827253e7c6ebae38c841d3e44 Mon Sep 17 00:00:00 2001 From: Patrick Date: Wed, 3 Jun 2026 09:29:13 +0200 Subject: [PATCH] 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 --- CLAUDE.md | 2 +- backend/main.py | 24 +++++++++++++++++++----- deploy/zfs-manager-backend.service | 4 ++++ 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 66de1a4..44e4252 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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. 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. -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://: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. 7. **Port 8090**: Default for ZMB Webui (HTTPS via nginx). Adjust in nginx/systemd if needed. diff --git a/backend/main.py b/backend/main.py index 402eb68..520b8a8 100644 --- a/backend/main.py +++ b/backend/main.py @@ -6,6 +6,7 @@ FastAPI backend for ZFS pool management import asyncio import json import logging +import os import sys from pathlib import Path from typing import Set @@ -35,11 +36,24 @@ app = FastAPI( 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://:8090,http://: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( CORSMiddleware, - allow_origins=["*"], # Change to specific origins in production - allow_credentials=True, + allow_origins=cors_origins, + allow_credentials=allow_credentials, allow_methods=["*"], allow_headers=["*"], ) @@ -144,13 +158,13 @@ async def status_check(): # Root endpoint - API info only @app.get("/") -async def root(): +async def root(request: Request): """API info""" return { "name": "ZMB Webui API", "version": "1.0.0", "docs": "/docs", - "frontend": "http://192.168.1.179:3000" + "frontend": str(request.base_url) } diff --git a/deploy/zfs-manager-backend.service b/deploy/zfs-manager-backend.service index 9d05951..1166468 100644 --- a/deploy/zfs-manager-backend.service +++ b/deploy/zfs-manager-backend.service @@ -9,6 +9,10 @@ WorkingDirectory=/opt/zmb-webui/backend Environment="PATH=/opt/zmb-webui/venv/bin" Environment="PYTHONUNBUFFERED=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://:8090" +#Environment="ZMB_CORS_ORIGINS=*" ExecStart=/opt/zmb-webui/venv/bin/python -m uvicorn main:app \ --host 0.0.0.0 \