TYPO3: Umgebungskontexte per .htaccess

Wer kennt es nicht? Wenn man eine Website implementiert, benötigt man oft Einstellungen für unterschiedliche Umgebungen. Meist sind das die Entwicklungsversion auf Eurem Rechner, eventuell eine Staging-Version auf einem internen oder externen Server und die Produktiv-Version, in der die Website schlussendlich läuft.

Je nachdem wie Ihr arbeitet, zum Beispiel über ein SCM wie Git, oder über direktes Veröffentlichen via PHP, benötigt Ihr für jede dieser Versionen unterschiedliche Einstellungen. Mindestens sind das in der Regel die Zugangsdaten zur Datenbank, aber auch weitere Konfigurationsvariablen für z.B. ImageMagick sind von Server zu Server unterschiedlich.

Wie also löst man das Umschalten der jeweiligen mit möglichst wenig Aufwand, also ohne, dass man aufpassen muss, dass man auch die richtigen Daten in der jeweiligen Umgebung hat?

Seit Längerem schon liefert TYPO3 CMS die Grundlage dafür mit, verschiedene Setups anhand von Umgebungsvariablen des Webservers auszuliefern.

Hier zeige ich Euch kurz beispielhaft, wofür man es nutzen kann.

Der wichtigste Punkt ist schon auskommentiert als Vorlage in der Datei .htaccess Eurer Installation zu finden:

# Rules to set ApplicationContext based on hostname
#RewriteCond %{HTTP_HOST} ^dev\.example\.com$
#RewriteRule .? - [E=TYPO3_CONTEXT:Development]
#RewriteCond %{HTTP_HOST} ^staging\.example\.com$
#RewriteRule .? - [E=TYPO3_CONTEXT:Production/Staging]
#RewriteCond %{HTTP_HOST} ^www\.example\.com$
#RewriteRule .? - [E=TYPO3_CONTEXT:Production]

Hier müsst Ihr im Prinzip nur Eure Hosts eintragen und es wieder einkommentieren. Ich halte es zum Beispiel so, dass ich auf meinem lokalen Rechner die Entwicklungsversion und auf einem externen Server je eine Staging- und eine Produktionsumgebung betreibe. Die Staging-Version ist für den Demo-Rollout für den Kunden und/oder die Redakteure, und sobald alles abgesegnet ist, geht es in die Produktivumgebung. Das könnt Ihr aber beliebig Euren Anforderungen anpassen. Hier ein Beispiel dessen, wie ich es handhabe:

# Rules to set ApplicationContext based on hostname
RewriteCond %{HTTP_HOST} ^dev\.kundenwebsite\.de$
RewriteRule .? - [E=TYPO3_CONTEXT:Development]
RewriteCond %{HTTP_HOST} ^staging\.kundenwebsite\.de$
RewriteRule .? - [E=TYPO3_CONTEXT:Production/Staging]
RewriteCond %{HTTP_HOST} ^www\.kundenwebsite\.de$
RewriteRule .? - [E=TYPO3_CONTEXT:Production]

Ihr könnt es aber natürlich auch vereinfachen, solltet Ihr nur die Entwicklungs- und die Live-Version haben:

# Rules to set ApplicationContext based on hostname
RewriteCond %{HTTP_HOST} ^dev\.kundenwebsite\.de$
RewriteRule .? - [E=TYPO3_CONTEXT:Development]
RewriteCond %{HTTP_HOST} ^www\.kundenwebsite\.de$
RewriteRule .? - [E=TYPO3_CONTEXT:Production]

Die hiermit gesetzte Umgebungsvariable ist dann für Euch PHP- und damit TYPO3-seitig einfach auswertbar. Ihr könnt also Bedingungen daran knüpfen, sowohl im PHP als auch im TypoScript, welche Umgebung Ihr gerade vor Euch habt.

Regelmäßig nutze ich dies insbesondere für unterschiedliche Einstellungen in der Datei LocalConfiguration.php. Hier werden wie oben angesprochen Zugangsdaten zur Datenbank, aber auch Einstellungen für z.B. ImageMagick abgelegt.

Aber bevor wir fortfahren, stellt sich ein Problem: Die LocalConfiguration.php wird vom Install-Tool von TYPO3 selbst verwaltet. Wenn man also doch noch einmal ins Install-Tool muss, werden die Daten mitunter wieder weggeschmissen und neu überschrieben, ein Context-Switch in dieser Datei ist damit also recht schwierig.

