Die Konfiguration von nginx ist übersichtlich aufgebaut, hat aber einige Eigenheiten, die zu schwer auffindbaren Fehlern führen. Dieser Artikel erklärt den Aufbau, die wichtigsten Blöcke und die Fallen.
Der Aufbau
nginx-Konfiguration ist hierarchisch. Einstellungen werden nach unten vererbt und können überschrieben werden:
# /etc/nginx/nginx.conf
user www-data;
worker_processes auto; # ein Prozess je CPU-Kern
error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;
events {
worker_connections 1024; # Verbindungen je Prozess
use epoll; # effizienteste Methode unter Linux
}
http {
# Basis
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on; # effizientes Senden aus dem Dateizwischenspeicher
tcp_nopush on;
tcp_nodelay on;
server_tokens off; # Versionsnummer nicht verraten
# Zeitlimits
client_body_timeout 12s;
client_header_timeout 12s;
keepalive_timeout 65s;
send_timeout 10s;
# Groessen
client_max_body_size 10m; # Upload-Grenze! Standard 1m
client_body_buffer_size 128k;
large_client_header_buffers 4 16k;
# Kompression
gzip on;
gzip_vary on;
gzip_min_length 1000;
gzip_comp_level 6;
gzip_types text/plain text/css application/json
application/javascript text/xml application/xml;
# Protokolle
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" rt=$request_time';
access_log /var/log/nginx/access.log main;
# Konfigurationen einbinden - getrennt je Seite ist uebersichtlicher
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Ein Server-Block
# /etc/nginx/sites-available/app.example.org
server {
listen 80;
listen [::]:80;
server_name app.example.org www.app.example.org;
# Alles auf HTTPS umleiten - als erster und eigener Server-Block
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name app.example.org www.app.example.org;
# TLS
ssl_certificate /etc/letsencrypt/live/app.example.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/app.example.org/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off; # bei TLS 1.3 ueberfluessig
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_stapling on;
ssl_stapling_verify on;
# Sicherheits-Kopfzeilen
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'" always;
root /var/www/app;
index index.html;
# Statische Dateien direkt ausliefern - schnell und ohne Anwendung
location /static/ {
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}
# Anwendung
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Zeitlimits bewusst setzen
proxy_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# Puffer
proxy_buffering on;
proxy_buffers 8 16k;
}
# Interner Zustandspunkt - nur lokal erreichbar
location = /health {
allow 127.0.0.1;
deny all;
proxy_pass http://127.0.0.1:8080/health;
}
# Versteckte Dateien sperren
location ~ /\. {
deny all;
access_log off;
}
}
Regeln für location: die Rangfolge
Diese Reihenfolge ist die häufigste Fehlerquelle. nginx prüft in fester Ordnung:
1. location = /pfad (exakt) - hoechste Prioritaet
2. location ^~ /pfad (Praefix, stoppt Regex-Pruefung)
3. location ~ regex (Regex, in Reihenfolge des Auftretens)
4. location ~* regex (Regex ohne Gross-/Kleinschreibung)
5. location /pfad (Praefix) - laengster Treffer gewinnt
6. location / (Standard)
# Beispiele
location = /login nur exakt /login
location ^~ /static/ alles unter /static/, keine Regex danach
location ~ \.php$ jede .php-Anfrage
location /api/ alles unter /api/
# Typischer Fehler: ^~ vergessen
location /static/ { } # eine spaetere Regex greift vielleicht
location ~ \.(css|js)$ { } # ... und ueberschreibt die Einstellung
Umleitung und Umschreibung
# 301 dauerhaft, 302 voruebergehend - IMMER eine Weiterleitung bei Regeln
# angeben, sonst wird intern umgeschrieben.
# Praefix ersetzen
location /alt/ {
return 301 /neu/;
}
# Regex-Umschreibung mit Umleitung
rewrite ^/blog/(\d{4})/(\d{2})/(.*)$ /artikel/$1-$2-$3 permanent;
# Intern umschreiben (keine Umleitung)
rewrite ^/konto$ /konto.php last;
# Trailing Slash erzwingen
location /ordner {
return 301 /ordner/;
}
# www auf ohne-www umleiten
server {
listen 443 ssl;
server_name www.example.org;
return 301 https://example.org$request_uri;
}
# Fuer Weiterleitungen immer $request_uri verwenden, nicht $uri:
# $request_uri enthaelt die Abfrageparameter, $uri nicht.
Häufige Fallstricke
add_headerwird vererbt – aber nur, wenn kein eigeneradd_headerim inneren Block steht. Setzt man in einemlocationeinen eigenenadd_header, verliert man alle Kopfzeilen der äußeren Blöcke. Entweder konsequentalwaysverwenden und in jedem betroffenen Block wiederholen – oder mit einer Include-Datei arbeiten.client_max_body_sizeStandard ist 1 MB. Wer größere Uploads braucht, muss den Wert erhöhen. Die Meldung 413 Request Entity Too Large ist die Folge.- Fehlermeldungen der Anwendung landen als 502. 502 Bad Gateway heißt meist: Die Anwendung lauscht nicht auf dem angegebenen Port oder läuft nicht. Zuerst
ss -tlnp | grep 8080prüfen. rootohnetry_files. Bei einer Anwendung mit eigenen Routen (Single Page Application) muss die Anfrage aufindex.htmlfallen, sonst liefert ein direktes Aufrufen einer Unterseite 404:location / { try_files $uri $uri/ /index.html; }- Protokollpuffer bei
proxy_buffering off. Ohne Puffer sammelt nginx alles im Speicher – bei großen Antworten problematisch. - Doppelte
server_name. Zwei Blöcke mit demselben Namen: Der zuerst gelesene gewinnt, der zweite wird ignoriert. nginx warnt beim Test, aber die Warnung wird übersehen. - Standard-Server nicht gesetzt. Ohne
default_serverbeantwortet der erste Server-Block alle Anfragen mit unbekanntem Hostnamen – oft mit einer Fehlerseite einer anderen Seite.
Prüfen und neu laden
# Konfiguration pruefen - IMMER vor dem Neuladen
nginx -t
nginx -T # die vollstaendige wirksame Konfiguration ausgeben
nginx -T | grep -A5 'server_name app'
# Neu laden ohne Verbindungsabbruch
systemctl reload nginx
# reload ist immer besser als restart: bestehende Verbindungen
# werden noch bedient, neue Prozesse uebernehmen.
# Bei Syntaxfehler bleibt die alte Konfiguration aktiv - gut so.
# Erzwingen: nginx -s reload
# Logs
tail -f /var/log/nginx/access.log
tail -f /var/log/nginx/error.log
journalctl -u nginx --since '10 min ago'
# Zustand
nginx -V # Version und Kompilieroptionen
curl -I http://localhost/ # Kopfzeilen pruefen
systemctl status nginx
Debuggen: was nginx wirklich tut
# Kopfzeilen einer Anfrage ansehen (auch die eigenen add_header)
curl -sSI https://app.example.org | grep -iE '^(http|server|x-|strict|content-security)'
# Welche Adresse/Geschwindigkeit?
curl -sS -o /dev/null -w 'HTTP %{http_code} %{time_total}s %{size_download} Bytes\n' \
https://app.example.org/
# nginx-Protokoll erweitern: Variablen zeigen, welcher Block greift
# In jedem server-Block: add_header X-Server-Block "app" always;
# In jedem location: add_header X-Location "api" always;
# Danach einmal abrufen und die Kopfzeilen ansehen - damit ist klar,
# welche Regel tatsaechlich gegriffen hat.
# TLS pruefen
openssl s_client -connect app.example.org:443 -servername app.example.org </dev/null 2>/dev/null | \
openssl x509 -noout -subject -issuer -dates
Verwandte Grundlagen: nginx, nginx-Befehle, Reverse-Proxy, Load Balancing.