contao/core — pull request #6959 by tristanlins (2014-05-04 10:29:36+00:00)
Title: [POC] [WIP] Add generic proxy support.

- [x] Respect the `X-Forwarded-Host` header
- [ ] Allow multiple proxy domains
- [ ] Use a domain mapping table for `X-Forwarded-Host`

Ich experimentiere gerade im Rahmen einer Kundenaquise mit Contao und seiner "load balancing" Fähigkeit rum. Sowohl mit Varnish, nginx als auch Apache. Dabei stoße ich an ein paar Probleme. Vorwiegend entstehen die Probleme beim load balancer, denn die Nodes haben dort NICHT den gleichen Hostname, wie der Proxy.

Das sieht dann so aus:

```
WWW
|
\- contao.example.com (Varnish)
|
\- contao.example.com (load balancing via nginx oder Apache)
|
|- node1.contao.example.com (Apache) --- MariaDB Cluster Node 1 -\
| |
\- node2.contao.example.com (Apache) --- MariaDB Cluster Node 2 -/
```

Ich könnte theoretisch bei den Nodes die Hauptdomain als Alias eintragen und dem Apache beibringen, aber normalerweise macht man das so nicht. Außerdem wird es dann schwierig die einzelnen Nodes zu testen.

Via `initconfig.php` experimentiere ich gerade ein wenig rum, bspw. so:

```php
if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
if (isset($_SERVER['HTTP_HOST']) && substr($_SERVER['HTTP_HOST'], 0, 4) == 'node') {
$_SERVER['HTTP_HOST'] = preg_replace('~^node\d+~\.', '', $_SERVER['HTTP_HOST']);
}
if (isset($_SERVER['SERVER_NAME']) && substr($_SERVER['SERVER_NAME'], 0, 4) == 'node') {
$_SERVER['SERVER_NAME'] = preg_replace('~^node\d+~\.', '', $_SERVER['SERVER_NAME']);
}
}
```

Allerdings geht das ganze im Multidomain Betrieb wieder nicht bzw. wenn ich einen DNS in der Rootpage eintrage, also forziere ich einen HTTP_HOST:

```php
if (isset($_SERVER['HTTP_HOST']) && substr($_SERVER['HTTP_HOST'], 0, 4) == 'node') {
if (!isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
$_SERVER['HTTP_X_FORWARDED_HOST'] = $_SERVER['HTTP_HOST'];
}

$_SERVER['HTTP_HOST'] = preg_replace('~^node\d+~\.', '', $_SERVER['HTTP_HOST']);
}
if (isset($_SERVER['SERVER_NAME']) && substr($_SERVER['SERVER_NAME'], 0, 4) == 'node') {
if (!isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
$_SERVER['HTTP_X_FORWARDED_HOST'] = $_SERVER['SERVER_NAME'];
}

$_SERVER['SERVER_NAME'] = preg_replace('~^node\d+~\.', '', $_SERVER['SERVER_NAME']);
}
```

Sieht etwas merkwürdig aus, aber damit kann ich erreichen, dass ich jeden Node auch unter `nodeX.contao.example.com` erreichen kann. Das ganze funktioniert allerdings nur mit diesem Patch, weil mir Contao sonst die falsche FE URL generiert. Jetzt behandelt Contao den `X-Forwarded-Host` Header imo korrekt, während er vorher gar nicht für non-ssl-proxy-Aufrufe berücksichtigt wurde.

So lassen sich auch mehrere Domains im Cluster in einer Installation verwalten, so lange die Node-Domains mit `nodeX.` anfangen.

-----

Was dem ganzen noch zu gute kommt, ich habe noch einen Staging Node der mit syncCto mit node1 und node2 Synchronisiert wird. Dabei ist mir aufgefallen, dass man diese Funktion auch wunderbar für syncCto ausnutzen könnte, um Multi-Domain Systeme unter einer staging Installation zu unterstützen, aktuell verwende ich dafür in meiner `initconfig.php` (das ist natürlich ein bad practice Beispiel, aber rein zum experimentieren ausreichend):

```php
if (isset($_SERVER['HTTP_HOST']) && substr($_SERVER['HTTP_HOST'], 0, 5) == 'stage') {
$GLOBALS['TL_CONFIG']['proxyDomain'] = $_SERVER['HTTP_X_FORWARDED_HOST'] = $_SERVER['HTTP_HOST'];
$_SERVER['HTTP_HOST'] = preg_replace('~^stage[\.-]~', '', $_SERVER['HTTP_HOST']);
}
else if (isset($_SERVER['SERVER_NAME']) && substr($_SERVER['SERVER_NAME'], 0, 5) == 'stage') {
$GLOBALS['TL_CONFIG']['proxyDomain'] = $_SERVER['HTTP_X_FORWARDED_HOST'] = $_SERVER['SERVER_NAME'];
$_SERVER['SERVER_NAME'] = preg_replace('~^stage[\.-]~', '', $_SERVER['SERVER_NAME']);
}
```

Mein Staging Node läuft als `stage.contao.example.com`, rufe ich die Domain auf, läuft Contao jetzt als HTTP_HOST `contao.example.com` und nutzt als `X-Forwarded-Host` die `stage.contao.example.com`. Ich kann also ohne Probleme auf der Staging Installation arbeiten, auch wenn ich `contao.example.com` als Domain in die Rootpage eingetragen habe :-)

Falls hier Interesse besteht das Feature weiter zu verfolgen, wäre eine Domain-Mapping-Tabelle die man in den Systemeinstellungen pflegen kann sicherlich hilfreicher, als dass alles in der `initconfig.php` von Hand machen zu müssen. Sollte der Patch auf Interesse stoßen, liefere ich da gerne noch was.