Hitzigrath

Netzwerk-Administrator und Hobby-Fotograf

Benutzer-Werkzeuge

Webseiten-Werkzeuge


Seitenleiste

docs:raspberrypi:prj_reverse_proxy

HTTP Reverse Proxy

In einem kleinen Netzwerk, das nur über eine DSL-Verbindung an das Internet angebunden ist, hat man zumeist nur eine IP um den Zugriff von außen auf einen Dienst im eigenen Netz bereit stellen zu können. Bei Webservern ist das seit den Zeiten von sog. name-based Webservern eigentlich auch kein Problem. Doch es kann dennoch mal vorkommen, dass man mehrere Systeme im eigenen Netz hat, auf denen eine Website läuft, die man aber auch von außen (also aus dem Internet) bedienen will. Für diesen Zweck wird ein Reserve Proxy benötigt.

1 Projekt-Beschreibung

Bei diesem Projekt geht es um den Aufbau eines Reverse Proxy auf Basis eines Raspberry PIs um damit mehrere Websites mit einer IP eines DSL-Routers, die im Internet mit Hilfe von DynDNS1) aufgelöst wird, erreichbar zu machen.

Die Angaben von IPs, Hostnamen und FQDNs in diesem Artikel sind nur exemplarisch und bedienen sich einem imaginären Netzwerks für Dokumentationen, das in dem Beitrag Zusatz-Informationen zu IT-Beiträgen beschrieben ist.

1.1 Ausgangssituation

Da ein Raspberry PI nicht gerade ein leistungsstarker Webserver ist, wurde im Rahmen einer Umbau-Aktion von einem Energie-fressenden Server zu Strom-sparenden Raspberrys die Websites auf mehrere Geräte aufgeteilt. Um diese weiterhin auch über das Internet erreichbar machen zu können war der Schritt zu einem Reverse Proxy nötig.

1.2 Projektziel

Es soll hiermit eine Strom-sparende Möglichkeit geschaffen werden mehrere Websites auf verschiedenen Geräten über das Internet mit einer einzelnen IP erreichbar zu machen.

1.3 Ausgesuchte Komponenten

Das System besteht aus folgenden Komponenten:

Komponente erworben bei Preis2)
Raspberry PI Model B rev. 2 Amazon 35,20
Raspberry Pi Kühler Set Amazon 3,50 €
TEK-BERRY Gehäuse für Raspberry Pi 256 / 512 gelb Amazon 9,35 €
SanDisk Class 10 Ultra SDHC 8GB Speicherkarte (UHS-I, 30Mbps) Amazon 8,42 €
Steckernetzteil Micro-USB 5V 1500mA für Raspberry Pi Amazon 4,99 €
Gesamt: 61,46 €

Auf die Versandkosten wird hier nicht eingegangen, da die Bestellung mit mehreren anderen Systemen getätigt wurde und sich somit die Versandkosten verteilen und nur schwer von einander zu trennen sind.

Bei der Software fallen keine Kosten an, da es sich um frei erhältliche Software handelt.

2 Durchführung

Für die Funktion des Reverse Proxys müssen mehrere Komponenten zusammen spielen: Die Namensauflösung im Internet für die Websites, die Konfiguration des DSL-Routers, die Konfiguration der hiermit zu erreichenden Webservern und der Reverse Proxy selbst.

In diesem Beispiel wird von folgender Umgebung ausgegangen:

  • Webserver 1
    interne IP: 192.168.0.50
    • namebased Website webserver.intern.example.com mit ServerAlias webserver.example.com
    • namebased Website website1.intern.example.com mit ServerAlias website1.example.com
  • Webserver 2
    interne IP: 192.168.0.51
    • namebased Website webserver2.intern.example.com mit ServerAlias webserver2.example.com
    • namebased Website website2.intern.example.com mit ServerAlias website2.example.com
  • DSL-Router
    externe IP 198.51.100.123 mit FQDN des Providers conip.connect.example.net
  • Reverse Proxy
    interne IP 192.168.0.40

Die vom Internet her zu erreichenden Websites sind in dem Beispiel bereits für die FQDNs aus dem Internet in den VirtualHost-Deklarationen konfiguriert.

Bevor man mit einem solchen Projekt beginnt, sollte man sich um eine DNS-Struktur für die Namensauflösung gedanken machen und entsprechende Vorkehrungen treffen. Dazu mehr weiter unten in dieser Dokumentation unter Kapitel 4 DNS einrichten.

