NGINX Training Dezember 2019

1 Virtuelle Maschinen

Domain-Name IPv4 IPv6 Teilnehmer
nginx01 136.244.101.93 2001:19f0:5001:27c6:5400:02ff:fe72:b997 Lars
nginx02 136.244.100.207 2001:19f0:5001:2139:5400:02ff:fe72:b998 Jan
nginx03 136.244.104.40 2a05:f480:1400:3cb:5400:02ff:fe72:b999 Morten
nginx04 78.141.216.5 2001:19f0:5001:2c6:5400:02ff:fe72:b99a Rupert
nginx05 95.179.179.95 2a05:f480:1400:735:5400:02ff:fe72:b99b Ali
nginx06 136.244.109.178 2001:19f0:5001:32b6:5400:02ff:fe72:b99c Carsten

2 TMUX Installieren

dnf install tmux
  • TMUX Befehle
Aktion Tastaturkombination
Neues Terminal CTRL+B C
nächstes Terminal CTRL+B N
voheriges Terminal CTRL+B P
Screen Nr. x [0…9] CTRL+B 4
Terminal horizontal teilen CTRL+B "
Terminal vertikal teilen CTRL+B %
zwischen geteilten Terminals wechseln CTRL+B <cursor>
zwischen geteilten Terminals wechseln CTRL+B O
Größe ändern CTRL+B CTRL+<cursor>
Zoomen CTRL+B z
Terminal schliessen CTRL+B x
Tmux abhängen (detach) CTRL+B d
Grafisch Fenster wechseln CTRL+B w
Grafisch Sitzung wechseln CTRL+B s
Scroll-Modus (abbrechen mit CTRL+C) CTRL+[
Tmux anhängen tmux attach
Tmux Kommandozeile CTRL+B :
Tastenkommandos in alle Fenster (Kommandozeile) set synchronize-panes

3 HTTP 0.9, 1.0, 1.1, h2

3.1 1991 - HTTP/0.9

  • nur GET
# nc nginx.defaultroutes.de 80
get /

3.2 1996 - HTTP/1.0

  • RFC 1945
  • HEAD und POST Anfragen
  • HTTP Versionsnummer in der Anfrage
  • HTTP Header
  • Mime-Types für Dateiformate
  • Response-Codes
    # nc nginx.defaultroutes.de 80
    GET / HTTP/1.0
    Accept: text/html,application/xhtml+xml,image/jxr/,*/*
    
    

3.3 1997/1999/2004 - HTTP/1.1

# nc nginx.defaultroutes.de 80
GET / HTTP/1.1
Host: nginx.deafultroutes.de
Accept: text/html,application/xhtml+xml,image/jxr/,*/*

3.4 2015 - HTTP/2 (h2)

  • RFC 7540
  • basierend auf SPDY von Google
  • binäres Protokoll
  • asynchrone Streams
  • nur mit TLS implementiert, Protokollauswahl im TLS Handshake
  • Server Push und Server Hint
  • Header Compression (HPACK)

3.5 ?? - HTTP/3 (h3)

  • Neues HTTP Protokoll, ursprünglich HTTP-over-QUIC
  • UDP basiert
  • TLS Transportverschlüsselung (TLS 1.3+) eingebaut
  • wird schon bei Google eingesetzt (google.com und youtube.com)
  • Chrome und Firefox unterstützen h3
  • Internet Draft: https://quicwg.org/base-drafts/draft-ietf-quic-http.html

4 Installation NGINX unter Linux mittels Paketmanager

  • Unter CentOS 8 installieren wir NGINX über den Paketmanager:
dnf install nginx
  • Dieser Befehl installiert NGINX sowie alle in CentOS 8 verfügbaren NGINX Module. Wir werden die Module in einem späteren Kapitel betrachten
  • Die Standard-Konfigurationsdatei von NGINX, so wie sie bei CentOS 8 (aber auch bei anderen Unix/Linux Distributionen) mitgeliefert wird, ist schon recht komplex und kann zum Anfang den Blick auf die wesendlichen Bestandteile verstellen
  • wir sichern daher die original Konfigurationsdateien und starten frisch mit einer einfachen Konfiguration:
mv /etc/nginx /etc/nginx.original
mkdir /etc/nginx
$EDITOR /etc/nginx/nginx.conf
  • eine simple NGINX Konfigurationsdatei
user nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log warn;
pid        /run/nginx.pid;

events {
  worker_connections  1024;
}

http {
   server {
          listen       80;
          server_name  nginx0X.defaultroutes.de;

	  access_log /var/log/nginx/site1_access.log;
          root   /srv/nginx/site1/html;

          location / {
                   index  index.html index.htm;
          }
   }
}
  • Test der Konfiguration
# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
  • das Verzeichnis fürr die Webseiten anlegen
mkdir -p /srv/nginx/site1/html
  • eine einfache HTML-Seite erstellen
$EDITOR /srv/nginx/site1/html/index.html
  • Inhalt der NGINX Seite
<HMTL>
 <BODY>
  <H1>Willkommen auf dem NGINX Webserver des Linuxhotel NGINX Kurses</H1>
 </BODY>
<HTML>
  • Unix Dateisystem-Rechte anpassen
chown -R nginx:nginx /srv/nginx/site1/html
  • SELinux Context-Label anpassen
semanage fcontext -a -t httpd_sys_content_t /srv/nginx/site1/html/index.html
restorecon -v /srv/nginx/site1/html/index.html
  • Port 80 in der Firewall freischalten
firewall-cmd --zone=public --add-service=http --permanent
firewall-cmd --reload
  • NGINX unter CentOS 8 aktivieren und starten
systemctl enable --now nginx
  • NGINX Status prüfen
  # systemctl status nginx
● nginx.service - The nginx HTTP and reverse proxy server
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
   Active: active (running) since Mon 2019-11-25 08:58:23 UTC; 5s ago
  Process: 22684 ExecStart=/usr/sbin/nginx (code=exited, status=0/SUCCESS)
  Process: 22682 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=0/SUCCESS)
  Process: 22681 ExecStartPre=/usr/bin/rm -f /run/nginx.pid (code=exited, status=0/SUCCESS)
 Main PID: 22686 (nginx)
    Tasks: 2 (limit: 5092)
   Memory: 2.1M
   CGroup: /system.slice/nginx.service
           ├─22686 nginx: master process /usr/sbin/nginx
           └─22687 nginx: worker process

Nov 25 08:58:22 nginx-training systemd[1]: Starting The nginx HTTP and reverse proxy server...
Nov 25 08:58:22 nginx-training nginx[22682]: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
Nov 25 08:58:22 nginx-training nginx[22682]: nginx: configuration file /etc/nginx/nginx.conf test is successful
Nov 25 08:58:22 nginx-training systemd[1]: nginx.service: Failed to parse PID from file /run/nginx.pid: Invalid argument
Nov 25 08:58:23 nginx-training systemd[1]: Started The nginx HTTP and reverse proxy server.

4.1 NGINX Konfiguration testen und neu laden

  • Nach einer Änderung der NGINX Konfiguration muss diese Konfiguration neu geladen werden
  • vor dem neu Laden des Konfiguration sollte immer geprüft werden, ob die Konfiguration vom NGINX geladen werden kann
  • der Aufruf nginx -t testet die Konfigurationsdatei. Mit dem optionalen Parameter -c <datei> kann eine Konfigurationsdatei angegeben werden
# nginx -t -c /etc/nginx/nginx.conf
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
  • war der Test der Konfiguration erfolgreich, kann die neue Konfiguration mit nginx -s reload in den NGINX Webserver geladen werden. Ein stoppen und neu starten des NGINX Dienstes ist nicht erforderlich.

4.2 Events

  • NGINX skaliert sehr gut über die bestehenden Hardware-Ressourcen
  • die Direktive worker_connections innerhalb eines events Block beschränkt die Anzahl der gleichzeitigen Netzwerk-Verbindungen zum NGINX-Server.
  • bei einem Server mit sehr vielen Anfragen sollte dieser Wert für die Hardware in einem Test ermittelt werden
  • die wirkliche Anzahl von Verbindungen kann über den stub_status (Kapitel Monitoring) überwacht werden. Wenn die von stub_status gemeldete Anzahl gleicher Verbindungen die in diesem Parameter eingestellten Wert erreicht, so sollte der Wert erhöht werden. Dabei sollte die Systemlast und die Antwortgeschwindigkeit des Servers überwacht werden
  • Der Standard-Wert ist 512, für moderne Hardware ist 1024 ein guter Startwert
events {
    worker_connections  1024;
}

4.3 MIME-Types

  • MIME = Multipurpose Internet Mail Extensions
  • seit HTTP/1.0 sendet ein Webserver zu jedem Dokument ein Content-Type Header, welcher dem Web-Browser eine Information gibt, wie die Daten darzustellen sind
  • eine ggf. vorhandene Datei-Endung wird von Browsers nicht beachtet
  • NGINX muss jedoch wissen, welcher MIME-Type für Dokumente ausgeliefert werden soll. Diese Zuordnung auf der Seite des Webservers geschied durch die Datei-Endungen
  • Beispiel einer MIME-Type Definition für NGINX
types {
    text/html                                        html htm shtml;
    text/css                                         css;
    text/xml                                         xml;
    image/gif                                        gif;
    image/jpeg                                       jpeg jpg;
    application/javascript                           js;
    application/atom+xml                             atom;
    application/rss+xml                              rss;
}
  • NGINX unter CentOS bringt eine Konfigurationsdatei mit den gängigen MIME-Typen mit. Diese Konfigurationsdatei mit dem Namen mime.types kann im http Block per include in die NGINX-Konfiguration aufgenommen werden
include             /etc/nginx/mime.types;
  • die Direktive default_type definiert den MIME-Type, welcher von NGINX gesetzt wird, wenn keine Zuordnung zu einer Datei-Endung gefunden wurde
default_type        application/octet-stream;

4.3.1 Aufgabe MIME-Types

  • kopiere die Datei mime.types aus den gesicherten Original-Konfigurationsverzeichnis des NGINX in das aktuelle NGINX Verzeichnis /etc/nginx
  • binde diese Datei im http Block per include ein
  • teste die NGINX Konfiguration mit nginx -t und lade danach die Konfiguration neu mit nginx -s
  • finde eine Bild-Datei in der Linux-Installation mit find /usr -name "*.png" und kopiere ein Bild in das Web-Root /srv/nginx/site1/html
cp /usr/share/nginx/html/nginx-logo.png /srv/nginx/site1/html/ 
chcon -t httpd_sys_content_t /srv/nginx/site1/html/nginx-logo.png
  • Binde das Bild als IMG-Tag in die HTML-Seite ein
<HMTL>
 <BODY>
  <H1>Willkommen auf dem NGINX Webserver des Linuxhotel NGINX Kurses</H1>
  <p />
  <img src="/nginx-logo.png">
 </BODY>
<HTML>
  • teste das das Bild vom Browser korrekt angezeigt wird
  • Mime-Type im Header vom Web-Server anzeigen
curl --head http://nginx0X.defaultroutes.de/nginx-logo.png

4.4 SELinux Context rekursiv

  • um nicht für jede neue Datei den SELinux Sicherheitskontext neu setzten zu müssel kann der Kontext in der SELinux Policy verankert werden. Alle neue Dateien welche unter /srv/nginx erstellt werden, bekommen damit den SELinux-Type httpd_sys_content_t:
    semanage fcontext -a -t httpd_sys_content_t --ftype f "/srv/nginx(/.*)?"
    semanage fcontext -a -t httpd_sys_content_t --ftype d "/srv/nginx(/.*)?"
    

4.5 Logging

4.5.1 Logging, Performance und Datenschutz

  • auf Webservern können viele Log-Informationen protokolliert werden
  • jedoch sollte die Menge und der Inhalt der Log-Informationen gut überlegt sein
  1. Performance
    • Log-Daten schreiben kostet CPU- und IO-Zeit. Das Schreiben von Log-Daten (kann) den Web-Server belasten und die Latenz der Antworten erhöhen
    • Log-Daten wenn möglich Puffern (Buffer)
    • Log-Daten ggf. über das Netzwerk auf einen anderen Log-Server senden (per Syslog oder Systemd-Journal) und dort auf ein Speichermedium schreiben. Ein dediziertes Netzwerk für die Log-Daten verwenden
  2. Datenschutz
    • in Log-Informationen von Webservern können datenschutzrelevante Informationen gespeichert sein
      • IP-Adressen
      • Query-Parameter
      • Passwörter (in Fehler-Logs)
      • Cookies
    • die Absicherung von Log-Dateien mit sensiblen Informationen kostet Aufwand und Geld
    • Log-Daten, die nicht ausgewertet werden, sollten auch nicht erhoben werden
    • Log-Daten nicht auf dem Webserver speichern sondern über das Netz (ggf. per TLS verschlüsselt) auf einen gesicherten Log-Server schreiben
    • Log-Daten verschlüsselt speichern (z.B. verschlüsseltes Storage mit dm-crypt)
    • Log-Daten nach einer Zeitdauer automatisch löschen

4.5.2 Logdatei-Namen mit Variablen

  • NGINX erlaubt es, interne Variablen in den Dateinamen von Log-Dateien zu verwenden. Im nachfolgenden Beispiel wird eine eigene Log-Datei für jeden virtuellen Host erzeugt.
access_log /var/log/nginx/hosts/access-for-$host;

4.5.3 gepufferte Logs

  • aus Geschwindigkeitsgründen sollten Log-Dateien auf dem Webserver gepuffert geschrieben werden. Dabei werden die Daten erst in den Puffer im Hauptspeicher geschrieben. Ist der Puffer-Speicher voll, oder ist der flush Zeitpunk seit dem letzten Schreiben erreicht, so werden die Log-Daten gesammelt auf die Platte geschrieben
  • der Web-Server schreibt daher weniger oft auf die Platte
  • Nachteil: bei einem Absturz oder Strom-Ausfall beim Webserver gehen Log-Daten verloren
access_log /path/to/log.gz combined buffer=2M flush=10m;

4.5.4 Logs per GZIP komprimieren

  • NGINX kann Log-Daten automatisch komprimiert speichern (gzip Algorithmus aus der zlib Bibliothek).
  • Komprimierte Log-Daten können mit den Programmen zcat oder gunzip ausgepackt werden. Mit dem Befahl less können komprimierte Dateien direkt angschaut werden, ohne diese vorher entpacken zu müssen
access_log /path/to/log.gz combined gzip flush=5m;
  • Wenn das Dateisystem eine Online-Komprimierung anbietet (z.B. ZFS oder btrfs), so ist diese in der Regel ressourcenschonender und einfacher zu handhaben und einer Komprimierung von NGINX vorzuziehen.

4.5.5 Error-Log und Access-Log

  • NGINX unterscheidet zwischen Fehler-Logs (error_log) und Zugriffs-Logs (access_log)
  • Beide Arten von Log-Dateien können auf unterschiedlichen Ebenen der Konfigurationsdateien definiert werden (http, server, location)
user nginx;
worker_processes  auto;

# Globales Fehler-Log
error_log  /var/log/nginx/error.log warn;

http {
  include             /etc/nginx/mime.types;
  default_type        application/octet-stream;

  # Definition eines eigenen Log-Formats
  log_format scripts '$document_root$fastcgi_script_name > $request';

  server {
        listen       80;
        server_name  nginx.defaultroutes.de;
        root   /srv/nginx/site1;

        # Zugriffs-Log für diesen virtuellen Webserver
        access_log /var/log/nginx/scripts.log scripts;
        [...]
   }
}

4.5.6 LogFormat

  • NGINX erlaubt es eigene Log-Formate zu definieren. Dabei stehen je nach aktivierten Modulen unterschiedliche Variablen zur Verfügung. Die Variablen sind in der NGINX Dokumentation der Module beschrieben.
log_format compression '$remote_addr - $remote_user [$time_local] '
                       '"$request" $status $bytes_sent '
                       '"$http_referer" "$http_user_agent" "$gzip_ratio"';

