Apache Reverse Proxy konfigurieren

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 Proxypi1“ 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

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.

<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

Schreibe einen Kommentar

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

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.