2.1 Vorbereitung des DSL-Routers

Auf dem DSL-Router sind zwei Sachen zu berücksichtigen. Einerseits muss eine Konfiguration erstellt werden, mit der der Router einen DynDNS-FQDN erhält. Dieser ist nötig um einen festen Bezugspunkt vor allem bei der Namensauflösung für das Erreichen der externen IP des Routers zu ermöglichen. In dem hier verwendeten Beispiel wird ein FQDN dyndnsint.example.net bei einem entsprechenden Provider eingerichtet. (Wie dies genau eingerichtet wird, liegt am eingesetzten Router und wird hier nicht explizit beschrieben, da die Unterschiede zu groß sind.)

Des Weiteren muss auf dem DSL-Router eine Umleitung des Port 80 (HTTP) auf den Reverse Proxy eingestellt werden.

2.2 Vorbereitung der Raspberry PI Installation

Zunächst muss das Gerät zusammen gesetzt werden. Da hier alle Komponenten einzeln beschafft wurden, ist im Vergleich zu den sonst gern verwendeten pi3g-Geräten3) etwas mehr Arbeit von Nöten. Dies beläuft sich in erster Linie auf die Anbringung der Kühlkörper.
Im wesentlichen ist dies aber dennoch recht flott (innerhalb von wenigen Minuten) erledigt.

Bei der Raspbian-Installation wird auf ein abgespecktes Grund-System gesetzt, wie es hier beschrieben ist. Da zuvor bereits ein Image von der abgespeckten Raspbian-Version gemacht wurde, reicht es dies auf eine SD-Karte zu spielen und die benötigten Änderungen zu Hostnamen, FQDN und IP zu tätigen. Dies kann sogar durch mounten der Root-Partition bei meiner normalen (Linux-)Workstation und anpassen der entsprechenden Dateien noch vor dem ersten Boot des Systems getätigt werden.

2.3 Ausführung mit Apache2

Nachdem das Basis-System soweit installiert und eingerichtet ist, muss nun die eigentliche Proxy-Installation getätigt werden. In diesem Kapitel wird dazu ein Apache-Server her genommen.

Die eigentliche Installation des Dienstes geschieht unter root mit apt-get install apache2-mpm-worker. Durch die Abhängigkeiten werden mit dem Befehl auch alle weiteren, vom Apache benötigten Pakete mit installiert.

Bei der Basis-Installation des Apache auf dem Raspberry PI ist die Komponente für den Proxy mod_proxy im Paket bereits enthalten und muss in der Konfiguration durch a2enmod proxy und a2enmod proxy_http aktiviert werden.

Als nächstes werden Konfigurationen zu den Websites benötigt, die vom Internet her erreichbar gemacht werden sollen. Dazu werden entsprechende Konfigurationsdateien in /etc/apache2/sites-available/ benötigt. Es empfiehlt sich dabei für jede Webserver-IP eine Datei wie folgt zu erstellen:

site1
<VirtualHost *:80>
    ServerName webserver.example.com
    ServerAlias website1.example.com
 
    ProxyRequests Off
    ProxyPreserveHost On
    ProxyPass / http://192.168.0.50/
    ProxyPassReverse / http://192.168.0.50/
</VirtualHost>

Die IP 192.168.0.50 ist entsprechend mit der IP des reellen Ziel-Webservers zu ersetzten. Der FQDN webserver.example.com (Option ServerName) ist ebenfalls mit dem reellen im Internet bekannten FQDN zur Website, der auf den DynDNS-Eintrags des DSL-Routers verweist, abzuändern. Namebased Websites auf dem Server (und auf gleicher IP) sollten mit der Option ServerAlias ergänzt werden. Auch hierbei sollten die im Internet aufgelösten DNS-Einträge auf den mit DynDNS aufgelösten DSL-Router zeigen.

Die Aktivierung der Konfiguration wird dann mit a2ensite site1 bewerkstelligt.

Eine entsprechende Konfiguration ist dann für alle Webserver (mit eigener IP) einzurichten, die über den Reverse Proxy aus dem Internet erreicht werden sollen.
Für einen zweiten Webserver könnte dann die Konfiguration so aussehen:

site2
<VirtualHost *:80>
    ServerName webserver2.example.com
    ServerAlias website2.example.com
 
    ProxyRequests Off
    ProxyPreserveHost On
    ProxyPass / http://192.168.0.51/
    ProxyPassReverse / http://192.168.0.51/