access_log /var/log/nginx/nginx-compression.log compression;
  1. Aufgabe Logging
    • Definiere das "vcombined" Logformat für virtual Hosting, wie es u.a. von Tools wie goaccess (siehe Kapitel Monitoring) benutzt wird
    log_format vcombined '$host:$server_port '
            '$remote_addr - $remote_user [$time_local] '
            '"$request" $status $body_bytes_sent '
            '"$http_referer" "$http_user_agent"';
    
    
    • Binde dieses Log-Format als weiteres Access-Log in die NGINX-Konfiguration ein
    access_log /var/log/nginx/vcombined_site1_access.log vcombined;
    
    • teste die Konfiguration, lade die Konfiguration neu
    • werden beide Log-Dateien geschrieben?
    • untersuche die Unterschiede beider Log-Formate

5 NGINX Grundkonfiguration als Webserver

5.1 NGINX Routing und virtuelle Webserver

  • NGINX unterstützt das Konzept von virtuellen Webservern (virtual web-hosting). Bei virtuellen Webservern können auf einem Server mit einer IP-Adresse mehere Webseiten mit verschiendenen Domain-Namen ausgeliefert werden. Ein Web-Browser muss diesen Web-Server per Domain-Namen (nicht per IP-Adresse) und per HTTP/1.1 Protokoll (oder neuer) ansprechen.
  • der NGINX Webserver sucht in der Konfiguration nach dem vom Web-Browser übermittelten DNS-Servernamen. Wird dieser gefunden, so wird die entsprechende Konfiguration des dazugehörigen Server-Blocks benutzt.
  • Die Direktive server_name kann auch das Platzhalter-Zeichen "*" am Anfang oder Ende des Server-Namens beinhalten, z.B. *.example.com oder example.*. Platzhalter zeichen können nicht in der Mitte des Namens auftauchen.
  • Startet der Server-Name mit dem Tilde-Zeichen ~, so wird der Name als Perl oder Python Regulärer-Ausdruck interpretiert: server_name "~^(?<name>\w\d{1,3}+)\.example\.net$";
  • ein leerer Server-Name wird mit dem Hostnamen des NGINX-Servers gefüllt: server_name "";
  • der spezielle Server-Name _ ist ein "Catch-All" für alle Namen
  • Wird der angefragte DNS-Name nicht gefunden, oder wird der Server per IP-Adresse angesprochen, so wird die "default"-Konfiguration aktiv. Die Default-Konfiguration ist die Konfiguration mit dem Schlüsselwort default_server in der listen Konfigurationdirektive. Ist kein server Block als default_server markiert, so wird die erste Server-Konfiguration in der Konfigurationsdatei aktiv.
  • Beispiel einer virtuellen Webserver-Konfiguration mit zwei Web-Auftritten:
http {
  server {
    listen       80;
    server_name  example.de www.example.de www.example.com;
    root  "/srv/nginx/example.de/html";
    [...]
  }
  server {
    listen       80 default_server;
    server_name  beispiel.de www.beispiel.de;
    root  "/srv/nginx/beispiel.de/html";
    [...]
  }
}

5.1.1 Aufgabe:

  • erstelle ein neues Verzeichnis für je eine weitere Webseite für die Domain-Namen www.nginx0X.defaultroutes.de und web.nginx0X.defaultroutes.de
  • erstelle eine Datei index.html in jedem Verzeichnis (mit einer einfachen HTML-Seite)
  • erstelle je einen weiteren server Block in der NGINX-Konfiguration für diese neue Seiten
  • teste die NGINX-Konfiguration und lade dann neue Konfiguration
  • teste neuen Webseiten des Servers vom Web-Browser
  • prüfe die Log-Einträge im Access-Log
  • spreche den Server per IPv4 Adresse an. Welche Webseite wird ausgeliefert?
  • setzte die Markierung default_server auf die listen Konfiguration des www virtuellen Hosts. Testen nochmal mit der IPv4 Adresse.

5.1.2 Lösung:

[...]
server {
  listen 80 default_server;
  server_name www.nginx0X.defaultroutes.de;

  access_log /var/log/nginx/site2_access.log;
  access_log /var/log/nginx/vcombined_site2_access.log vcombined;

  root /srv/nginx/site2/html;

  location / {
	   index index.html index.htm;
  }
}
server {
  listen 80;
  server_name web.nginx0X.defaultroutes.de;

  access_log /var/log/nginx/site3_access.log;
  access_log /var/log/nginx/vcombined_site3_access.log vcombined;

  root /srv/nginx/site3/html;

  location / {
	   index index.html index.htm;
  }
}

5.2 Location Block

  • mit einem location Block kann die Konfiguration von NGINX für einen bestimmten Pfad, oder für bestimmte Datei-Namen, geändert werden
  • Pfad- und Dateinamen für den location Block können als absoluter Name, oder als regulärer Ausdruck angegeben werden (reguläre Ausdrücke sind CPU intensiv und können die Auslieferung von Webseiten verlangsamen)
  • Beispiel absoluter Pfad:
server {
  listen 80;
  server_name www.example.com;
  root /srv/nginx/;
  location /site1 {
    root /srv/nginx/site1;
  }
}
  • Beispiel regulärer Ausdruck (Bild-Dateien dürfen für 14 Tage gecached werden)
