Skip to main content
Home
Schatzchaeschtli 2026

Main navigation

  • Home
User account menu
  • Log in

Breadcrumb

  1. Home

Settings Struktur per.net

By PierreAdmin , 14 September 2026

Dieses Dokument beschreibt den Aufbau und die Verwendung der verschiedenen Settings-Dateien innerhalb des Projekts.

Ziel ist eine klare Trennung zwischen gemeinsamer Projektkonfiguration, geheimen Umgebungswerten und Development-Einstellungen. Die Struktur bleibt dabei möglichst nahe am Drupal Core.

1 Grundstruktur

Für die lokale Entwicklungsumgebung und dev (settings.local und settings.dev) gilt folgende Ladereihenfolge:

settings.php
└── settings.local.php
    └── settings.development.php
        └── development.pernet.services.yml

settings.development.php wird bewusst über settings.local.php und nicht direkt über settings.php geladen.

Dadurch ist sichergestellt, dass Development-Einstellungen auf Stage oder Live nicht allein durch das Vorhandensein der versionierten Datei aktiviert werden.

1.1 -- Die Settings-Dateien im Einzelnen

1.1.1 -- settings.php

public/web/sites/default/settings.php ist die gemeinsame, versionierte Basis aller Umgebungen (local, dev, stage und live).

Die Datei bleibt möglichst nahe an der von Drupal erzeugten settings.php und enthält:

  • die allgemeine Drupal-Konfiguration,
  • verschiede Pfade die nicht mehr über das Backend gepflegt werden, sondern ausschliesslich über die settings.php
    • Pfad: Config Sync
      den gemeinsamen Pfad für Config Sync. Dazu die folgende Zeile anpassen, die auf mein /config/sync Verzeichnis ausserhalb des Webroots zeigt.
      • $settings['config_sync_directory'] = dirname($app_root, 2) . '/config/sync';
      • Bemerkung zu dirname($app_root, 2):
        $app_root enthält den absoluten Pfad zum Drupal Application Root (bei uns …/public/web); dirname($app_root, 2) geht von diesem Pfad zwei Verzeichnisebenen nach oben, bei uns also von …/public/web zum Projektordner (z.B. /pernet-starter)
    • Pfad: Öffentliche Dateien
      Öffentliche Dateien liegen bei per.net Projekten unter public/web/media und nicht wie üblich unter sites/default/files. Das ergibt kürzere und neutralere URLs. Der Ordner wird nicht versioniert..
      • $settings['file_public_path'] = 'media';
    • Pfad: Private
      Geschütztes Verzeichnis ausserhalb des Webroots, auf das nicht direkt über eine URL im Browser zugegriffen werden kann. Hier legen wir Dateien ab, die Drupal nur nach einer Rechteprüfung ausliefert, sowie die Backups vom Modul «Backup and Migrate». Auf local zusätzlich das der Ordner deployment-settings, wo die settings.local, settings.dev, settings.stage und settings.live abgelegt sind. Diese Dateien müssen auf den entsprechenden Instanzen manuell ersetzt werden, da sie die sensiblen Daten enthalten. Private wird nicht versioniert.
      • $settings['file_private_path'] = dirname($app_root, 2) . '/private';
    • Pfad: tmp
      Das temporäre Verzeichnis wird von Drupal und Modulen für kurzzeitig benötigte Dateien verwendet, z. B. während Datei-Uploads, Importen, Archiverstellung oder anderen Verarbeitungsschritten, bevor Dateien verarbeitet, verschoben oder wieder gelöscht werden; deshalb liegt auch tmp bewusst ausserhalb des öffentlich erreichbaren Webroots.
      • $settings['file_temp_path'] = dirname($app_root, 2) . '/private/tmp';
  • am Ende der Datei binden wir die umgebungsspezifischen Settings ein. Wir prüfen, dass nur eine der vier möglichen Dateien da ist und laden diese. settings.dev.php, settings.stage.php und settings.live.php liegen in private/deployment-settings, werden nicht versioniert und müssen als einzige Datei separat auf Dev, Stage und Live geladen werden.
    • $environment_files = [];
      
      foreach (['local', 'dev', 'stage', 'live'] as $environment) {
        $file = $app_root . '/' . $site_path
          . '/settings.' . $environment . '.php';
      
        if (file_exists($file)) {
          $environment_files[] = $file;
        }
      }
      
      if (count($environment_files) !== 1) {
        throw new \RuntimeException(
          'Genau eine Umgebungsdatei muss vorhanden sein: '
          . 'settings.local.php, settings.dev.php, settings.stage.php oder settings.live.php.'
        );
      }
      
      include $environment_files[0];

