Was macht ein Reverse Proxy? (Klick)
Ein Reverse Proxy nimmt eingehende Anfragen von Clients (z. B. Webbrowser) entgegen und leitet diese Anfragen dann an einen oder mehrere interne Server weiter. Ein Reverse Proxy ist auch hilfreich, wenn man hinter einem Internetanschluss mehrere Server betreiben möchte.
Der Webserver fungiert dabei als eine Art “Vermittler” zwischen den Clients und den Servern im Hintergrund. Der Client „merkt“ dabei nicht, dass die Anfrage im Hintergrund durch einen anderen Server erledigt wird.
Ein Reverse Proxy versteckt die internen Server vor direkten Zugriffen von außen, was ein zusätzliches Sicherheitsniveau schafft.
Anzeige
Direktlinks: Allgemein | Reverse Proxy | Backend-Server | Client-Zertifikate
Allgemein
Die Einrichtung eines Reverse Proxy ist im besten Fall einfach. HTTPS-Verbindungen weiterreichen, das Verteilen von Unterordnern einer Domain oder sogar einer ganzen Domain bzw. Subdomain auf andere Backend-Server hinter dem Reverse Proxy sind schnell umgesetzt.
Beim korrekten Logging der Client-IP oder dem Durchreichen von Client-Zertifikaten an den Backend-Server wird es dann auch schon etwas schwieriger. Ich möchte versuchen diese Schritte anhand der folgenden Anleitung für jeden umsetzbar zu machen.
Um einen Reverse Proxy zu konfigurieren, werden mindestens zwei Server (bspw. Raspberry Pi) benötigt auf denen jeweils ein Webserver läuft. Im Falle dieser Anleitung wird als Webserver der Apache eingesetzt.
Wird ein Raspberry Pi als Reverse Proxy verwendet, sollte es mindestens ein 4er sein. 4 GB RAM reichen aus, um auch bei Bedarf Funktionalitäten wie Caching oder Load Balancing nutzen zu können. Sollen auf dem Reverse Proxy zusätzlich ebenfalls Webseiten oder andere Dienste laufen, empfehle ich 8 GB RAM.
In dieser Anleitung werde ich den Server mit Reverse Proxy „pi1“ und den dahinter liegenden Backend-Server „pi2“ nennen.
Konfiguration auf pi1 (Reverse Proxy)
Folgende Apache-Module müssen auf pi1 aktiviert werden:
sudo a2enmod proxy sudo a2enmod proxy_http sudo a2enmod ssl sudo systemctl restart apache2
Öffne für die Konfiguration des Reverse Proxy die Konfigurationsdatei deiner jeweiligen Domain:
sudo nano /etc/apache2/sites-available/domain1.conf
Weiterleitung von Unterordnern
Folgendes muss in deiner Konfigurationsdatei ergänzt werden:
# Anfragen von www.domain1.tld/unterordner1 an pi2 weiterleiten ProxyPreserveHost On SSLEngine on SSLProxyEngine On ProxyPass /unterordner1 http://192.168.0.2/unterordner1 ProxyPassReverse /unterordner1 http://192.168.0.2/unterordner1
Du kannst innerhalb einer Konfigurationsdatei auch mehrere Weiterleitungen bspw. zu unterschiedlichen Backend-Servern angeben:
ProxyPreserveHost On SSLEngine on SSLProxyEngine On # Anfragen von www.domain1.tld/unterordner2 an pi2 weiterleiten ProxyPass /unterordner2 http://192.168.0.2/unterordner2 ProxyPassReverse /unterordner2 http://192.168.0.2/unterordner2 # Anfragen von www.domain1.tld/unterordner3 an pi3 weiterleiten ProxyPass /unterordner3 http://192.168.0.3/unterordner3 ProxyPassReverse /unterordner3 http://192.168.0.3/unterordner3
Anzeige
Damit die IP-Adresse des Clients und nicht die des Reverse Proxy bspw. für das Logging an die Backend-Server übergeben wird, muss folgendes ebenfalls in der Konfigurationsdatei hinterlegt werden:
# Weitergabe der Original-IP SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}e" env=forwarded
Damit dies auf den Backend-Servern verarbeitet werden kann, ist noch eine Anpassung an dessen Konfiguration notwendig.
Wie gewohnt, kannst du auch direkt auf dem Reverse Proxy Webseiten hosten:
# Lokale Webseite auf pi1 unter /unterordner1 bereitstellen DocumentRoot /var/www/html/unterordner1 <Directory /var/www/html/unterordner1> AllowOverride All Options -Indexes </Directory>
Die Datei per STRG+O speichern und per STRG+X schließen.
Im Ganzen könnte deine Konfigurationsdatei wie folgt aussehen:
<VirtualHost *:443> ServerName www.domain1.tld ServerAlias www.domain1.tld SSLEngine on SSLProxyEngine On SSLCertificateFile /etc/letsencrypt/live/domain1.tld/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/domain1.tld/privkey.pem Include /etc/letsencrypt/options-ssl-apache.conf ProxyPreserveHost On # Anfragen von www.domain1.tld/unterordner2 an pi2 weiterleiten ProxyPass /unterordner2 http://192.168.0.2/unterordner2 ProxyPassReverse /unterordner2 http://192.168.0.2/unterordner2 # Anfragen von www.domain1.tld/unterordner3 an pi3 weiterleiten ProxyPass /unterordner3 http://192.168.0.3/unterordner3 ProxyPassReverse /unterordner3 http://192.168.0.3/unterordner3 # Weitergabe der Original-IP SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}e" env=forwarded # Lokale Webseite auf pi1 unter /unterordner1 bereitstellen DocumentRoot /var/www/html/unterordner1 <Directory /var/www/html/unterordner1> AllowOverride All Options -Indexes </Directory> # Logging ErrorLog ${APACHE_LOG_DIR}/domain1.tld_error.log CustomLog ${APACHE_LOG_DIR}/domain1.tld_access.log combined </VirtualHost>
Das Ganze funktioniert natürlich auch für ganze Domains, bzw. Subdomains, wobei eine Konfiguration so aussehen kann:
# Weiterleitung für eine Domain <VirtualHost *:443> ServerName domain1.tld ServerAlias domain1.tld SSLEngine on SSLProxyEngine On SSLCertificateFile /etc/letsencrypt/live/domain1.tld/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/domain1.tld/privkey.pem Include /etc/letsencrypt/options-ssl-apache.conf ProxyPreserveHost On # Anfragen von (Sub)domain domain1.tld an pi2 weiterleiten ProxyPass / http://192.168.0.2/ ProxyPassReverse / http://192.168.0.2/ # Weitergabe der Original-IP SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}e" env=forwarded # Logging ErrorLog ${APACHE_LOG_DIR}/domain1.tld_error.log CustomLog ${APACHE_LOG_DIR}/domain1.tld_access.log combined </VirtualHost> # Weiterleitung für eine Subdomain <VirtualHost *:443> ServerName subdomain1.domain1.tld ServerAlias subdomain1.domain1.tld SSLEngine on SSLProxyEngine On SSLCertificateFile /etc/letsencrypt/live/subdomain1.domain1.tld/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/subdomain1.domain1.tld/privkey.pem Include /etc/letsencrypt/options-ssl-apache.conf ProxyPreserveHost On # Anfragen von Subdomain subdomain1.domain1.tld an pi2 weiterleiten ProxyPass / http://192.168.0.2/ ProxyPassReverse / http://192.168.0.2/ # Weitergabe der Original-IP SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}e" env=forwarded # Logging ErrorLog ${APACHE_LOG_DIR}/subdomain1.domain1.tld_error.log CustomLog ${APACHE_LOG_DIR}/subdomain1.domain1.tld_access.log combined </VirtualHost>
SSL-Zertifikat für die Verwendung von HTTPS-Verbindungen
Wenn du für deine Domain(s) SSL-Zertifikate für HTTPS-Verbindungen nutzt, ist es wichtig, dass die SSL-Zertifikate sowohl auf dem Reverse Proxy (pi1) und auf dem Backend-Server (pi2) installiert sind. Dies erhöht die Sicherheit, da dann auch die Kommunikation zwischen pi1 und pi2 im internen Netz verschlüsselt wird und ist notwendig, wenn du auch mit Client-Zertifikaten arbeitest.
Wie du SSL-Zertifikate mit Hilfe von certbot erstellen kannst, ist bei ubuntuusers.de beschrieben.
Anzeige
Konfiguration auf pi2 (Backend-Server)
Die Konfiguration des Backend-Servers entspricht genau der eines regulären Servers. Bspw. anhand von virtuellen Hosts.
SSL-Zertifikate sollten auch auf dem Backend-Server für die jeweilige (Sub)-Domain eingebunden sein.
Sicherheit: Für Webseiten und Dienste, die vom Reverse Proxy an den Backend-Server weitergeleitet werden, solltest du sicherstellen, dass auch nur der Reverse Proxy Anfragen an den Backend-Server stellen kann.
Neben der Konfiguration innerhalb einer eingesetzen Firewall, geht dass auch anhand der „Require ip“-Direktive:
<Directory /var/www/html/> AllowOverride All Options -Indexes Require ip 192.168.0.1 # IP des Reverse Proxy </Directory>
Client-IP auf Backend-Server verarbeiten
Damit die IP des Clients, dessen Anfragen über den Reverse Proxy an den Backend-Server weiterleitet werden, vom Backend-Server bspw. für das Logging verarbeitet werden können, muss auf dem Backend-Server das folgende Modul aktiviert werden:
sudo a2enmod remoteip
Öffne nun die Apache-Konfigurationsdatei:
sudo nano /etc/apache2/apache2.conf
Füge hier die folgenden Zeilen hinzu:
# RemoteIP-Konfiguration RemoteIPHeader X-Forwarded-For RemoteIPTrustedProxy 192.168.0.1 # IP des Reverse Proxy, Zugriff auf Dienste nur von Reverse Proxy aus
RemoteIPHeader sorgt dafür, dass die vom Reverse Proxy übermittelte Client-IP abgefragt wird und als tatsächliche IP-Adresse in X-Forwarded-For auf dem Backend-Server verwendet wird.
RemoteIPTrustedProxy wird mit der lokalen IP-Adresse des Reverse Proxy beschrieben. Das stellt sicher, dass nur der ReverseProxy und sonst keiner die Möglichkeit hat die IP-Adresse zu überschreiben.
Die Datei per STRG+O speichern und per STRG+X schließen und den Webserver neustarten:
sudo systemctl restart apache2
Client-Zertifikate auf dem Backend-Server verwenden
Der Apache-Webserver kann Client-Zertifikate nicht vom Reverse Proxy an den Backend-Server „durchschleifen“, sodass eine Überprüfung des Client-Zertifikats auf dem Backend-Server nicht direkt möglich ist.
Um die Überprüfung von Client-Zertifikaten auf dem Backend-Server zu gewährleisten und damit Zugriffe auf entsprechend geschützte Instanzen abzusichern, müssen die entsprechenden Informationen per Header mitgegeben werden.
Auf dem Reverse Proxy muss die Konfiguration zur Weitergabe von Client-Zertifikaten bspw. wie folgt aussehen:
# Client-Zertifikatsprüfung auf dem Reverse Proxy pi1 SSLCACertificateFile /ca_path/int/certs/ca-chain.cert.pem SSLCARevocationFile /ca_path/int/crl/intermediate.crl.pem #SSLCARevocationCheck chain no_crl_for_cert_ok SSLVerifyClient require SSLVerifyDepth 2 # Tiefe ist je nach eigener Zertifikatskette anzupassen SSLOptions +StrictRequire +StdEnvVars # Weiterleiten der Client-Zertifikatsinformationen an pi2 RequestHeader set X-SSL_CLIENT_S_DN_O "%{SSL_CLIENT_S_DN_O}e" RequestHeader set X-SSL_CLIENT_S_DN_OU "%{SSL_CLIENT_S_DN_OU}e" RequestHeader set X-SSL_CLIENT_I_DN_O "%{SSL_CLIENT_I_DN_O}e" RequestHeader set X-SSL_CLIENT_VERIFY "%{SSL_CLIENT_VERIFY}e"
Auf dem Backend-Server müssen die übergebenen Informationen ausgwertet und gegengeprüft werden:
<Directory /var/www/html/> AllowOverride All Options -Indexes Require ip 192.168.0.1 # IP des Reverse Proxy, Zugriff auf Dienste nur von Reverse Proxy aus <RequireAll> # Require ssl-verify-client -> wird an dieser Stelle nicht benötigt, da die eigentliche # Prüfung bereits auf dem Reverse Proxy stattfand. # Überprüfung der über die Header übergebenen Zertifikatsinformationen Require expr ( %{HTTP:X-SSL_CLIENT_I_DN_O} == "CA" \ && %{HTTP:X-SSL_CLIENT_S_DN_O} == "FIRMA" \ && %{HTTP:X-SSL_CLIENT_S_DN_OU} in {"ABTEILUNG", "ABTEILUNG2"} \ && %{HTTP:X-SSL_CLIENT_VERIFY} == "SUCCESS" ) </RequireAll> </Directory>
Anzeige