Abhilfe schafft hier, dass TYPO3 CMS für genau solche Fälle anbietet, parallel zu dieser Datei eine Datei namens AdditionalConfiguration.php anzulegen. Diese wird nach Abarbeitung der LocalConfiguration.php automatisch inkludiert und von TYPO3 nicht angefasst, was uns ermöglicht, hier genau die Konfigurationsdetails abzulegen, die sich von Umgebung zu Umgebung unterscheiden.

Da es sich um PHP handelt, könnt Ihr hier also eine einfache if-Abfrage platzieren, die je nach Umgebungsvariable aus der .htaccess-Datei andere Variablen setzt. Dazu fragt Ihr einfach die Variable $_SERVER["TYPO3_CONTEXT"] ab und erhaltet den String zurück, den Ihr in der .htaccess-Datei hierfür gesetzt habt. Hier müsst Ihr aber etwas aufpassen, da je nach Konfiguration des Webservers diese Variable auch mal nur als $_SERVER["REDIRECT_TYPO3_CONTEXT"] verfügbar ist. In meinem gleich folgenden Beispiel berücksichtige ich das. Es beinhaltet wie oben angesprochen zwei Setups mit Variablen für den Datenbankzugriff sowie ImageMagick. Außerdem setze ich nur für die Entwicklungsversion ein paar Einstellungen, die mir beim Debugging helfen:

// /typo3conf/AdditionalConfiguration.php
$context = !empty($_SERVER["TYPO3_CONTEXT"]) ? $_SERVER["TYPO3_CONTEXT"] : $_SERVER["REDIRECT_TYPO3_CONTEXT"];

if ( $context == "Development") {
    \TYPO3\CMS\Core\Configuration\ConfigurationManager::setLocalConfigurationValueByPath('DB/database', "kundenwebsite_local");
    \TYPO3\CMS\Core\Configuration\ConfigurationManager::setLocalConfigurationValueByPath('DB/host', "127.0.0.1");
    \TYPO3\CMS\Core\Configuration\ConfigurationManager::setLocalConfigurationValueByPath('DB/port', 3306);
    \TYPO3\CMS\Core\Configuration\ConfigurationManager::setLocalConfigurationValueByPath('DB/username', "root");
    \TYPO3\CMS\Core\Configuration\ConfigurationManager::setLocalConfigurationValueByPath('DB/password', "root");
    \TYPO3\CMS\Core\Configuration\ConfigurationManager::setLocalConfigurationValueByPath('SYS/displayErrors', "1");
    \TYPO3\CMS\Core\Configuration\ConfigurationManager::setLocalConfigurationValueByPath('SYS/systemLogLevel', 0);
    \TYPO3\CMS\Core\Configuration\ConfigurationManager::setLocalConfigurationValueByPath('GFX/im_path', '/opt/ImageMagick/bin/');
    \TYPO3\CMS\Core\Configuration\ConfigurationManager::setLocalConfigurationValueByPath('GFX/im_path_lzw', '/opt/ImageMagick/bin/');
}

if ( $context == "Production/Staging") {
    \TYPO3\CMS\Core\Configuration\ConfigurationManager::setLocalConfigurationValueByPath('DB/database', "db1");
    \TYPO3\CMS\Core\Configuration\ConfigurationManager::setLocalConfigurationValueByPath('DB/host', "127.0.0.1");
    \TYPO3\CMS\Core\Configuration\ConfigurationManager::setLocalConfigurationValueByPath('DB/port', 3307);
    \TYPO3\CMS\Core\Configuration\ConfigurationManager::setLocalConfigurationValueByPath('DB/username', "username_db1");
    \TYPO3\CMS\Core\Configuration\ConfigurationManager::setLocalConfigurationValueByPath('DB/password', "daspasswort");
    \TYPO3\CMS\Core\Configuration\ConfigurationManager::setLocalConfigurationValueByPath('SYS/displayErrors', "1");
    \TYPO3\CMS\Core\Configuration\ConfigurationManager::setLocalConfigurationValueByPath('SYS/systemLogLevel', 2);
    \TYPO3\CMS\Core\Configuration\ConfigurationManager::setLocalConfigurationValueByPath('GFX/im_path', '/usr/bin/');
    \TYPO3\CMS\Core\Configuration\ConfigurationManager::setLocalConfigurationValueByPath('GFX/im_path_lzw', '/usr/bin/');
}