Datenbank-Zugangsdaten und «hash_salt» bleiben in settings.php leer ($databases = []; und $settings['hash_salt'] = '';) und werden in settings.local.php, entsprechend settings.dev.php, settings.stage.php und settings.live.php gesetzt.

Die von Drupal mitgelieferte default.settings.php bleibt unverändert bestehen. Nach Core-Updates dient Git dazu, Änderungen an dieser Referenzdatei zu erkennen und bei Bedarf in die eigene settings.php zu übernehmen.

 

1.1.2. -- settings.local.php

gilt auch für settings.dev.php, settings.stage.php und settings.live.php mit kleinen Ausnahmen.

public/web/sites/default/settings.local.php enthält ausschliesslich lokale und geheime Werte:

  • lokale Datenbankverbindung,
  • hash_salt
  • die Kennung der Umgebung für das Modul pernet_environment (local, dev, stage oder live),
  • Shield (Passwortschutz) und Trusted Hosts,
  • Einbindung von den Entwicklungseinstellungen settings.development.php
    auf settings.stage.php soll die Einbindung von settings.development.php da sein, aber auskommentiert. In der Regel braucht es das nicht, aber zum debuggen sinnvoll, wenn es auf stage aktiviert werden kann.

Die Datei wird nicht versioniert.

Beispieldatei settings.local.php

<?php

// phpcs:ignoreFile

$settings['hash_salt'] = 'HASH HIER EINKOPIEREN';

/**
 * Database connection.
 */
$databases['default']['default'] = array (
  'database' => 'DB-NAME',
  'username' => 'DB-USER',
  'password' => 'DB-PW',
  'prefix' => '',
  'host' => '127.0.0.1',
  'port' => '3306',
  'collation' => 'utf8mb4_general_ci',
  'isolation_level' => 'READ COMMITTED',
  'driver' => 'mysql',
  'namespace' => 'Drupal\\mysql\\Driver\\Database\\mysql',
  'autoload' => 'core/modules/mysql/src/Driver/Database/mysql/',
);

/**
 * Current environment for per.net (local, dev, stage, live).
 */
$settings['pernet_environment'] = 'local';

/**
 * Enable Shield for the local environment.
 */
$config['shield.settings']['shield_enable'] = TRUE;
$config['shield.settings']['credential_provider'] = 'shield';
$config['shield.settings']['credentials']['shield']['user'] = 'SHIELD-BENUTZERNAME';
$config['shield.settings']['credentials']['shield']['pass'] = 'SHIELD-PASSWORT';

/* Load development settings */
if (file_exists($app_root . '/' . $site_path . '/settings.development.php')) {
  include $app_root . '/' . $site_path . '/settings.development.php';
}

/**
 * Trusted host configuration.
 * 
 * $settings['trusted_host_patterns'] = [
 *   '^example\.com$',         // = genau example.com
 *   '^.+\.example\.com$',     // = Subdomain: www.example.com, stage.example.com, usw
 *                             // . muss immer escaped werden \. 
 * ];
 * 
*/
$settings['trusted_host_patterns'] = [
  '^local\.projekt\.test$',
];

settings.dev.php: 
Identisch wie settings.local.php, aber mit den DB-Daten des Dev-Servers, pernet_environment = 'dev' und dem Dev-Hostnamen. settings.development.php bleibt eingebunden, Shield bleibt aktiv:

$settings['pernet_environment'] = 'dev';

$settings['trusted_host_patterns'] = [
 '^dev-projekt\.selfip\.net$',
];

settings.stage.php: 
Identisch wie settings.local.php aber DB Daten können/sollten sich unterscheiden und der Link zu settings.development.php ist auskommentiert:
Vorteil unterschiedliche DB-Zugänge hilft auch Verwechslungen zu verhindern. Development Settings sind generell auskommentiert, es kann aber sinnvoll sein, sie in stage bei Problemen und zum Debuggen schnell wieder zu aktivieren.

$settings['pernet_environment'] = 'stage';

/* Load development settings */
# if (file_exists($app_root . '/' . $site_path . '/settings.development.php')) {
#  include $app_root . '/' . $site_path . '/settings.development.php';
# }

$settings['trusted_host_patterns'] = [
  '^stage\.projekt\.ch$',
];

settings.live.php: 
Identisch wie settings.local.php aber DB Daten sollten sich unterscheiden aber Link zu settings.development.php braucht es gar nicht und Shield reicht es es zu deaktivieren:

$settings['pernet_environment'] = 'live';

/**
* Disable Shield for the live environment.
*/
$config['shield.settings']['shield_enable'] = FALSE;

$settings['trusted_host_patterns'] = [
  '^projekt\.ch$',
  '^www\.projekt\.ch$',
];

1.1.3. -- settings.development.php

public/web/sites/default/settings.development.php enthält die gemeinsamen Development-Einstellungen des Projekts und wird versioniert. Sie ist eine Kopie von public/web/sites/example.settings.local.php, welche alle grundsätzlichen Entwicklungseinstellungen enthält. Sie wird nur auf local und dev geladen.

Dazu gehören:

  • Einbindung von development.pernet.services.yml,
    Dies ist eine Kopie von development.services.yml wo zusätzlich twig.config eingefügt wurde.
  • ausführliche Fehlermeldungen,
  • deaktivierte CSS- und JS-Aggregation,
  • optionale Cache-Deaktivierung (um Änderungen in twig Dateien ohne Cache Reload sofort angezeigt zu bekommen),
  • deaktiviertes Permission Hardening während der lokalen Entwicklung,
  • Ausschluss der Entwicklermodule (Devel, Kint) vom Config-Export.

Wir passen den Pfad zur development.pernet.services.yml an. Diese Einstellung ist schon da, verweist aber auf die Originaldatei development.services.yml, welche nach Core-Update überschrieben wird und eine Ebene über dem default-Verzeichnis (in sites/) liegt.

/**
 * Enable development services.
 */
$settings['container_yamls'][] = DRUPAL_ROOT . '/sites/development.pernet.services.yml';
Weitere Änderungen. Erklärung weiter unten.
$settings['cache']['bins']['render'] = 'cache.backend.null';
$settings['cache']['bins']['page'] = 'cache.backend.null';
$settings['cache']['bins']['dynamic_page_cache'] = 'cache.backend.null';

# $settings['rebuild_access'] = TRUE; // per.net: aus, Cache leeren per drushh cr

Am Ende der Datei Export der dev-Module ausschliessen. Siehe unten zu confit_exclude_modules:

// per.net: Devel und Kint nicht in den Config-Export, sie fehlen auf Stage/Live (--no-dev)
$settings['config_exclude_modules'] = ['devel', 'kint'];

Kurze Erläuterungen zu einigen settings:

  • error_level = 'verbose': Zeigt ausführliche Fehlermeldungen inklusive Stacktrace zur Fehlersuche.
  • css/js preprocess = FALSE: Deaktiviert das Zusammenfassen und Optimieren von CSS-/JavaScript-Dateien. Erleichtert die Frontend-Entwicklung.
  • rebuild_access (auskommentiert): Würde den Aufruf von /core/rebuild.php ohne Login erlauben. Das Skript leert zwischengespeicherte Informationen über PHP-Klassen und den Service-Container, als Notfall-Einstieg, wenn die Site wegen veralteter Caches nicht mehr startet. Wir lassen es aus: Caches leeren geht per drushh cr, und auf dev wäre die Seite von aussen erreichbar. Ist die Zeile aktiv, meldet der Status-Report einen Fehler.
  • skip_permissions_hardening = TRUE: Unterbindet Drupals automatische Härtung der Dateirechte von sites/default und settings.php. Bereits gesetzte Rechte werden dadurch nicht gelockert.
  • config_exclude_modules: Die aufgeführten Module bleiben lokal aktiv, werden aber bei drushh cex nicht exportiert, weder in der Modulliste (core.extension.yml) noch mit ihrer eigenen Config. Grund: Devel und Kint werden mit --dev installiert und fehlen auf Stage/Live. Stünden sie in der exportierten Modulliste, würde drushh cim dort versuchen, sie zu aktivieren, und abbrechen. In settings.stage.php und settings.live.php braucht es die Zeile nicht, dort wird nur importiert. Kommt ein weiteres --dev-Modul dazu, gehört es ebenfalls in diese Liste.