server {
  listen 80;
  server_name www.example.com;
  root /srv/nginx/;
  location ~* \.(png|jpg|jpeg)$ {
    expires 14d;
  }
}
  • die Definition eines Location-Block kann über sg. location modifier angepasst werden:
    Modifier Wirkung
    ~* bei regulärem Ausdruck Gross-/Kleinschreibung nicht beachten (case insensitive)
    ~ bei regulärem Ausdruck Gross-/Kleinschreibung beachten
    ^~ nicht auf reguläre Ausdrücke prüfen
    = Datei-/Pfadangabe exakt benutzen (nicht nach regulären Ausdrücken suchen)
  • wichtige Dokument der Webseite sollten aus Geschwindigkeitsgründen mit dem Location-Modifier "=" markiert werden

5.2.1 Index-Dateien

  • Mit der Direktive index kann der Name einer Standard-Datei ausgewählt werden. Diese Datei wird von Webserver zurückgeliefert, wenn in der Anfrage keine Datei angegeben wurde. Typische Dateinamen für Standard-Dateien sind index.html, index.html, index.php.
server {
  listen 80;
  server_name www.example.com;
  root /srv/nginx/;
  location /site1 {
    root /srv/nginx/site1;
    index index.html, index.htm, default.html;
  }
}

5.2.2 try_files

  • mit der Direktive try_files kann eine Datei oder ein HTTP-Status-Code ausgewählt werden, welcher vom Webserver zurückgeliefert wird, wenn die Datei nicht gefunden wurde
  • in diesem Beispiel wird die Start-Seite (anstatt eines 404-Fehlers) zurückgeliefert, wenn die Angefragte Datei nicht gefunden wurde
location / {
  try_files $uri /index.html;
}
  • Beispiel: eine Standard-Bilddatei zurückliefern
location /images {
  try_files $uri $uri.png default.png;
}
  • Als Ergebniss kann auch ein HTTP-Statuscode zurückgegeben werden
location / {
  try_files $uri index.html =404;
}
  • Das Default-Ziel von try_files kann auch eine benannte location sein, welche z.B. per Reverse Proxy auf einen anderen Server verzweigt
location /bar {
  try_files $uri @revproxy;
}

location @revproxy {
  proxy_pass https://webservice2.example.com;
}

5.3 Directory Listing

  • für Software-Download-Seiten ist es praktisch, wenn der Webserver automatisch eine Webseite mit einem Verzeichnis aller Dateien auf dem Webserver ausgibt.
  • ein Directory Listing kann pro location Block angeschaltet werden
server {
  listen 80;
  server_name www.example.com;
  root /srv/nginx/;
  location /downloads {
    root /srv/nginx/software;
    autoindex on;
    autoindex_exact_size off;
    autoindex_localtime on;
  }
}
  • Die Direktive autoindex_localtime schaltet die Anzeige des Zeitstempels der Dateien an- bzw. aus.
  • Die Direktive autoindex_exact_size konfiguriert, ob die Dateigrösse exakt (in Byte) oder in für Menschen einfach lesbarer Form (in Kilobyte, Megabyte oder Gigabyte) ausgegeben werden sollen.

5.3.1 Aufgabe:

  • erstelle ein Verzeichnis für Download-Dateien unterhalb der bestehenden Webseite
  • finde und kopiere alle PDF-Dateien unterhalb von /usr in dieses Verzeichnis
    mkdir /srv/nginx/site1/download
    find /usr -name "*.pdf" -exec cp {} /srv/nginx/site1/download \;
    chown -R nginx: /srv/nginx/site1/download
    restorecon -rv /srv/nginx
    
  • lege eine location Konfiguration mit Directory-Listing für dieses Download-Verzeichnis an

5.3.2 Lösung

location /download {
	   root /srv/nginx/site1;
	   autoindex on;
	   autoindex_exact_size off;
	   autoindex_localtime on;
}

5.4 Redirect/Rewrite

  • nach einem Redesign eines Webauftritts sind viele Dateien der Webseite nicht mehr unter den vorher bekannten URLs erreichbar. Viele externe Webseiten (und auch Suchmaschinen) haben jedoch die alten URLs noch gespeichert, und es ist unrealistisch, diese zu ändern. Mit der Direktive rewrite (oder einem Redirect) kann eine Anfrage umgeschrieben oder umgelenkt werden. Damit können Anfragen von den alten URLs auf die neuen Pfade umgeschrieben oder umgelenkt werden
  • Informationen zu Rewrite und Redirect in NGINX: https://www.nginx.com/blog/creating-nginx-rewrite-rules/

5.4.1 Redirect

  • NGINX kann in einem Server- oder Location-Block einen HTTP-Redirect Statuscode zurücksenden
  • Hiermit kann die Anfrage auf einen anderen Server, ein anderes Protokoll (von HTTP auf HTTPS), oder auf einen anderen Pfad umgelenkt werden
server {
       listen *:80;
       server_name example.com;
       return 301 $scheme://www.example.com$request_uri;
}
  • oft benutzte HTTP-Statuscodes für Redirect:
Status-Code Wirkung
301 Permanent umgezogen. Die neue URL wird angegeben, neue Anfrage per GET
302 "Found", temporär umgezogen. Die alte URL bleibt gültig, neue Anfrage per GET
307 temporärer Redirect; neue Anfrage mit der gleichen Methode (z.B. GET oder POST)
308 permanent Redirect; neue Anfrage mit der gleichen Methode (z.B. GET oder POST)

5.4.2 Rewrite

  • Beim rewrite wird die Anfrage des Web-Clients umgeschrieben
  • in diesem Beispiel hat sich der Pfad zu den Bild-Dateien von /image/ zu /assets/img/ geäendert. Die Namen der Bilddateien sind gleich geblieben
