NGINX Reverse Proxy

Reverse Proxy Server mit NGINX

nginx Logo

Im folgenden Tutorial erkläre ich euch, wie man mit NGINX einen Reverse Proxy Server aufbaut.

Wenn einzelne Server wie beispielsweise ein GIT, Blog, WIKI und ein CMS geführter Webserver auf Basis von Docker auf demselben oder mehreren Hostservern in einem geschlossenen Netzwerk laufen, können diese Dienste über einen reverse Proxy nach außen hin erreichbar gemacht werden und dann alle unter dem Port 80 und 443 von außen angesprochen werden. Eine gesonderte URL für jeden einzelnen Dienst leitet dann die Anfrage zu dem richtigen Server weiter.

Reverse Proxys heben gleichzeitig die Sicherheit für die Zugriffe durch die Kapselung an, da die eigentlichen Zugriffe auf die einzelnen Dienste von innen heraus geschehen und gleichzeitig von außen nur der Reverse Proxy angefragt wird.

Ziel ist es, dass die einzelnen Server z.B. unter diesem Schema erreichbar sind:

  • https://meinetraumdomain.de (CMS Webserver)
  • https://meinetraumdomain.de/wiki/ (ein WIKI System)
  • https://meinetraumdomain.de/git/ (eine Versionsverwaltung)
  • https://meinetraumdomain.de/blog/ (ein Blogging System)
  • beliebig viele weitere

Konfiguration der einzelnen Server:
Jeder Server besitzt eine eigene Virtual Host (in NGINX Sprache: Server Blocks), die so aussehen könnte:

Konfigurationsdatei:
server {
  listen 80 default_server;
  listen [::]:80 default_server;
  ...
(hier kommen die server-spezifischen Konfigurationen hin, sodass sie lokal schon einmal laufen)
}

Beachtenswert ist, dass nur der Port 80 und nicht der Port 443 konfiguriert ist, da das SSL Zerifikat im einfachsten Fall lediglich für den Reverse Proxy ausgestellt sein muss, der über die Domain erreicht wird. Diese Dienste müssen zunächst auf dem Server erreichbar sein.

Ebenfalls wichtig für die Konfiguration ist es, einen individuellen Port zu vergeben, falls die Dienste auf demselben Server laufen. Das lässt sich einfach über Docker realisieren, indem der interne Port 80 auf den äußeren z.B. Port 5080 gelinkt wird.

In diesem Beispiel sieht die Porterreichbarkeit so aus:

  • CMS Webserver - Port 5080
  • Versionsverwaltung - Port 5180
  • WIKI System - Port 5280

Eine laufende Nummerierung macht das Ganze übersichtlicher. Die 80 am Ende verrät das eigentliche Ziel schnell und vermeidet Fehler bei der Konfiguration.

Das eigentlich Besondere ist die Konfiguration des Reverse Proxys selbst. Hier ist der Port 80 Bereich lediglich dafür da, eine Weiterleitung zum Port 443 zu veranlassen, der per Letsencrypt verschlüsselt ist (der Pfad well-known/acme-challenge/ ist für das Update des Schlüssels angelegt und spielt keine Rolle für den Reverse Proxy):

Konfigurationsdatei:
upstream web {
        server 192.168.0.16:5080;
}

upstream git {
        server 192.168.0.16:5180;
}

upstream wiki {
        server 192.168.0.16:5280;
}
...

Der upstream ist hier jeder einzelne Server, der eingebunden werden soll.

...
server {
    listen       80;
    server_name meinetraumdomain.de;

    location ^~ /.well-known/acme-challenge/ {
    auth_basic off;
        allow all;
        root /var/lib/letsencrypt/;
        try_files $uri =404;
        break;
    }

    # Webserver - direkter Aufruf der Domain
    location / {
        return 301 https://$host$request_uri;
    }

    location ^~ /git {
      return 301 https://$host$request_uri;
    }

    location ^~ /wiki {
      return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl http2;
    server_name meinetraumdomain.de;
    # certs sent to the client in SERVER HELLO are concatenated in ssl_certificate
    ssl_certificate /etc/letsencrypt/live/meinetraumdomain.de/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/meinetraumdomain.de/privkey.pem;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;

    # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
    ssl_dhparam /etc/nginx/ssl/dhparam.pem;

    # intermediate configuration. tweak to your needs.
    ssl_protocols TLSv1.1 TLSv1.2;
    ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
    ssl_prefer_server_ciphers on;

    # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
    add_header Strict-Transport-Security max-age=15768000;

    # OCSP Stapling ---
    # fetch OCSP records from URL in ssl_certificate and cache them
    ssl_stapling on;
    ssl_stapling_verify on;

    ## verify chain of trust of OCSP response using Root CA and Intermediate certs
    ssl_trusted_certificate /etc/letsencrypt/live/meinetraumdomain.de/fullchain.pem;

    resolver 8.8.8.8 8.8.4.4 valid=300s;

Nach den Standardeinstellungen für die Verschlüsselung kommen jetzt die einzelnen Server dran:

    location / {
      proxy_pass http://web;
      proxy_set_header Host      $host;
      proxy_set_header X-Real-IP $remote_addr;
    }

   location /git {
      rewrite ^/git(/.*)$ $1 break;
      proxy_pass http://git;
      auth_basic "Restricted";
      auth_basic_user_file /etc/nginx/.htpasswd;
    }

   location /wiki {
      rewrite ^/git(/.*)$ $1 break;
      proxy_pass http://wiki;
    }
...

}

In den Beispielen ist der proxy_pass sehr wichtig. Hier gehört jeweils genau der hinein, der ganz oben mit upstream für den Dienst definiert wurde. Beim Git-Server kann man außerdem sehen, dass er nur mit zusätzlicher Passwortabfrage (htaccess oder bei NGINX: htpasswd) erreicht werden kann und es Suchmaschinen daher auch nicht möglich ist, ihn zu indexieren.

Nach einem Reload des Proxy Servers können jetzt die einzelnen Seiten über die URLs erreicht werden und bekommen eine sichere HTTPS Verbindung.

  • https://meinetraumdomain.de
  • https://meinetraumdomain.de/git/
  • https://meinetraumdomain.de/wiki/

Mehr Infos zur Konfiguration von NGINX findet ihr hier.

Rony Schell - Trainer und Sys. Admin




Viel Spass beim ausprobieren.
Euer Rony. 


Wenn ihr Fragen habt, meldet euch: info@mobilistics.de oder folgt uns auf Twitter.