Caches und Twig: was in Drupal passiert

Damit eine geänderte Twig-Datei nach dem Reload sofort sichtbar ist, müssen zwei Caches aus dem Weg:

  • Twig-Cache: Drupal übersetzt jede .html.twig einmal in PHP-Code und speichert ihn. Abgeschaltet wird er in development.pernet.services.yml mit twig.config → cache: false (siehe 1.1.4).
  • HTML-Caches: Drupal speichert zusätzlich das fertige HTML von Blöcken, Feldern und Seiten. Solange es im Cache liegt, ruft Drupal das Template gar nicht auf. Abgeschaltet werden sie mit den drei Zeilen unten.

Nur beides zusammen zeigt Änderungen sofort an. BrowserSync stösst dabei nur den Reload im Browser an.

Achtung Stolperfalle: Bei den drei Zeilen gilt Zeile ohne # = Cache AUS, Zeile mit # = Cache AN.

Die drei Zeilen sind in settings.development.php ohne # (Cache AUS):

$settings['cache']['bins']['render'] = 'cache.backend.null';
$settings['cache']['bins']['page'] = 'cache.backend.null';
$settings['cache']['bins']['dynamic_page_cache'] = 'cache.backend.null';
  • render: HTML von Blöcken, Feldern usw. wird nicht gespeichert, sondern jedes Mal neu aufgebaut.
  • page: Ganze Seiten für anonyme Besucher werden nicht gespeichert.
  • dynamic_page_cache: Seiten für angemeldete Benutzer werden nicht gespeichert.

Alle drei verwenden cache.backend.null aus development.pernet.services.yml.

Zusammenspiel: Die drei HTML-Caches liegen wie Schichten übereinander. Ist auch nur einer AN, kann er das alte HTML liefern, z. B. dynamic_page_cache, wenn ich eingeloggt bin, oder page, wenn BrowserSync in einem Browser läuft, in dem ich nicht angemeldet bin. Darum gilt: Alle vier Einstellungen gehören zusammen. Eine allein reicht nicht.

Schalttabelle (nach jedem Umstellen drush cr):

EinstellungTwig-Arbeit (Standard lokal)Caches wie Live
cache.bins.renderohne # (Cache AUS)mit # (Cache AN)
cache.bins.pageohne # (Cache AUS)mit # (Cache AN)
cache.bins.dynamic_page_cacheohne # (Cache AUS)mit # (Cache AN)
twig.config → cachefalsetrue

twig.config → debug ist ein eigenes Thema und hat damit nichts zu tun: nur bei Bedarf auf true. auto_reload: true kann immer so bleiben. Es wirkt nur bei cache: true und übersetzt dann geänderte Twig-Dateien automatisch neu.

Warum standardmässig Cache AUS: Sie wirken nur auf local und dev. Bei unseren Projekten macht das die Site nicht spürbar langsamer, und man muss sich beim Arbeiten nicht darum kümmern.

Kontrolle mit Caches: Stage lädt settings.development.php nicht, dort laufen alle Caches. Vor dem Schritt auf Live auf Stage prüfen, ob alles richtig angezeigt wird.

Wo drush cr trotzdem nötig ist:

  • neue Twig-Dateien,
  • neue Funktionen in .theme oder .module
  • Änderungen an *.libraries.yml, *.info.yml, *.services.yml, *.routing.yml
  • twig.config (z. B. debug umstellen).

