Skip to content

Konfiguration

New Semantics trennt Konfiguration strikt in versionierte Defaults (config.php) und lokale Secrets (config.local.php). Zusaetzlich liest das Nuxt-Theme eine .env ein, und im Backend werden CORS, API-Keys und 2FA dynamisch verwaltet.

config.php vs. config.local.php

DateiInhaltGit
config.phpsystemVersion, Directory-Konstanten, Password-Salt, Baseurl-Ableitungversioniert
config.local.phpDB-Zugangsdaten, Update-Server-Credentialsgit-ignored
config.local.example.phpTemplate fuer neue Installationenversioniert

config.php laedt config.local.php automatisch am Anfang:

php
// config.php (Ausschnitt)
if (file_exists(__DIR__ . '/config.local.php')) {
    require_once __DIR__ . '/config.local.php';
}

$GLOBALS['systemVersion'] = "3.0.0";
$GLOBALS['pw_salt']       = '...';
$GLOBALS['baseurl']       = 'https://' . $_SERVER['HTTP_HOST'];

pw_salt nie aendern

$GLOBALS['pw_salt'] ist Bestandteil jedes User-Passwort-Hashs. Wird der Salt nachtraeglich geaendert, schlagen alle Logins fehl. Bei einer neuen Installation einen frischen Salt setzen, danach nicht mehr anfassen.

baseurl ist hardcoded https://

$GLOBALS['baseurl'] praeft nicht $_SERVER['HTTPS'] — das Schema ist fest https://. Lokale Entwicklung ueber http:// funktioniert trotzdem, aber Features, die baseurl fuer absolute Links nutzen (E-Mails, Sitemap, Schema.org), geben in dem Fall falsche URLs aus. Fuer lokale Arbeit: entweder mit HTTPS-Vhost (z. B. mkcert) oder $GLOBALS['baseurl'] manuell ueberschreiben.

config.local.php

Minimales Template (config.local.example.php):

php
<?php
$GLOBALS["db_host"] = "localhost";
$GLOBALS["db_user"] = "";
$GLOBALS["db_pw"]   = "";
$GLOBALS["db_db"]   = "";

$GLOBALS["update_user"]     = "";
$GLOBALS["update_password"] = "";
$GLOBALS["update_base_url"] = "https://update.newmeta.de";

Update-Server-Credentials

Der Update Manager unter /admin/update zieht ZIP-Updates vom Update-Server. Ohne Zugangsdaten ist Git-basiertes Arbeiten weiterhin moeglich — es werden nur die In-Place-Updates deaktiviert.

php
$GLOBALS['update_user']     = 'username';
$GLOBALS['update_password'] = 'password';
$GLOBALS['update_base_url'] = 'https://update.newmeta.de';

Mehr dazu in der README-Sektion Update Manager; eine dedizierte Update-Doku ist fuer zukuenftige Releases geplant.

.env-Dateien des Themes

Das Nuxt-Theme liegt unter _theme/vue-base/ und liest eine .env beim Start von Dev- bzw. Build-Server:

env
# _theme/vue-base/.env
NUXT_API_KEY=123456
NUXT_PUBLIC_API_BASE=http://newmeta.local/api
NUXT_PUBLIC_SITE_URL=http://newmeta.local
NUXT_PUBLIC_THEME=vue-base

