NGINX Training Dezember 2019
- Kursnotizen: http://notes.defaultroutes.de
- Linuxhotel Lab-Server (Bewertung, Passwort ändern etc): http://lab.linuxhotel.de
- Wiki (aktuelle Notizen des Kurses werden dort nach der Schulung erscheinen!): https://wiki.linuxhotel.de/doku.php?id=nginx:start
- Training Blog: https://blog.defaultroutes.de
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
- RFC 2068
- Host Header verpflichtend
- HTTP Proxies
- Header für Keep-Alive
- Pipelining
- PUT, OPTIONS, CONNECT, TRACE, und DELETE verben
- Cache-Control Header
- Basic Authentication
- Trailing headers (Trailer) https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Trailer
# 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
undyoutube.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.
- Im Browser (Firefox) vom Laptop aus die Webseite unter http://nginxXX.defaultroutes.de aufrufen
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 einesevents
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 vonstub_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 imhttp
Block perinclude
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;
- IANA List der MIME-Types https://www.iana.org/assignments/media-types/media-types.xhtml
- MDN Basics of HTTP - Mime-Types: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types
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 perinclude
ein - teste die NGINX Konfiguration mit
nginx -t
und lade danach die Konfiguration neu mitnginx -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-Typehttpd_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
- 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
- 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
- in Log-Informationen von Webservern können datenschutzrelevante
Informationen gespeichert sein
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
odergunzip
ausgepackt werden. Mit dem Befahlless
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;
- über das NGINX JavaScript Modul können eigene Variablen generiert werden. Beispiel mit SQL-Log-Informationen eines SQL-Backend-Servers im NGINX-Log: https://www.nginx.com/blog/scaling-mysql-tcp-load-balancing-nginx-plus-galera-cluster/#nginscript-logging-galera
- 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
- Definiere das "vcombined" Logformat für virtual Hosting, wie es
u.a. von Tools wie
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
oderexample.*
. 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 derlisten
Konfigurationdirektive. Ist keinserver
Block alsdefault_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
undweb.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 dielisten
Konfiguration deswww
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 sindindex.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 benanntelocation
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 Verzeichnismkdir /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üsselwortdeny
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
undallow
kann der Zugriff von bestimmten IP-Adressen oder Netzwerken erlaubt oder unterbunden werden. Diedeny
undallow
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
- rufe aus dem Browser die URL http://nginxXX.defaultroutes.de/foo auf (diese Seite existiert nicht). Es wird die Standard-Fehlerseite des NGINX Webservers angezeigt
- erstelle ein Verzeichnis für die Fehler-Seiten (Error-Pages)
- erstelle eigene Fehler-Seiten für die Fehler 404 und 50x
- Inspiration für Fehlerseiten
- teste die NGINX Konfiguration, lade die neue Konfiguration
- teste die neuen Fehlerseiten aus dem Web-Browser
- welche Log-Meldungen siehst Du im Error-Log des Webservers?
- welche Log-Meldungen siehst Du im Access-Log?
- wie kann man 404 Fehler erzeugen?
- wie kann man 50x Fehler erzeugen?
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
- binde das Image-Filter Modul
ngx_http_image_filter_module
in die NGINX Konfiguration ein - lese die Dokumentation des Moduls unter https://nginx.org/en/docs/http/ngx_http_image_filter_module.html
- richte den Image-Filter so ein, das alle Bilder auf der Webseite um 90 Grad gedreht werden
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
undexample.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:
- https://de.wikipedia.org/wiki/Lastverteilung_per_DNS
- DNS Round Robin and Destination IP address selection https://web.archive.org/web/20150316185202/http://blogs.technet.com/b/networking/archive/2009/04/17/dns-round-robin-and-destination-ip-address-selection.aspx
- RFC 6724 "Default Address Selection for Internet Protocol Version 6 (IPv6)" https://tools.ietf.org/html/rfc6724
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