</VirtualHost>

Nach dem die Konfiguration dann im Apache-Server auf dem Reverse Proxy mit service apache2 reload neu eingeladen wurde, können die entsprechenden Websites bereits erreicht werden. Dabei sind weitere Websites auf anderen Servern, oder für deren FQDN hier keine Konfiguration existiert nicht über den Reverse Proxy erreichbar. Eine Website sonstwas.intern.example.com auf einem der beiden hier für den Zugriff konfigurierten Webservern wird damit nicht von außen erreicht; es greift dafür dann die Standard-Website der Apache-Installation auf dem Reverse Proxy.
Eine entsprechende Default-Konfiguration in /etc/apache2/sites-available/default könnte dabei wie folgt aussehen:

default
<VirtualHost *:80>
	ServerAdmin webmaster@example.com
 
	DocumentRoot /var/www
	<Directory /var/www/>
		Options Indexes
		AllowOverride None
		Order allow,deny
		allow from all
	</Directory>
 
	ErrorLog ${APACHE_LOG_DIR}/error.log
 
	# Possible values include: debug, info, notice, warn, error, crit,
	# alert, emerg.
	LogLevel warn
 
	CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Die HTML-Seite /var/www/index.html sollte dann ebenfalls minimal ausfallen ähnlich dem Beispiel hier:

index.html
<html>
<head>
<meta http-equiv="refresh" content="1; URL=http://www.example.com" />
</head>
<body>
<h1>No Website</h1>
<p>The website you requested is not on this server.</p>
</body></html>

Damit würde bei jedem nicht konfigurierten FQDN ein Browser nach einer Sekunde auf die Haupt-Website im Internet mit einer kurz sichtbaren Fehlermeldung weitergeleitet werden.

3 richtige IPs auf dem Ziel-Webserver

Auf dem Ziel-Webserver muss zumeist ein weiteres Modul aktiviert werden, damit auch die richtigen Client-IPs dort ausgewertet werden können. Denn sonst wird immer nur die Proxy-IP in den Logs und bei den Applikationen zu sehen sein (was beispielsweise bei PHP unter $_SERVER[REMOTE_ADDR] zu sehen ist). Im HTTP-Header kann zwar auch HTTP_X_FORWARDED_FOR dafür ausgewertet werden, doch sind selten Applikationen darauf ausgelegt.

Doch um dieses Problem recht einfach in den Griff zu bekommen, existiert für einige Webserver ein entsprechendes Modul, das den X-Forward-For Header in den Remote-Address Header schreibt.

3.1 mod_rpaf bei Apache2

Damit die Client-IPs auch beim Webserver wieder richtig erscheint (und nicht nur die IP des Reverse Proxys) muss dort (bei einem Apache-Server) ebenfalls noch etwas getan werden. Hier wird das Modul mod_rpaf benötigt, das auf einem Debian-basierenden System (Ubuntu, Raspbian u.w.) mit apt-get install libapache2-mod-rpaf installiert werden kann. Anschließend sollte in der Datei /etc/apache2/mods-available/rpaf.conf der Eintrag bei RPAFproxy_ips auf die IP des Reverse Proxys gesetzt werden. (Zumindest ist das ausreichend, wenn eh nur ein Reserve Proxy für alle Websites auf dem Webserver zuständig ist. Alternativ dazu kann man auch die ganze Konfiguration an dieser Stelle auskommentieren und innerhalb der VirtualHost-Direktive zu den einzelnen Websites einsetzen. Dadurch kann für jede Website ein (oder mehrere) eigener Reverse Proxy eingesetzt werden, oder auch bei welchen, bei denen kein entsprechendes Verfahren zum Einsatz kommen soll, auch ganz weg lassen.)

3.2 mod_extforward bei lighttpd

Ähnlich dem mod_rpaf Modul auf dem Apache kann auf einem lighttpd-Webserver das Modul mod_extforward eingesetzt werden. Das Modul selber ist bei der Basis-Installation des lighttpd auf einem Debian- oder Raspbian-System bereits mit installiert und muss nur mit einer entsprechenden Konfiguration aktiviert werden. Dabei ist unter /etc/lighttpd/conf-available/ eine Datei 20-extforward.conf wie folgt zu erstellen:

20-extforward.conf
server.modules += ( "mod_extforward" )
 
extforward.forwarder = (
	"192.168.0.40" => "trust"
)

Die IP „192.168.0.40“ steht hier nur beispielhaft für einen Reverse Proxy und sollte mit der IP eines existenten Proxys ersetzt werden. Auch können hier mehrere Proxys mit jeweils einer entsprechenden Zeile eingetragen werden; dabei aber nicht bei der vorherigen ein Komma am Ende der Zeile vergessen.

Das Modul wird dann mit lighty-enable-mod extforward aktiviert und läuft beim nächsten Starten des Dienstes mit.

3.3 HTTP RealIP Modul bei NGiNX

TODO in Vorbereitung — Verweis zumindest zur generellen Dokumentation des Moduls HttpRealipModule

4 DNS einrichten

Die Frage hier ist: Wie bewerkstellige ich, dass verschiedene (interne) Websites mit einer DynDNS-Adresse von außen richtig aufgelöst werden?
Die Antwort darauf ist eigentlich gar nicht so schwer. Man sollte sich eventuell aber ein bisschen mit der Verwaltung von DNS-Einträgen zu einer Domain auskennen.

Das Problem besteht auch darin, dass der eigentliche DSL-Provider zwar bereits einen FQDN (mit PTR) für den DSL-Router beim Verbinden zum Internet vergibt, aber dieser FQDN sich bei einem Reconnect ändert (wie auch die IP). Somit muss dem DSL-Router über einen DynDNS-Provider mit einem eindeutigen FQDN versehen werden. Mit den meisten heutigen Geräten sollte das recht einfach zu bewerkstelligen sein und der DSL-Router kann somit mit einem festen DNS-Namen von außen (also vom Internet her) unabhängig seiner externen IP (im Internet) erreicht werden.
In dieser Dokumentation wird ein DynDNS-FQDN dyndnsint.example.net auf dem DSL-Router eingerichtet.

Praktisch an der Sache ist nun, wenn alles was unterhalb des externen FQDN, der vom DynDNS-Provider kommt, ebenfalls auf diese IP weitergeleitet wird. Dies kann unter Umständen etwas Arbeit ersparen.
In diesem Beispiel heißt das nun, dass eine Anfrage für website1.dyndnsint.example.net oder sonstwas.dyndnsint.example.net genauso auf der externen IP des DSL-Routers landen, wie der eigentliche FQDN dyndnsint.example.net. Damit kann man bereits ohne weitere Aktionen seine Websites auch auf externen Seiten mit eigenen (und eindeutigen) FQDNs verlinken ohne jeweilige DNS-Einträge tätigen zu müssen.

Da dies aber nicht unbedingt immer der Fall ist, braucht man eventuell noch einen „eigenen“ DNS-Server. Hierbei kann bereits ein Hosting-Paket eines virtuellen Root-Servers (für kleines Geld, also unter 10,-€/Monat) bei einem Provider völlig ausreichen, wenn dort dann der primäre DNS zu der damit gezogenen Domain betrieben werden kann. Viele Provider bieten eine entsprechende Möglichkeit und richten ihre eigenen DNS-Server dann als sekundäre DNS für die Zone ein, oder verfahren gar nach dem Hidden DNS Prinzip.

Bei so einem eigenen Server kann man nun eigene Einträge für seine Websites hinter dem Reverse Proxy tätigen und lässt die eigentlichen FQDNs mit CNAMEs auf den FQDN des DynDNS-Providers zu dem DSL-Router zeigen.
In dieser Dokumentation hier wird auf den DynDNS-FQDN dyndnsint.example.net mit CNAMEs webserver.example.com und website1.example.com verwiesen. Diese Websites müssen entsprechend dann auch auf den eigentlichen Webservern eingerichtet sein (z.B. bei einem Apache mit der Option ServerAlias in der VirtualHost-Deklaration zur entsprechenden Website).

Das war dann eigentlich schon alles. ;-)

5 den Proxy prüfen

Ob der Reverse Proxy auch seine Arbeit richtig mach, kann mit wget oder curl recht einfach geprüft werden.

user@desktop:~$ curl -s -H "Host: website1.example.com" 192.168.0.40 | grep "<title>"
    <title>Titel einer Website auf einem named-based Webserver</title>
user@desktop:~$ wget -q -O - --header="Host: website1.example.com" 192.168.0.40 | grep "<title>"
    <title>Titel einer Website auf einem named-based Webserver</title>