Fuer Produktion werden API- und Site-URL auf die oeffentliche Domain gesetzt (z. B. https://www.example.com/api / https://www.example.com).

VariableZweck
NUXT_API_KEYInterner Key fuer Server-zu-Server-Aufrufe aus Nuxt (z. B. SSR-Fetches)
NUXT_PUBLIC_API_BASEBasis-URL der REST-API, wird clientseitig exposed
NUXT_PUBLIC_SITE_URLKanonische Site-URL (Open Graph, Sitemap, Schema.org)
NUXT_PUBLIC_THEMEAktiver Theme-Name — steuert Alias-Aufloesungen (siehe Themes › Nuxt-Aliases)

PurgeCSS-Safelist

Projektspezifische Klassen lassen sich ohne Fork der nuxt.config.ts ergaenzen:

env
NUXT_PURGECSS_SAFELIST_STANDARD=ma-,foo-    # exakter Prefix-Match
NUXT_PURGECSS_SAFELIST_GREEDY=bar-          # Contains-Match
NUXT_PURGECSS_SAFELIST_DEEP=baz-            # Deep-Selector-Match

Jeder Prefix wird zu einer ^prefix-RegExp und mit den Defaults (^ns-, ^swiper, ^fa-, …) gemerged.

CORS / Allowed Origins

CORS ist dynamisch — die eigene Domain ist immer erlaubt, weitere Origins werden im Backend gepflegt:

  1. Admin → /admin/api-keys → Tab Allowed Origins
  2. Origin eintragen (z. B. http://localhost:3000 fuer den Nuxt-Dev-Server gegen ein Remote-Backend)
  3. Aktivieren — keine Deploy-Schritte noetig

Anfragen von nicht registrierten Origins werden global abgelehnt — das betrifft auch public Endpoints wie /api/pages. Die genaue Fehler-Response (CORS-Reject ohne Body vs. HTTP-Statuscode) haengt davon ab, an welcher Stelle der Request abgewiesen wird.

Lokal ohne Cross-Origin

Wer das Nuxt-Theme ueber denselben Apache-Vhost ausliefert wie die API, hat kein CORS-Problem. Der Dev-Server (localhost:3000) gegen einen Remote-API-Host braucht hingegen immer einen Origin-Eintrag.

API-Keys fuer externe Zugriffe

Externe Tools authentifizieren sich ueber den X-Api-Key-Header:

bash
curl -H "X-Api-Key: nscms_k1_your_key_here" https://your-domain.com/api/pages?view=start

Verwaltet unter /admin/api-keys — pro Key konfigurierbar: Endpunkte, HTTP-Methoden, Ablaufdatum, erlaubte Origins. Keys werden SHA-256-gehasht gespeichert und nur einmal bei Erzeugung angezeigt.

Webhook-Subscriptions, HMAC-Secrets und Delivery-Historie liegen im selben Panel — siehe Plugins › Webhook-Events.

2FA-Setup fuer Admin-Logins

2FA (TOTP nach RFC 6238) ist obligatorisch fuer alle Backend-Logins:

  1. Erster Login → QR-Code scannen (Google Authenticator, 1Password, Bitwarden, Authy, Microsoft Authenticator, …)
  2. 6-stelligen Code eingeben
  3. Acht Recovery-Codes abspeichern — werden nur einmal gezeigt
  4. Jeder weitere Login verlangt zusaetzlich den TOTP-Code

Der Code-Vergleich ist timing-safe ueber hash_equals() — siehe _core/system/auth/TotpAuth.php::verifyCode(). Die Pending-2FA-Session laeuft nach 5 Minuten ab (auth/model.php::verify2fa()).

Brute-Force-Schutz: 2FA-Verifizierung teilt sich den Login-Attempts-Zaehler (Tabelle loginattempts, IP-basiert, Limit 15 Fehlversuche) mit der Passwort-Prueung. Ein erfolgreicher Login loescht den Zaehler.

Recovery-Codes aufbewahren

Verliert ein Admin den zweiten Faktor und die Recovery-Codes, hilft nur noch manueller DB-Eingriff in user_recovery_codes. Ein Zuruecksetzen via Web-UI gibt es bewusst nicht.

Rate-Limiting

Rate-Limits werden ueber APCu durchgesetzt — Token-Bucket pro Identifier (Backend-User-ID, API-Key oder IP), keine DB-Last. Der Limiter ist die erste Pruefung im Request-Lifecycle und schuetzt so die Datenbank unter Last.

  • Globale Limits: Frontend 100 Req/Min, Backend 250 Req/Min, API-Key 60 Req/Min
  • Endpoint-spezifisch: strengere Per-IP-Limits auf sensible Endpoints (auth 10 Versuche, checkout 10/Min, elearning/certificate 5/Min)
  • Konfiguration: _core/system/api/Ratelimiter.php ($endpointLimits-Array)
  • Standard-Header: X-RateLimit-Limit, X-RateLimit-Remaining, Retry-After (bei 429)
  • Graceful Degradation: Ohne APCu gibt der Limiter silent allowed:true zurueck — Requests werden nicht blockiert

Response-Cache

Anonyme GET-Responses werden in APCu gecached (X-Cache: HIT|MISS-Header). Konfiguration im Backend-Plugin cache_settings — dort laesst sich Cache aktivieren/deaktivieren, TTL setzen und der Cache leeren.

Personalisierte Requests (eingeloggte User via $_SESSION['userid'], Backend-User via $_SESSION['backend_loggedin'], API-Key-Anfragen via HTTP_X_API_KEY) werden nie gecached — das ist hardcoded. Zusaetzlich liegen Endpoint-Ausschluesse in _public/extensions/core/backend/cache_settings/config/cache_exclude_endpoints.json (Prefix-Match). Alle backend/*-Endpoints sind generell vom Cache ausgeschlossen.

Siehe auch