server {
  listen 80;
  server_name www.example.com;
  root /srv/nginx/;
  location /site1/image {
    rewrite ^(/image/)(.*) /assets/img/$2 last;
  }
}
  • Bei HTML-Dokumenten kann ein temporärer oder permanenter Redirect benutzt werden
 server {
  listen 80;
  server_name www.example.com;
  root /srv/nginx/;
  location /site1/training/index.php {
    rewrite ^/training/index.php$ /services/clourses/training.html permanent;
  }
}
  • Beispiel mit mehreren Rewrite-Direktiven. Wird kein regulärer Ausdruck aktiv, so wird ein HTTP-Statuscode 403 (Forbidden) zurückgegeben.
server {
   # ...
   rewrite ^(/download/.*)/media/(\w+)\.?.*$ $1/sounds/$2.mp3  last;
   rewrite ^(/download/.*)/audio/(\w+)\.?.*$ $1/sounds/$2.opus last;
   return  403;
   # ...
}
  • Mögliche "Flags" für die rewrite Direktive:
    Flag Wirkung
      kein Flag - die Konfiguration wird nach dem Umschreiben weiter abgearbeitet
    last die Konfiguration wird mit der neuen URI nocheinmal neu abgearbeitet
    break die Abarbeitung der Konfiguration wird an dieser Stelle gestoppt
    permanent der Client bekommt eine permanente Umleitungs-Nachricht (Status 301)
    redirect der Client bekommt eine temporäre Umleitungs-Nachricht (Status 302)

5.5 Caching

  • mit dem Schlüsselwort expires wird der “Cache-Control” Response-Header der HTTP-Antwort, und damit das Caching-Verhalten auf der Client-Seite beeinflusst.
  • Ohne expires Direktive ist das Caching nicht aktiv
  • ein expires max setzt die Caching-Zeit auf den maximalen Wert (derzeit bis zum 31. Dezember 2037, NGINX hat ein Jahr 2038 Problem). Vorsicht mit diesem Parameter!
  • mit expires off kann das Caching explizit ausgeschaltet werden (wenn z.B. Caching von einem übergeordnetem Block geerbt wurde)
  • mit expires @zeitpunkt kann die Cache-Zeit für die Dokumente auf einen fixed Zeitpunkt gesetzt werden. Beispiel: expires @15h30m;
  • wird ein positiver Wert als Parameter zu expires angegeben, so ist dieses die Zeitdauer, über welche die ausgelieferten Dateien beim Client gecached werden dürfen: expires 24h; (Caching für 24 Stunden)
  • Beispiel:
location / {
  try_files $uri index.html =404;
  expires 10d;
}

5.6 Zugriff verweigern

  • für bestimmte Verzeichnisse unterhalb des Web-Roots kann der Zugriff verweigert werden. Dies kann per HTTP-Status via return oder mit dem Schlüsselwort deny geschehen:
server {
  listen 80;
  server_name www.example.com;
  root /srv/nginx/;
  location /secret {
    deny all;
  }
}
  • hier wird explizit der Status 403 "Forbidden" zurückgegeben:
server {
  listen 80;
  server_name www.example.com;
  root /srv/nginx/;
  location /secret {
    return 403; #Forbidden
  }
}
  • mit den Schlüsselwörtern deny und allow kann der Zugriff von bestimmten IP-Adressen oder Netzwerken erlaubt oder unterbunden werden. Die deny und allow Konfigurationen werden in der Reihenfolge der Konfiguration abgearbeitet und mit der IP-Adresse des Web-Clients verglichen:
server {
  listen 80;
  server_name www.example.com;
  root /srv/nginx/;
  location /secret {
    deny 192.0.2.100;
    allow 192.0.2.0/25;
    allow 203.0.113.0/24;
    allow 198.51.100.0/24;
    deny all;
  }
}

5.7 Error-Pages

  • Ein Webserver meldet auf die Anfrage eines Clients einen Status-Code
  • die Status-Codes sind in Gruppen eingeteilt
    • 100-199 Information - die Anfrage wird weiter bearbeitet
    • 200-299 Erfolg - die Anfrage war erfolgreich
    • 300-399 Umleitung - die Anfrage wird auf ein neues Ziel umgeleitet
    • 400-499 Fehler bei der Client Anfrage - die Anfrage war fehlerhaft und konnte nicht beantwortet werden
    • 500-599 Fehler auf Server-Seite - der Server konnte eine korrekte Anfrage nicht beantworten
    • 900-999 (inofiziell) herstellerspezifische Fehlermeldungen
  • IANA HTTP Status Code Registry https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
  • NGINX kommt mit eingebauten Fehlerseiten fuer 4xx und 5xx Fehler
    • diese Seiten können in der Konfiguration ersetzt werden
    • sowohl statische als auch dynamische (PHP, Python, Lua etc) Fehlerseiten sind möglich
error_page  404              /error_pages/404.html;
location = /error_pages/404.html {
    internal;
}

error_page  500 502 503 504  /error_pages/50x.html;
location = /error_pages/50x.html {
    internal;
}

5.7.1 Aufgabe: NGINX Error Pages

5.7.2 Beispiellösung

  • Fehler-Seiten Konfiguration in der Datei nginx.conf
