feat: update environment configuration and derive public URLs
Some checks are pending
E2E / Playwright e2e (push) Waiting to run

- Modified .env.example to include PUBLIC_HOST and SECURE variables for better environment management.
- Updated Dockerfile to pass PUBLIC_HOST and SECURE as build arguments and set them as environment variables.
- Enhanced next.config.mjs to derive public-facing URLs based on PUBLIC_HOST and SECURE, improving flexibility for different deployment environments.
This commit is contained in:
R3D347HR4Y 2026-06-18 08:13:55 +02:00
parent d6d18f911b
commit ce364dbdb4
3 changed files with 55 additions and 27 deletions

View File

@ -1,29 +1,26 @@
# =============================================================================
# Public suite URL — edit PUBLIC_HOST + SECURE when switching domain
# =============================================================================
# Hostname only (no scheme). Keep in sync with ulti-backend/.env PUBLIC_HOST.
PUBLIC_HOST=localhost
# "s" → https/wss (Cloudflare tunnel, prod) ; empty → http/ws (local nginx :80)
SECURE=
# API backend — URL relative : Next.js proxy vers nginx (:80), pas de CORS en dev
NEXT_PUBLIC_API_URL=/api/v1
NEXT_PUBLIC_WS_URL=ws://localhost/ws
# Cible du proxy Next (optionnel, défaut 127.0.0.1:80)
# Sert aussi aux appels OIDC serveur (discovery/token) — Docker: http://nginx
# ULTI_PROXY_ORIGIN=http://127.0.0.1:80
# OIDC Authentik (blueprints deploy/authentik dans ulti-backend)
NEXT_PUBLIC_OIDC_ISSUER=http://localhost/auth/application/o/ulti/
NEXT_PUBLIC_OIDC_CLIENT_ID=ulti-backend
# URL publique affichée dans les redirects OIDC (navigateur) — utiliser localhost, pas 0.0.0.0
# URL publique navigateur (suite nginx) — pas :3004 si tu passes par http://localhost/mail
NEXT_PUBLIC_APP_URL=http://localhost
# Cookies session Secure (auto: true seulement si NEXT_PUBLIC_APP_URL est https://)
# Cookies session Secure (auto: true si NEXT_PUBLIC_APP_URL dérivé en https://)
# COOKIE_SECURE=false
# Secret serveur uniquement — doit matcher ULTID_OIDC_CLIENT_SECRET / blueprint
OIDC_CLIENT_SECRET=changeme
# OnlyOffice editor (UltiDrive — tableurs/présentations)
NEXT_PUBLIC_ONLYOFFICE_URL=http://localhost/office
# Rich text editor (TipTap + Hocuspocus — docs texte)
NEXT_PUBLIC_HOCUSPOCUS_URL=ws://localhost/collab
# UltiAI (chemin proxy OpenWebUI — même origine)
NEXT_PUBLIC_AI_PUBLIC_PATH=/ai
# Origine UltiSpace par défaut (picker serveur apps Tauri mobiles)
# NEXT_PUBLIC_ULTISPACE_ORIGIN=https://dev.ultispace.fr
# Dev Next.js (:3000) : charger l'iframe depuis nginx (:80) pour cookies session + proxy OpenWebUI
NEXT_PUBLIC_AI_ORIGIN=http://localhost
# NEXT_PUBLIC_APP_URL, WS_URL, OIDC_ISSUER, ONLYOFFICE_URL, HOCUSPOCUS_URL,
# AI_ORIGIN, ULTISPACE_ORIGIN — dérivés dans next.config.mjs depuis PUBLIC_HOST + SECURE.

View File

@ -12,6 +12,10 @@ FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ARG PUBLIC_HOST=localhost
ARG SECURE=
ENV PUBLIC_HOST=$PUBLIC_HOST
ENV SECURE=$SECURE
ENV NEXT_TELEMETRY_DISABLED=1
RUN pnpm run build

View File

@ -10,22 +10,48 @@ const projectRoot = path.dirname(fileURLToPath(import.meta.url))
const ultiProxyOrigin = process.env.ULTI_PROXY_ORIGIN ?? "http://127.0.0.1"
/** "s" for https/wss when SECURE=s (or true/1). */
function suiteSecureSuffix() {
const secure = process.env.SECURE?.trim().toLowerCase()
if (secure === "s" || secure === "true" || secure === "1") return "s"
return ""
}
/** Derive browser-facing NEXT_PUBLIC_* URLs from PUBLIC_HOST + SECURE. */
function suitePublicEnv() {
const host = (
process.env.PUBLIC_HOST ??
process.env.DOMAIN ??
"localhost"
).trim()
const s = suiteSecureSuffix()
const origin = `http${s}://${host}`
return {
NEXT_PUBLIC_APP_URL: origin,
NEXT_PUBLIC_WS_URL: `ws${s}://${host}/ws`,
NEXT_PUBLIC_OIDC_ISSUER: `${origin}/auth/application/o/ulti/`,
NEXT_PUBLIC_ONLYOFFICE_URL: `${origin}/office`,
NEXT_PUBLIC_HOCUSPOCUS_URL: `ws${s}://${host}/collab/`,
NEXT_PUBLIC_AI_ORIGIN: origin,
NEXT_PUBLIC_ULTISPACE_ORIGIN: origin,
}
}
/** Hostnames allowed to load /_next/* in dev (tunnel, LAN, public dev domain). */
function allowedDevOrigins() {
const hosts = new Set([
"127.0.0.1",
"localhost",
"192.168.0.20",
"100.120.4.66",
"dev.ultispace.fr",
"dev.ultimail.fr",
])
const appUrl = process.env.NEXT_PUBLIC_APP_URL?.trim()
if (appUrl) {
const hosts = new Set(["127.0.0.1", "localhost"])
const publicHost = (
process.env.PUBLIC_HOST ??
process.env.DOMAIN ??
""
).trim()
if (publicHost) hosts.add(publicHost)
const derived = suitePublicEnv().NEXT_PUBLIC_APP_URL
if (derived) {
try {
hosts.add(new URL(appUrl).hostname)
hosts.add(new URL(derived).hostname)
} catch {
/* ignore invalid NEXT_PUBLIC_APP_URL */
/* ignore invalid origin */
}
}
return [...hosts]
@ -46,6 +72,7 @@ const mobilePageExtensions = ["tsx", "ts", "jsx", "js"]
const baseConfig = {
outputFileTracingRoot: projectRoot,
allowedDevOrigins: allowedDevOrigins(),
env: suitePublicEnv(),
typescript: {
ignoreBuildErrors: true,
},