fix(config): make FRONTEND_URL optional and default to APP_URL

This commit is contained in:
Tronax 2026-08-27 20:44:39 +02:00
parent bfae47f584
commit 5fb92fd582
Signed by: Tronax
SSH key fingerprint: SHA256:2pKKXDZucWvaF/GzXNz0FY53EAO1YDLN80bqS+TTz/o
4 changed files with 21 additions and 8 deletions

View file

@ -36,8 +36,9 @@ USER app
ENV PORT=8080 \
DB_PATH=/data/wannpassts.db \
STATIC_DIR=/app/dist \
APP_URL=http://localhost:8080 \
FRONTEND_URL=http://localhost:8080
APP_URL=http://localhost:8080
# FRONTEND_URL ist bewusst nicht gesetzt: Ohne Wert leiten Callbacks auf APP_URL.
# Bei getrenntem Frontend-Host einfach -e FRONTEND_URL=https://… setzen.
VOLUME /data
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \

View file

@ -7,11 +7,15 @@ PORT=8080
# SQLite-Datenbankdatei (relativ zum backend-Verzeichnis)
DB_PATH=wannpassts.db
# Öffentliche URL des Backends (wichtig für den Google-OAuth-Redirect!)
# Öffentliche URL des Backends. Wichtig für:
# - Google-OAuth-Redirect: {APP_URL}/api/calendars/google/callback
# - Umleitung nach erfolgreichem Google-Login (sofern FRONTEND_URL leer)
APP_URL=http://localhost:8080
# URL des Frontends (dev: Vite, prod: gleiche Origin wie StaticDir)
FRONTEND_URL=http://localhost:5173
# URL des Frontends optional! Leer/unset = es wird APP_URL verwendet
# (Single-Origin, z. B. Docker). Nur setzen, wenn das Frontend getrennt läuft
# (Dev: Vite auf http://localhost:5173).
FRONTEND_URL=
# Statische Secrets in Produktion zwingend setzen (z. B. `openssl rand -hex 32`)
# JWT_SECRET sichert Logins, ENCRYPTION_KEY verschlüsselt gespeicherte Kalender-Tokens.

View file

@ -5,6 +5,7 @@ import (
"encoding/hex"
"log"
"os"
"strings"
"github.com/joho/godotenv"
)
@ -29,14 +30,19 @@ func Load() Config {
cfg := Config{
Port: env("PORT", "8080"),
DBPath: env("DB_PATH", "wannpassts.db"),
AppURL: env("APP_URL", "http://localhost:8080"),
FrontendURL: env("FRONTEND_URL", "http://localhost:5173"),
AppURL: strings.TrimSuffix(env("APP_URL", "http://localhost:8080"), "/"),
FrontendURL: strings.TrimSuffix(os.Getenv("FRONTEND_URL"), "/"),
JWTSecret: os.Getenv("JWT_SECRET"),
EncryptionKey: os.Getenv("ENCRYPTION_KEY"),
GoogleClientID: os.Getenv("GOOGLE_CLIENT_ID"),
GoogleClientSecret: os.Getenv("GOOGLE_CLIENT_SECRET"),
StaticDir: env("STATIC_DIR", ""),
}
// FRONTEND_URL ist optional: Ohne eigenen Wert leiten Google-Callbacks etc.
// auf die öffentliche App-URL (APP_URL) wichtig für Single-Origin-Deployments.
if cfg.FrontendURL == "" {
cfg.FrontendURL = cfg.AppURL
}
if cfg.JWTSecret == "" {
cfg.JWTSecret = randomHex(32)
log.Println("WARNUNG: JWT_SECRET nicht gesetzt temporäres Secret erzeugt (Sessions verfallen bei Neustart).")

View file

@ -10,8 +10,10 @@ services:
# (cp backend/.env.example backend/.env) und Kommentar entfernen:
# env_file: backend/.env
environment:
# APP_URL = öffentliche URL; Frontend-Callbacks leiten standardmäßig dorthin.
APP_URL: ${APP_URL:-http://localhost:8080}
FRONTEND_URL: ${FRONTEND_URL:-http://localhost:8080}
# Optional bei getrenntem Frontend-Host:
FRONTEND_URL: ${FRONTEND_URL:-}
JWT_SECRET: ${JWT_SECRET:-}
ENCRYPTION_KEY: ${ENCRYPTION_KEY:-}
GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}