CSS und JS sind von diesen Caches nicht betroffen.

Nur CSS/JS-Aggregation testen

Nach dem Zusammenfassen funktioniert manchmal etwas nicht mehr. Zum Testen in settings.development.php diese zwei Zeilen mit # versehen (Aggregation AN), dann drush cr. Zurück: # wieder entfernen, drush cr.

$config['system.performance']['css']['preprocess'] = FALSE;
$config['system.performance']['js']['preprocess'] = FALSE;
Lokal testen wie auf Live

Am einfachsten in settings.local.php die Einbindung von settings.development.php auskommentieren, dann drush cr. Damit fallen alle Entwicklungseinstellungen auf einmal weg: Caches, Aggregation, Fehlermeldungen und auch twig.config, weil die yml-Datei nur über settings.development.php geladen wird. Zurück: # wieder entfernen, drush cr.

 

1.1.4. -- Development-Services

Die von Drupal mitgelieferte Datei public/web/sites/development.services.yml wird nicht verändert.

Stattdessen wird eine eigene Kopie angelegt:

public/web/sites/development.pernet.services.yml

Eigene Änderungen können dadurch bei Core-Updates nicht überschrieben werden. Gleichzeitig bleibt die Core-Datei für Vergleiche unverändert erhalten.

Unter `parameters` wird die Twig-Konfiguration ergänzt:

parameters:
  http.response.debug_cacheability_headers: true

  twig.config:
    debug: true
    auto_reload: true
    cache: false

Die Einstellungen bewirken:

  • debug: true aktiviert Twig-Debug-Kommentare und Template-Vorschläge im HTML-Quelltext.
  • auto_reload: true kompiliert geänderte Twig-Dateien automatisch neu.
  • cache: false deaktiviert den Twig-Template-Cache, damit Änderungen sofort sichtbar werden.

Der restliche relevante Inhalt aus development.services.yml, insbesondere das Null-Cache-Backend und der Config-Schema-Checker, bleibt erhalten.

 

1.2. -- Dateirechte

Drupal schützt sites/default und settings.php nach der Installation. Für die Einrichtung werden beide vorübergehend beschreibbar gemacht.

chmod u+w public/web/sites/default
chmod u+w public/web/sites/default/settings.php

Nach Abschluss werden die Schreibrechte wieder entzogen:

chmod u-w public/web/sites/default
chmod u-w public/web/sites/default/settings.php

 

1.3. -- Git

Versioniert werden

public/web/sites/default/settings.php
public/web/sites/default/settings.development.php
public/web/sites/development.pernet.services.yml
config/sync/

Nicht versioniert werden:

public/web/sites/default/settings.local.php
public/web/sites/default/settings.dev.php
public/web/sites/default/settings.stage.php
public/web/sites/default/settings.live.php

Vor jedem Commit wird geprüft, dass keine Datenbank-Zugangsdaten oder andere Secrets aufgenommen werden.

1.4 -- Stage und Live

Die endgültige Struktur von settings.stage.php und settings.live.php wird im Deployment-Konzept festgelegt.

Es gelten bereits folgende Grundsätze:

  • Local und dev binden settings.development.php ein.
  • Stage bleibt standardmässig produktionsnah.
  • Auf Stage kann settings.development.php für einen kontrollierten Test vorübergehend bewusst eingebunden werden.
  • Live bindet settings.development.php niemals ein.

Damit bleiben gemeinsame Projektkonfiguration, Secrets und Development-Einstellungen klar voneinander getrennt.

  • drupal
  • drupal 11
  • settings
Drupal

Tag Suche

Categories (Taxonomie-Menu)

  • Drupal
    • Module
    • Theming
    • Views
  • Webentwicklung
    • Composer
    • CSS/SCSS
    • Deployment
    • Drush
    • Git
    • HTML
    • JavaScript
    • PHP
    • SSH
    • SVG
    • VS Code
  • Datenbank
    • mySQL
  • Server
    • Apache
    • DNS
    • Domains
    • Plesk
    • SSL/TLS
  • System
    • Mac
    • Unix
    • Windows