Ein kleiner Wermutstropfen an der Stelle: TYPO3 CMS arbeitet derzeit so, dass es diese Einstellungen in die lokale LocalConfiguration.php übernimmt. Das ist aber kein Problem, da es nach einem Austausch der Dateien einfach wieder gemacht wird. Man muss lediglich damit leben, dass beim ersten Reload nach Austausch der Dateien die Daten noch nicht stimmen, wodurch ein Fehler geworfen wird. Bei diesem Aufruf aber übernimmt TYPO3 CMS die richtigen Daten, so dass es ab dem zweiten Aufruf dann läuft. Ein Reload zu viel, anstatt jede Datei immer wieder manuell zu synchronisieren.

Wir können also auf diese Art und Weise alle drei Dateien nur ein Mal anfassen und dennoch auf allen Umgebungen lauffähig behalten:

  • .htaccess
  • typo3conf/LocalConfiguration.php
  • typo3conf/AdditionalConfiguration.php

Darüber hinaus gibt es, wie oben angesprochen, auch die Möglichkeit, die Variable via TypoScript auszulesen, um auch hier if-Abfragen zu platzieren. Dies ist insbesondere dann von Vorteil, wenn man das TypoScript über TypoScript-Includes auf Dateiebene versioniert. Ein Beispiel in TypoScript:

[applicationContext = Development,Production/Staging]
config.admPanel = 1

[applicationContext = Production]
config.admPanel = 0

[global]

Zusammenfassung

Über das Setzen und Auswerten einer Umgebungsvariable des Webservers kann man sich das Leben beim Synchronhalten mehrerer Server sehr stark erleichtern und TYPO3 CMS bringt die dafür notwendigen Vorkehrungen mit.

Getestet und laufen habe ich das mit mehreren Installationen auf Apache2-Webservern, die jeweils TYPO3 CMS in Version 6.2 bis 7.6 fahren. Von 6.2 LTS bis 7.6 LTS gibt es hier auch keinerlei mir bekannte Unterschiede.

4 Antworten zu “TYPO3: Umgebungskontexte per .htaccess”

  1. Martin Bless sagt:

    Schöner Beitrag! Danke!

    Zur Info und Diskussion: Ich mache es so:

    <?php
    if (file_exists(PATH_site . 'typo3conf/AdditionalConfiguration.php.NOT_VERSIONED.php')) {
       include(PATH_site . 'typo3conf/AdditionalConfiguration.php.NOT_VERSIONED.php');
    }
    ?>

    Und in „AdditionalConfiguration.php.NOT_VERSIONED.php“ habe ich dann die Server-spezifischen Einstellungen.

    In .gitignore steht „*NOT_VERSIONED*“, so dass alle Dateien mit „NOT_VERSIONED“ im Namen nicht ins Repository wandern.

    Und auch be rsync kann man das Muster angeben, z. B.:

    rsync -rlt -z -v --safe-links --delete --exclude=*NOT_VERSIONED* -e 'ssh' $useratdomain:SRCDIR DESTDIR
  2. arnekolja sagt:

    Hallo Martin,

    habe Deinen Kommentar mal nach Deiner E-Mail dazu wegen der HTML-Entities bearbeitet. Hoffe, das ist so in Ordnung :-)

    So wie Du es machst, hab ich das im Grunde vor der Verwendung der Umgebungsvariablen auch gemacht. Ist auch ein guter Weg. Im Grunde nimmt sich das ja beides nichts, ich finde die Lösung mit den Umgebungsvariablen nur irgendwie sexier :-)

    • Martin Bless sagt:

      Wie so oft, es kommt halt drauf an. Was du machst, ist gut und richtig und elegant. An meinem mag ich, dass die Passwörter nicht ins Git-Repository gehen und ich auf dem einen Server nicht angeben muss was ich auf dem anderen benutze. Mach weiter so und schreibe schöne Beiträge (aber das machst du ja schon :-)!

  3. arnekolja sagt:

    Stimmt, da war ich etwas voreilig. Mit den Passwörtern ist das so natürlich irgendwo eleganter. Kenne ich von anderer Stelle auch, dass Zugangsdaten auf dem Server in einer nicht versionierten Datei landen. Ist ein sehr schöner „Catch“ daran.

    Aber: Man kann ja beides auch wunderbar kombinieren!

    Herzlichen Dank für das Lob – schauen wir mal ;-)

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *