Reverse Proxy mit Raspberry 3b+, Raspian Buster, NGINX
© Dr.-Ing. Rainer Knausenberger, April 2020

Letzte Änderung: 25.10.2021

Ein Reverse Proxy ist in der Lage, mehrere Internet-Domins über 1 IP-Adresse zugänglich zu machen, wenn man diese bei sich zu Hause über den dortigen Internet-Anschluss (optimalerweise mit fester IP) betreiben will. Natürlich müssen diese Domains beim Registrar auch mit dieser IP-Adresse verknüpft sein. Der Reverse Proxy lauscht am Internet-Anschluss auf Verbindungs-Anfragen an seinem Internet-Router und kann den verlangten Domain-Namen lesen. Er steuert dann die Verbindung zum entsprechenden Web-Server.

Folgende Domains sind über den Reverse Proxy mit http (Port 80) und https (Port 443) zugänglich:

  • knausenberger.info (hierunter läuft der IceWarp Mailserver, der ein php-System unter Windows Server ist)
  • knausir.com (hier arbeitet mein File-Server u. Media-Center auf Windows Home Server 2011, der auf Windows Server 2008 R2 aufsetzt)

Alle Zugriffe mit http werden automatisch auf https umgestellt (redirect).

Zur Einrichtung und Konfiguration des Rasperry 3b muss dieser zunächst mittels eines auf SD card geladenen images (2020-02-13-raspbian-buster-lite.img) gestartet werden. Es muss auch ein Display sowie Keyboard und Maus sowie ein Netzwerkkabel angeschlossen sein. Nach dem ersten Start startet man raspi-config, um

  • das Passwort für den User ´pi´ zu ändern
  • den Hostname zu ändern (´raspi-proxy´)
  • Sprache, Land, Zeitzone, Keyboard Layout und WLAN Country zu setzen
  • SSH und ggfs. VNC zu aktivieren

Jetzt den Raspberry herunterfahren (´shutdown´), dann Netzteil abziehen, Display, Keyboard und Maus abhängen und dann mit LAN-Anschluss neu starten. Die weiteren Einstellungen und Installationen erfolgen mittels Power Shell von einem Windows-Rechner im LAN.

 

Einrichten der statischen IP-Adresse unter Raspian Buster (10):

Configure Static IP (optional). Alternatively you can also assign fixed IP address on your router.

First check the actual settings:

    ip addr show

 

   To change IP address from dhcp mode to static you need to do the following:
    - Login to raspi-proxy using these credentials:
       user: pi
       password: <your password> (originally: raspberry)

    - Open file /etc/dhcpcd.conf (use nano or vim)
      Add at the end of the file:
        interface eth0
        static ip_address=192.168.0.10/24   <- your static IP address here
        static routers=192.168.0.1  <- your default gateway here
        static domain_name_servers=192.168.0.1 8.8.8.8   <- your domain name servers (DNS) here

    Save the file using Strg-x and Y/J.
   - Reboot raspi-proxy

Die Ethernet-Schnittstelle muss nicht „eth0“ lauten, sie kann auch anders (z.B. „ens192“) benannt sein. Die vorgegebene Bezeichnung muss übernommen werden!

Damit die Kommunikation über https:// läuft, braucht man ein Zertifikat.

Die nun folgenden Schritte habe ich von der Internet-Seite https://linuxize.com/post/secure-nginx-with-let-s-encrypt-on-debian-10/ übernommen:

- Begin of take over from linuxize.com –

This tutorial shows how to install a free Let’s Encrypt SSL certificate on Debian 10, Buster running Nginx as a web server and Reverse Proxy. We’ll also show how to configure Nginx to use the SSL certificate and enable HTTP/2.

Prerequisites

Ensure the following prerequisites are met before proceeding with the guide:

  • Logged in as root or user with sudo privileges.
  • The domain for which you want to obtain the SSL certificate must point to your public server IP. We’ll use com.
  • Nginx installed. (Installation directions you get by pointing with mouse over to beginning of this line and then pressing [Strg]+[Left mouse button].

Installing Certbot

We’ll use the certbot tool to obtain and renew the certificates.

Certbot is a fully-featured and easy to use tool that automates the tasks for obtaining and renewing Let’s Encrypt SSL certificates and configuring web servers to use the certificates.

The certbot package is included in the default Debian repositories. Run the following commands to install certbot:

sudo apt updatesudo apt install certbot

Generating DH (Diffie-Hellman) Group

Diffie–Hellman key exchange (DH) is a method of securely exchanging cryptographic keys over an unsecured communication channel.

We’re going to generate a new set of 2048 bit DH parameters to strengthen the security:

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

You can also change the size up to 4096 bits, but the generation may take more than 30 minutes depending on the system entropy.

Obtaining a Let’s Encrypt SSL certificate

To obtain an SSL certificate for the domain, we’re going to use the Webroot plugin. It works by creating a temporary file for validating the requested domain in the ${webroot-path}/.well-known/acme-challenge directory. The Let’s Encrypt server makes HTTP requests to the temporary file to validate that the requested domain resolves to the server where certbot runs.

We’re going to map all HTTP requests for .well-known/acme-challenge to a single directory, /var/lib/letsencrypt.

Run the following commands to create the directory and make it writable for the Nginx server:

sudo mkdir -p /var/lib/letsencrypt/.well-knownsudo chgrp www-data /var/lib/letsencryptsudo chmod g+s /var/lib/letsencrypt

To avoid duplicating code, we’ll create two snippets that will be included in all Nginx server block files.

Open your text editor and create the first snippet, letsencrypt.conf:

sudo nano /etc/nginx/snippets/letsencrypt.conf

/etc/nginx/snippets/letsencrypt.conf

location ^~ /.well-known/acme-challenge/ {  allow all;  root /var/lib/letsencrypt/;  default_type "text/plain";  try_files $uri =404;}

The second snippet ssl.conf includes the ciphers recommended by Mozilla, enables OCSP Stapling, HTTP Strict Transport Security (HSTS), and enforces few security‑focused HTTP headers.

sudo nano /etc/nginx/snippets/ssl.conf

/etc/nginx/snippets/ssl.conf

ssl_dhparam /etc/ssl/certs/dhparam.pem;

 

ssl_session_timeout 1d;

ssl_session_cache shared:SSL:10m;

ssl_session_tickets off;

 

ssl_protocols TLSv1.2 TLSv1.3;

ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;

ssl_prefer_server_ciphers off;

 

ssl_stapling on;

ssl_stapling_verify on;

resolver 8.8.8.8 8.8.4.4 valid=300s;

resolver_timeout 30s;

 

add_header Strict-Transport-Security "max-age=63072000" always;

add_header X-Frame-Options SAMEORIGIN;

add_header X-Content-Type-Options nosniff;

Once done, open the domain server block file and include the letsencrypt.conf snippet as shown below:

sudo nano /etc/nginx/sites-available/example.com.conf

/etc/nginx/sites-available/example.com.conf

serverlisten 80;  server_name example.com www.example.com;   include snippets/letsencrypt.conf;}

Create a symbolic link to the sites-enabled directory to enable the domain server block:

sudo ln -s /etc/nginx/sites-available/example.com.conf /etc/nginx/sites-enabled/

Restart the Nginx service for the changes to take effect:

sudo systemctl restart nginx

You’re now ready to obtain the SSL certificate files by running the following command:

sudo certbot certonly --agree-tos --email Diese E-Mail-Adresse ist vor Spambots geschützt! Zur Anzeige muss JavaScript eingeschaltet sein! --webroot -w /var/lib/letsencrypt/ -d example.com -d www.example.com

If the SSL certificate is successfully obtained, the following message will be printed on your terminal:

IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at:   /etc/letsencrypt/live/example.com/fullchain.pem   Your key file has been saved at:   /etc/letsencrypt/live/example.com/privkey.pem   Your cert will expire on 2020-02-22. To obtain a new or tweaked   version of this certificate in the future, simply run certbot   again. To non-interactively renew *all* of your certificates, run   "certbot renew" - If you like Certbot, please consider supporting our work by:    Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate   Donating to EFF:                    https://eff.org/donate-le

Edit the domain server block and include the SSL certificate files as follows:

sudo nano /etc/nginx/sites-available/example.com.conf

/etc/nginx/sites-available/example.com.conf

server {    listen 80;    server_name www.example.com example.com;     include snippets/letsencrypt.conf;    return 301 https://$host$request_uri;} server {    listen 443 ssl http2;    server_name www.example.com;     ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;    ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;    include snippets/ssl.conf;    include snippets/letsencrypt.conf;     return 301 https://example.com$request_uri;} server {    listen 443 ssl http2;    server_name example.com;     ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;    ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;    include snippets/ssl.conf;    include snippets/letsencrypt.conf;     # . . . other code}

The configuration above tells Nginx to redirect from HTTP to HTTPS and from www to non-www version.

Restart or reload the Nginx service for the changes to take effect:

sudo systemctl restart nginx

Open your website using https://, and you’ll notice a green lock icon.

If you test your domain using the SSL Labs Server Test, you’ll get an A+ grade.

The next 2 lines are added by me.
Now repeat this for every domain (example2.com, example3.com …) you wish to run behind Reverse Proxy.

Auto-renewing Let’s Encrypt SSL certificate

Let’s Encrypt’s certificates are valid for 90 days. To automatically renew the certificates before they expire, the certbot package creates a cronjob that runs twice a day and automatically renews any certificate 30 days before its expiration.

On renewal the nginx service must be reloaded for the server to load the certificate. Append --renew-hook "systemctl reload nginx" to the /etc/cron.d/certbot file so as it looks like this:

sudo nano /etc/cron.d/certbot

/etc/cron.d/certbot

0 */12 * * * root test -x /usr/bin/certbot -a \! -d /run/systemd/system && perl -e 'sleep int(rand(3600))' && certbot -q renew --renew-hook "systemctl reload nginx"

Test the automatic renewal process, by running this command:

sudo certbot renew --dry-run

If there are no errors, it means that the renewal process was successful.

Conclusion

Having an SSL certificate is a must nowadays. It secures your website, increases SERP ranking position, and allows you to enable HTTP/2 on your web server.

- End of take over from linuxize.com -

Result of the „dry-run“:

You can see, every domain´s certificates defined in /etc/nginx/sites-enabled/ are renewed.

If the dry run shows up with error, then you must create a new certificate using (in my case):

 


 

 

Dealing with Windows Server certificates on Reverse Proxy

Microsoft Windows Server uses built-in certificates for SSL and inside domain controller in pfx-format. This certificate has to be copied to Reverse Proxy and then to be made useful for NGINX. First you have to open the IIS Manager:

Open „Server Certificates“.

Select the domain certificate (knausir.homeserver.com).
Click on „Export…“. Define the path and password. I put it in C:\Users\Rainer\Desktop\Homeserver_CA\.
Open https://www.sslshopper.com/ssl-converter.html 

Click on „Durchsuchen“ and point to the homeserver’s .pfx-file. Select the format of the homeserver certificate (PFX) and the format to convert to (PEM). Also enter the password defined during export on IIS and then click on „Convert Certificate“. Store the file in the same folder as the .pfx. file.

Using notepad or editor you now devide this .PEM file into 2 separate files „fullchain.pem“ and „privkey.pem“.

 

 

The content of fullchain.pem looks like:

and the content of privkey.pem looks like

These 2 files you now copy to the folder /etc/homeserver/ on the Reverse Proxy using WinSCP.

 

Because of the long validity (15 months) actualization of the certificate copies on Reverse Proxy is seldom needed. Therefore you should make a printed copy of this document and carefully safe it.


 

The Scripts on my Reverse Proxy:

/etc/nginx/sites-available/default

                               (not linked to /sites-enabled/ !)

# Default server configuration

#

server {

                     listen 80 default_server;

                     listen [::]:80 default_server;

 

                     root /var/www/html;

                     index index.html index.htm index.nginx-debian.html;

 

                     server_name _;

 

                     location / {

                                           # First attempt to serve request as file, then

                                           # as directory, then fall back to displaying a 404.

                                           try_files $uri $uri/ =404;

                     }

}

 

Content of file: index.nginx-debian.html

 

<!DOCTYPE html>

<html>

<head>

<title>Welcome to nginx!</title>

<style>

    body {

        width: 35em;

        margin: 0 auto;

        font-family: Tahoma, Verdana, Arial, sans-serif;

    }

</style>

</head>

<body>

<h1>Welcome to nginx!</h1>

<p>If you see this page, the nginx web server is successfully installed and

working. Further configuration is required.</p>

 

<p>For online documentation and support please refer to

<a href="http://nginx.org/">nginx.org</a>.<br/>

Commercial support is available at

<a href="http://nginx.com/">nginx.com</a>.</p>

 

<p><em>Thank you for using nginx.</em></p>

</body>

</html>

 

 

 

/etc/nginx/sites-available/knausenberger.info.conf

 

# Configuration for knausenberger.info and www.knausenberger.info

server {

  listen 80;

  server_name knausenberger.info www.knausenberger.info;

 

  include snippets/letsencrypt.conf;

  return 301 https://$host$request_uri;

}

 

server {

  listen 443 ssl http2;

  server_name www.knausenberger.info;

 

  ssl_certificate /etc/letsencrypt/live/knausenberger.info/fullchain.pem;

  ssl_certificate_key /etc/letsencrypt/live/knausenberger.info/privkey.pem;

  ssl_trusted_certificate /etc/letsencrypt/live/knausenberger.info/chain.pem;

  include snippets/ssl.conf;

  include snippets/letsencrypt.conf;

 

  return 301 https://knausenberger.info$request_uri;

}

 

server {

  listen 443 ssl http2;

  server_name knausenberger.info;

 

  ssl_certificate /etc/letsencrypt/live/knausenberger.info/fullchain.pem;

  ssl_certificate_key /etc/letsencrypt/live/knausenberger.info/privkey.pem;

  ssl_trusted_certificate /etc/letsencrypt/live/knausenberger.info/chain.pem;

  include snippets/ssl.conf;

  include snippets/letsencrypt.conf;

 

  # . . . other code

  location / {

    include proxy_params;

    proxy_pass https://10.163.54.30;

  }

}

 

 

/etc/nginx/sites-available/knausir.com.conf

 

# Configuration for knausir.com and www.knausir.com

server {

  listen 80;

  server_name knausir.com www.knausir.com;

 

  include snippets/letsencrypt.conf;

  return 301 https://$host$request_uri;

}

 

server {

  listen 443 ssl http2;

  server_name www.knausir.com;

 

  ssl_certificate /etc/letsencrypt/live/knausir.com/fullchain.pem;

  ssl_certificate_key /etc/letsencrypt/live/knausir.com/privkey.pem;

  ssl_trusted_certificate /etc/letsencrypt/live/knausir.com/chain.pem;

  include snippets/ssl.conf;

  include snippets/letsencrypt.conf;

 

  return 301 https://knausir.com$request_uri;

}

 

server {

  listen 443 ssl http2;

  server_name knausir.com;

 

  ssl_certificate /etc/letsencrypt/live/knausir.com/fullchain.pem;

  ssl_certificate_key /etc/letsencrypt/live/knausir.com/privkey.pem;

  ssl_trusted_certificate /etc/letsencrypt/live/knausir.com/chain.pem;

  include snippets/ssl.conf;

  include snippets/letsencrypt.conf;

 

  # . . . other code

  location / {

    proxy_buffering off;

    include proxy_params;

    proxy_pass https://10.163.54.2;

  }

}

 

 

/etc/nginx/sites-available/knausir.homeserver.com.conf

# Configuration for knausir.homeserver.com

server {

  listen 80;

  server_name knausir.homeserver.com www.knausir.homeserver.com;

 

#    include snippets/letsencrypt.conf;

  return 301 https://$host$request_uri;

}

 

server {

  listen 443 ssl http2;

  server_name www.knausir.homeserver.com;

 

  ssl_certificate /etc/homeserver/fullchain.pem;

  ssl_certificate_key /etc/homeserver/privkey.pem;

#    ssl_trusted_certificate /etc/homeserver/chain.pem;

#    include snippets/ssl.conf;

#    include snippets/letsencrypt.conf;

 

  return 301 https://knausir.homeserver.com$request_uri;

}

 

server {

  listen 443 ssl http2;

  server_name knausir.homeserver.com;

 

  ssl_certificate /etc/homeserver/fullchain.pem;

  ssl_certificate_key /etc/homeserver/privkey.pem;

#    ssl_trusted_certificate /etc/homeserver/chain.pem;

#    include snippets/ssl.conf;

#    include snippets/letsencrypt.conf;

 

  # . . . other code

  location / {

    include proxy_params;

    proxy_pass https://10.163.54.2;

  }

}

 

Sicherheitshalber legen wir jetzt noch Links für diese Scripts in /etc/nginx/sites-enabled/ an, damit sie in nginx auch gestartet werden

sudo ln -s /etc/nginx/sites-available/knausenberger.info.conf /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/knausir.com.conf /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/knausir.homeserver.com.conf /etc/nginx/sites-enabled/

sudo systemctl restart nginx.service

 

Mit diesen Scripts, dem konvertierten Windows Server Zertifikat und den zugehörigen Let’s Encrypt-Zertifikaten meldet das System reibungslose Funktionalität.