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
| Datei | Inhalt | Git |
|---|---|---|
config.php | systemVersion, Directory-Konstanten, Password-Salt, Baseurl-Ableitung | versioniert |
config.local.php | DB-Zugangsdaten, Update-Server-Credentials | git-ignored |
config.local.example.php | Template fuer neue Installationen | versioniert |
config.php laedt config.local.php automatisch am Anfang:
// 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
$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.
$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:
# _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-baseFuer Produktion werden API- und Site-URL auf die oeffentliche Domain gesetzt (z. B. https://www.example.com/api / https://www.example.com).
| Variable | Zweck |
|---|---|
NUXT_API_KEY | Interner Key fuer Server-zu-Server-Aufrufe aus Nuxt (z. B. SSR-Fetches) |
NUXT_PUBLIC_API_BASE | Basis-URL der REST-API, wird clientseitig exposed |
NUXT_PUBLIC_SITE_URL | Kanonische Site-URL (Open Graph, Sitemap, Schema.org) |
NUXT_PUBLIC_THEME | Aktiver Theme-Name — steuert Alias-Aufloesungen (siehe Themes › Nuxt-Aliases) |
PurgeCSS-Safelist
Projektspezifische Klassen lassen sich ohne Fork der nuxt.config.ts ergaenzen:
NUXT_PURGECSS_SAFELIST_STANDARD=ma-,foo- # exakter Prefix-Match
NUXT_PURGECSS_SAFELIST_GREEDY=bar- # Contains-Match
NUXT_PURGECSS_SAFELIST_DEEP=baz- # Deep-Selector-MatchJeder 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:
- Admin →
/admin/api-keys→ Tab Allowed Origins - Origin eintragen (z. B.
http://localhost:3000fuer den Nuxt-Dev-Server gegen ein Remote-Backend) - 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:
curl -H "X-Api-Key: nscms_k1_your_key_here" https://your-domain.com/api/pages?view=startVerwaltet 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:
- Erster Login → QR-Code scannen (Google Authenticator, 1Password, Bitwarden, Authy, Microsoft Authenticator, …)
- 6-stelligen Code eingeben
- Acht Recovery-Codes abspeichern — werden nur einmal gezeigt
- 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 (
auth10 Versuche,checkout10/Min,elearning/certificate5/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:truezurueck — 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
- Installation — Erstes Setup, Apache, Datenbank-Import
- Verzeichnisstruktur — wo liegt was
- Themes › Environment-Variablen — alle Nuxt-Env-Variablen im Detail
- Plugins › API-Endpunkte — API-Auth und CORS aus Plugin-Sicht