[...]
       error_page  404              /error_pages/404.html;
       location = /error_pages/404.html {
	     internal;
             root   /srv/nginx/site1;
       }

       error_page  500 502 503 504  /error_pages/50x.html;
       location = /error_pages/50x.html {
	        internal;
                root   /srv/nginx/site1;
       }
[...]
  • Beispiel 404.html Fehler-Seite
<!DOCTYPE html>
<html>
<head>
  <title>Error 404 - %{HOSTNAME}</title>
  <style>
    html{ background-color: #e74c3c; }
    body{ color: #fefefe; }
  </style>
</head>

<body>
  <div class="error-middle">
    <h1>Error 404 - Not Found</h1>
    <p>The 404 (Not Found) status code indicates that the origin server
      did not find a current representation for the target resource or is
      not willing to disclose that one exists. A 404 status code does not
      indicate whether this lack of representation is temporary or
      permanent; the 410 (Gone) status code is preferred over 404 if the
      origin server knows, presumably through some configurable means,
      that the condition is likely to be permanent.</p>
  </div>
</body>
</html>
  • Beispiel 50x.html Fehler-Seite
<!DOCTYPE html>
<html>
<head>
  <title>Error 500 - %{HOSTNAME}</title>
  <style>
    html{ background-color: #f1c40f; }
    body{ color: #fefefe; }
  </style>
</head>

<body>
  <div class="error-middle">
        <h1>Error 500 - Internal Server Error</h1>
        <p>The 500 (Internal Server Error) status code indicates that
        the server encountered an unexpected condition that prevented
        it from fulfilling the request.</p>
  </div>
</body>
</html>
  • für den URL-Pfad /server-kaputt-test einen Fehler 500 zurückgeben
location = /server-kaputt-test {
        return 500;
}

5.7.3 dynamische HTML (Fehler-) Seiten mit SSI (Server Side Includes)

  • NGINX Konfiguration
error_page  500 502 503 504  /error_pages/50x.html;
location = /error_pages/50x.html {
	     internal;
	     ssi on;
	     root   /srv/nginx/site1;
}
  • HTML Seite
[...]
<body>
<div class="error-middle">
	<h1>Error 500 - Internal Server Error bei Host <!--# echo var="host" --></h1>
[...]

6 Signale zum NGINX Server senden

  • Konfiguration neu laden nginx -s reload
  • Log-Dateien neu öffnen (nach einem externen Log-Rotate): nginx -s reopen
  • NGINX geordnet beenden: nginx -s quit
  • NGINX hart stoppen: nginx -s stop
  • Unix-Signale die an NGINX gesendet werden können, z.B. per pkill -HUP nginx
    Signal Wirkung
    INT / TERM hart stoppen
    QUIT beenden
    HUP Konfiguration neu laden
    USR1 Logdateien neu öffnen
    USR2 einen neuen Master Prozess starten (Upgrade)
    WINCH Worker-Prozesse beenden, Master Prozess laufen lassen (Upgrade)

7 externe NGINX Module / Installation von externen Modulen

  • Ab Version 1.9.11 kann NGINX auch Funktionen aus externen Module nachladen (anstatt die Module bei der Kompilation aus dem Quellcode einzubinden).
  • NGINX unter CentOS 8 bringt einige Module mit
# yum search nginx
Last metadata expiration check: 1:26:25 ago on Mon Nov 25 06:40:47 2019.
=============================================================== Name Exactly Matched: nginx ================================================================
nginx.x86_64 : A high performance web server and reverse proxy server
============================================================== Name & Summary Matched: nginx ===============================================================
nginx-mod-mail.x86_64 : Nginx mail modules
nginx-mod-stream.x86_64 : Nginx stream modules
nginx-mod-http-perl.x86_64 : Nginx HTTP perl module
nginx-mod-http-xslt-filter.x86_64 : Nginx XSLT module
nginx-mod-http-image-filter.x86_64 : Nginx HTTP image filter module
nginx-filesystem.noarch : The basic directory layout for the Nginx server
pcp-pmda-nginx.x86_64 : Performance Co-Pilot (PCP) metrics for the Nginx Webserver
nginx-all-modules.noarch : A meta package that installs all available Nginx modules
  • unter CentOS 8 liegen die Modul-Dateien (shared objects) unter /usr/lib64/nginx/modules
  • Module werden im globalen NGINX Konfigurations-Kontext eingebunden
load_module "/usr/lib64/nginx/modules/ngx_http_geoip_module.so";
http {
  server {
    [...]
  }
}

7.1 Aufgabe: Image-Filter-Modul

7.2 Lösung:

load_module "/usr/lib64/nginx/modules/ngx_http_image_filter_module.so";
http {
  server {
        [...]
        location ~* \.(jpg|png) {
                image_filter rotate 90;
        }
     }
}

8 DNS und WWW

8.1 TTLs (DNS Time-to-Live)

  • die DNS-Einträge für Webseite in "produktion" sollten DNS TTL Werte zwischen einer Stunde (1h) und einem Tag (1d) aufweisen
  • Ausnahmen sind Webseiten auf CDN Systemen (Content-Delivery-Networks), dort werden die TTL Werte vom CDN-Betreiber vorgegeben
  • Vor einer Änderung an der Infrastruktur (neue IP-Adressen, Umzug in ein neues Rechenzentrum, neuer Hoster) sollten die TTLs der Webseite eine Woche vor dem Umzug herabgesetzt werden (5-10 Minuten)
  • Kurz vor dem Umzug können die TTLs dann nochmals verringert werden (1 Minute)
  • Nach dem Umzug sollten die TTLS erst auf 5-10 Minuten (um, wenn notwendig, schnell auf die alte Infrastruktur schwenken zu können) und nach einigen Tagen wieder auf die hohen TTLs (1h - 24h) gesetzt werden
  • Link: "Stop using ridiculously low DNS TTLs" https://00f.net/2019/11/03/stop-using-low-dns-ttls/

8.2 domain.tld und www.domain.tld

  • oft soll eine Webseite sowohl unter dem Service-Namen www, als auch unter der Domain direkt erreichbar sein. Beispiel: www.example.de und example.de
  • auf der DNS-Seite kann dies über einen CNAME (Alias) oder über mehrere Adress-Records realisiert werden

8.2.1 CNAME

  • Beispiel einer Lösung mit CNAME-Records
example.de.    24h IN SOA  ns01.hosting.example.  ...
example.de.    24h IN NS   ns01.hosting.example.
example.de.     2h IN A    192.0.2.80
example.de.     2h IN AAAA 2001:db8::80
www.example.de. 2h IN CNAME example.de.
  • Ein CNAME Record darf nicht im Apex (Kopf) einer DNS Zonendatei stehen (nicht auf der gleichen Ebene wie der SOA-Record). Das folgende Beispiel ist nicht korrekt:
example.invalid.        24h IN SOA  ns01.hosting.example.  ...
example.invalid.        24h IN NS   ns01.hosting.example.
example.invalid.         2h IN CNAME www.example.de.
www.example.invalid.     2h IN A    192.0.2.80
www.example.invalid.     2h IN AAAA 2001:db8::80
  • CNAME Records haben den Nachteil, das wenn der CNAME-Name aufgelöst wird, eine weitere Namensauflösung gestartet wird. Die Latenz der Webseite steigt.

8.2.2 Mehrere Adressen-Records

  • Eine Beispiel-Lösung mit mehreren Adress-Records
example.de.    24h IN SOA  ns01.hosting.example.  ...
example.de.    24h IN NS   ns01.hosting.example.
example.de.     2h IN A    192.0.2.80
example.de.     2h IN AAAA 2001:db8::80
www.example.de. 2h IN A    192.0.2.80
www.example.de. 2h IN AAAA 2001:db8::80
  • die Erfahrung zeigt das mehrere Adress-Record die einfachere und schnellere Lösung ist, auch wenn hierdurch ein wenig Redundanz in der DNS-Zone entsteht

8.3 DNS "round robin" und IPv6

  • lange Zeit war es möglich, mit mehreren Adress-Records im DNS eine einfache Lastverteilung über mehrere Web-Server zu konfigurieren
  • Beispiel:
example.de.    24h IN SOA  ns01.hosting.example.  ...
example.de.    24h IN NS   ns01.hosting.example.
www.example.de. 2h IN A    192.0.2.80
www.example.de. 2h IN A    203.0.113.80
www.example.de. 2h IN A    198.51.100.80
  • Bei der Abfrage des DNS-Namens www.example.de liefert das DNS alle drei IP Adressen an das Betriebssystem. Die Adressen werden in beliebiger Reihenfolge, oder in zufälliger Reihenfolge, an das Betriebsystem gegeben (abhängig von der Konfiguration des DNS-Resolvers des Clients, außerhalb der Kontrolle des Domain-Besitzers). Die Anwendungen (Browser) nutzen den ersten Eintrag, hier durch werden die Anfragen auf die drei Web-Server verteilt.
  • Diese Lastverteilung funktioniert nur bei Betriebssystemen, die ausschließlich IPv4 können. Bei modernen Betriebssystemen, die IPv6 können (aber nicht unbedingt aktiv konfiguriert haben), sortiert das Betriebssystem die Adressen alphanumerisch, bevor diese an die Anwendung gegeben werden. Es wird daher von der Anwendung immer die erste Adresse in der Liste benutzt, die anderen Webserver bekommen keine Anfragen mehr.
  • Links:

8.4 gTLDs, ccTLDs und nTLDs

  • Die Auswahl einer Top-Level-Domain für eine Webseite bedarf einiger Überlegung
    • bietet die TLD DNSSEC Sicherheit?
    • bietet die TLD DNS-Server für die TLD mit IPv6 Adressen (wenn nicht, kann die Domain nicht von "IPv6-Only" Clients erreicht werden)?
    • gibt es Preis-Erhöhungs-Grenzen auf dem Domain-Preis?
    • wie stabil ist die Domain (wichtig bei einigen ccTLDs wie .io oder .ly oder neuen TLDs [nTLD])

8.5 DNSSEC

  • die Sicherheitserweiterung DNSSEC sichert DNS gegen gefälschte DNS Pakete ab. DNSSEC hat zwei Bestandteile
    • DNS Zonen, welche mit DNSSEC Signaturen abgesichert sind
    • DNS-Resolver, welche die DNS Antworten mit Signaturen für die DNS-Clients prüfen (validieren) können
  • werden auf einer Webseite sensible Daten verarbeitet (Kreditkarteninformationen, datenschutzrelevante Informationen), so sollten die DNS-Namen der Webseite per DNSSEC abgesichert werden
  • macht der NGINX Server eigene DNS-Anfragen, z.B. als Reverse-Proxy oder Load-Balancer, so sollte das Betriebssystem, auf dem NGINX läuft, für eine DNS-Auflösung über einen DNSSEC validierenden Resolver konfiguriert sein