user@desktop:~$

Die Angabe website1.example.com und die IP in diesem Beispiel sind nur exemplarisch und sollten natürlich mit entsprechenden real vorhandenen Angaben ersetzt werden. Dabei ist website1.example.com die anzusprechende Website auf dem Zielsystem und die IP der anzusprechende Reverse Proxy.

Um die Funktion über den DSL-Router prüfen zu können benötigt man die externe IP-Adresse des Routers, die zumeist mit der Konfigurations-Applikation zum Router abgefragt werden kann. (Auf einer FritzBox reicht es hierzu sich an dieser mit einem Browser anzumelden und sieht diese dann unter „Verbindungen“ hinter „Internet“ - in diesem Beispiel dafür wird 198.51.100.123 angenommen.)

user@desktop:~$ curl -s -H "Host: website1.example.com" 198.51.100.123 | grep "<title>"
    <title>Titel einer Website auf einem named-based Webserver</title>
user@desktop:~$ wget -q -O - --header="Host: website1.example.com" 198.51.100.123 | grep "<title>"
    <title>Titel einer Website auf einem named-based Webserver</title>
user@desktop:~$

6 Fazit

Ein Proxy dient dazu gewisse Engpässe bei einer Internet-Verbindung zu entschärfen, in dem ein Cache die Leitung entlastet. Aber auch um mehreren Clients den Zugriff in das Internet zu ermöglichen und dabei Header-Informationen so aufzubereiten, dass nach außen hin diese als ein direkt angeschlossener Rechner erscheinen (dennoch aber der Proxy eine Unterscheidung zu den Clients hin ermöglicht).

Bei einem Reverse Proxy geschieht eigentlich nichts anderes nur im umgekehrten Weg. Es ist damit möglich, mehrere interne Webserver über eine IP nach außen hin (also für das Internet) erreichbar zu machen. Dabei kann aber noch mehr mit so einem System erreicht werden.

Das hiesige Beispiel ist in erster Linie für Leute, die nur über eine DSL-Anbindung o.ä. mit nur einer IP mehrere interne Websites (über verschiedene Webserver) über das Internet erreichbar machen wollen. Gerade Webentwickler, die von zu Hause aus arbeiten und ein Preview für einen Auftrag ihrem Kunden erreichbar machen wollen (bzw. mehrere mit unterschiedlichen Anforderungen am Webserver, weswegen mehrere Webserver zum Einsatz kommen), dürfte eine solche Umgebung einen großen Nutzen bringen.

Es gibt aber noch weitere Varianten, die hier nicht dokumentiert sind, aber dennoch angesprochen werden sollen. Dabei handelt es sich um Lastverteilung in größeren Umgebungen, oder auch um Webserver auf Grund hoher Requests und mit Hilfe eines Caches zu entlasten.
Dabei gibt es dann aber noch einen weiteren Aspekt. Die meisten Applikationen / Dienste, die für einen Reverse Proxy eingesetzt werden können, beinhalten auch die Möglichkeit diverse Requests zu filtern. Mit dieser Funktion können Angriffe auf eine Web-Applikation und dessen Webserverdienstes abgefangen werden, da damit die entsprechenden Requests den eigentlichen Webserver erst gar nicht erreichen.

Für den Einsatz eines Reverse Proxy gibt es also mehrere Aspekte, die einen entsprechenden Server begründen können. In wie weit das Arbeitsaufkommen für die Konfiguration und Administration eines solchen Dienstes ausfällt, hängt jedoch von der Anforderung und der Größe der Umgebung ab. Gerade bei der Absicherung von Applikationen muss Entwicklung und Administration eng zusammen arbeiten und es kann eine recht langwierige Angelegenheit werden nur bis die benötigte Basis-Konfiguration steht. Davon abgesehen muss so eine Umgebung ständig weiter gepflegt werden.

Quellennachweise

1) DynDNS oder auch dDNS steht für dynamic DNS. Hierbei handelt es sich um einen Dienst, mit dessen Hilfe FQDNs erzeugt werden können auch wenn eine variable IP auf dem Zielsystem eingerichtet ist.
2) zum Zeitpunkt bei der Bestellung für dieses Projekt
docs/raspberrypi/prj_reverse_proxy.txt · Zuletzt geändert: 20.07.2017 - 09:52 (Externe Bearbeitung)