Was Nginx eigentlich ist
Nginx (ausgesprochen “engine-x”) ist ein Webserver, der auf einer ereignisgesteuerten, asynchronen Architektur basiert. Anstatt einen Thread oder Prozess pro Verbindung zu nutzen, verarbeiten wenige Worker-Prozesse tausende gleichzeitige Verbindungen, indem sie auf Events reagieren. Dank dieses Designs kann Nginx vor einer langsamen Anwendung geschaltet werden, ohne zusammenzubrechen – weshalb es zum Standard-Einstiegspunkt für das moderne Web wurde.
Nginx übernimmt drei Rollen, die oft vermischt werden. Es ist ein statischer Webserver, der Dateien effizient von der Festplatte ausliefert. Es ist ein reverse proxy, der Anfragen an einen anderen Server weiterleitet und die Antwort zurückgibt. Und es ist ein load balancer, der Anfragen auf einen Pool von Backends verteilt. Vor einer Node, Python, Go oder PHP App werden Sie alle drei Funktionen nutzen. Nginx ist kein Teil Ihrer Anwendung: es ist ein separater Prozess mit eigener Konfiguration, eigenem Lebenszyklus und eigenen Logs.
Warum man es vor die App schaltet
Man könnte Node direkt an Port 80 binden. In Tutorials wird das oft so gemacht, und es funktioniert – bis es nicht mehr funktioniert. Nginx als Reverse Proxy davor zu schalten, bietet eine Reihe von Funktionen, die mühsam oder riskant zu implementieren wären, wenn man sie direkt in die Anwendung einbaut.
TLS-Terminierung. Nginx verwaltet das Zertifikat, führt den Handshake durch und entschlüsselt die Daten. Deine App kommuniziert über einfaches HTTP auf localhost und muss sich nie um die Zertifikatserneuerung kümmern. Certbot kann die Konfiguration sogar automatisch für dich anpassen.
Statische Dateien, Komprimierung und Caching. Nginx liefert Dateien mit sendfile und Kernel-Caching aus, komprimiert diese mit gzip oder brotli und kann eine gespeicherte Antwort zurückgeben, ohne den Upstream überhaupt zu kontaktieren.
Rate Limiting und Request-Limits. Missbrauch wird direkt am Edge gestoppt, bevor er den Connection Pool oder eine Datenbankabfrage belastet.
Ein einziger Einstiegspunkt. Eine einzige öffentliche Adresse und ein Zertifikat können viele Dienste bedienen, die über den Hostnamen oder Pfad geroutet werden. Du kannst eine App auf einen anderen Port oder Host verschieben, ohne den DNS ändern zu müssen.
Zero-Downtime-Deployments. Ein Upstream kann den Traffic von einem Backend ableiten, während dieses neu startet, und ein Neuladen der Konfiguration erfolgt reibungslos (graceful). Direkt exponiertes Node bricht beim Neustart jede aktive Verbindung ab.
Das Konfigurationsmodell
Die Nginx-Konfiguration ist ein Baum aus Contexts und Directives. Eine Directive ist eine Einstellung, die mit einem Semikolon endet; ein Context ist ein in geschweiften Klammern eingeschlossener Block, der weitere Directives enthält. Directives werden nach unten hin vererbt, wobei der spezifischste Context Vorrang hat.
# /etc/nginx/nginx.conf (main context)
user www-data;
worker_processes auto;
pid /run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
gzip on;
gzip_types text/css application/javascript application/json;
# site configs are pulled in here
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Die Contexts, mit denen Sie arbeiten werden, sind:
- main — globale Einstellungen wie
userundworker_processes. - events — wie Verbindungen gehandhabt werden.
- http — alles rund um HTTP: MIME-Typen, Logging, Kompression und die Includes, die die Website-Dateien einbinden.
- server — ein virtueller Host, der über
listenundserver_nameausgewählt wird. - location — ein Pfad innerhalb eines Servers, an dem Anfragen tatsächlich verarbeitet werden.
Unter Debian und Ubuntu ist es üblich, pro Website eine Datei in /etc/nginx/sites-available/ zu führen und die aktivierten Seiten per Symlink nach /etc/nginx/sites-enabled/ zu verknüpfen. Dies bietet einen einfachen Weg, eine Website zu deaktivieren, ohne sie löschen zu müssen.
sudo ln -s /etc/nginx/sites-available/app /etc/nginx/sites-enabled/app
sudo rm /etc/nginx/sites-enabled/app
Directives sind keine Skriptsprache. Es gibt keine Schleifen oder Variablen im herkömmlichen Sinne – nur map, if (sparsam einzusetzen) und Includes. Wenn ein Problem nach einer Steuerungslogik verlangt, ist die Lösung meist ein map oder eine Änderung an der Anwendung.
Dein erster server block
Ein server block ist ein virtueller Host. Er hört auf einem Port, antwortet auf einen oder mehrere Namen und enthält location blocks.
server {
listen 80;
server_name app.example.com www.app.example.com;
root /var/www/app/dist;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
server_name wird mit dem Host header abgeglichen. Der erste server block für einen Port ist der default server und fängt Anfragen ab, deren Host mit nichts anderem übereinstimmt. Daher lohnt es sich, diesen explizit als Catch-all einzurichten, der einen 444-Fehler oder eine Wartungsseite zurückgibt, anstatt versehentlich eine nicht beabsichtigte Seite auszuliefern.
Die Reihenfolge des Matchings ist entscheidend und führt oft zu Fehlern. location blocks werden zuerst als exakte Treffer (=), dann als längster Prefix-Match und schließlich über Regexes (~ und ~*) geprüft. Ein ^~ prefix weist Nginx an, die Suche zu stoppen und diesen Prefix zu verwenden, ohne Regexes zu prüfen. Wenn sich das Verhalten falsch anfühlt, liegt das meist an dieser Reihenfolge.
location = /favicon.ico { log_not_found off; access_log off; }
location ^~ /assets/ { expires 1y; }
location ~* \.(jpg|png|css|js)$ { expires 30d; }
location / { try_files $uri /index.html; }
Proxying zu einer Node.js App
Die zentrale Direktive ist proxy_pass. Richten Sie diese auf Ihre Anwendung aus, und Nginx fungiert als Reverse Proxy.
upstream app {
server 127.0.0.1:3000;
keepalive 32;
}
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://app;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_read_timeout 30s;
proxy_connect_timeout 5s;
}
}
Die Definition eines upstream-Blocks anstelle der Inline-Angabe der Adresse dient nicht nur der Unterstützung mehrerer Server. Erst dadurch können Sie keepalive festlegen, sodass Nginx Verbindungen zum Backend wiederverwendet, anstatt für jede Anfrage eine neue TCP-Verbindung zu öffnen. proxy_http_version 1.1 ist für Keepalive und für WebSockets erforderlich.
Timeouts sollten sorgfältig geplant werden. proxy_connect_timeout begrenzt die Zeit, die Nginx auf den Verbindungsaufbau wartet; proxy_read_timeout begrenzt die Zeit, die auf das nächste Byte vom Upstream gewartet wird. Der Read-Timeout muss länger sein als Ihre langsamste legitime Antwort, andernfalls gibt Nginx einen 504-Fehler zurück, während die App noch arbeitet.
Die Regel mit dem abschließenden Slash ist eine klassische Stolperfalle. proxy_pass http://app; leitet den vollständigen Pfad unverändert weiter. proxy_pass http://app/; ersetzt das gefundene Location-Präfix durch /. Innerhalb von location /api/ sendet die erste Variante /api/users und die zweite /users. Wählen Sie bewusst und prüfen Sie das Upstream-Log.
Header-Weiterleitung und warum sie für deine App wichtig ist
Standardmäßig sieht der Upstream die Anfrage so, als käme sie von Nginx: Die Client-Adresse ist 127.0.0.1, das Schema ist http und der Host-Header fehlt möglicherweise. Das führt zu Problemen beim Logging, bei Redirects, Cookies und beim Rate Limiting innerhalb der App.
location / {
proxy_pass http://app;
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;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
}
Jeder Header hat seine Daseinsberechtigung:
- Host bewahrt die ursprüngliche Domain, sodass die App korrekte absolute URLs und Virtual Hosts erstellen kann.
- X-Real-IP ist die unmittelbare Client-Adresse.
- X-Forwarded-For ergänzt eine Kette;
$proxy_add_x_forwarded_forbehält alle vorhandenen Einträge bei und fügt den aktuellen Client hinzu. Nutze den ersten Eintrag als ursprünglichen Client, aber vertraue ihm niemals blind. - X-Forwarded-Proto teilt der App mit, ob sich der Benutzer über HTTPS verbunden hat, was Redirect-Loops und Bugs bei Secure-Cookies behebt.
- X-Forwarded-Host und X-Forwarded-Port helfen weiter, wenn Nginx auf einem nicht standardmäßigen Port lauscht.
Deinem Framework muss mitgeteilt werden, dass es diesem Proxy vertrauen soll. In Express sorgt app.set("trust proxy", 1) dafür, dass req.ip und req.protocol die weitergeleiteten Werte auslesen. Wenn du das überspringst, scheint jede Anfrage von localhost zu kommen, was stillschweigend das per-IP Rate Limiting und die Geolocation beeinträchtigt.
Statische Dateien ausliefern und der SPA-Fallback
Nginx ist hervorragend darin, statische Dateien auszuliefern – überlassen Sie ihm also diese Aufgabe. Eine gängige Aufteilung besteht darin, das gebaute Frontend direkt von der Festplatte zu servieren und nur die API zu proxien.
server {
listen 80;
server_name app.example.com;
root /var/www/app/dist;
location /assets/ {
try_files $uri =404;
expires 1y;
add_header Cache-Control "public, immutable";
}
location /api/ {
proxy_pass http://app;
proxy_set_header Host $host;
}
location / {
try_files $uri /index.html;
}
}
Für eine Single-Page App ist try_files $uri /index.html der Fallback, der das clientseitige Routing ermöglicht: Wenn der angeforderte Pfad keine Datei ist, wird index.html zurückgegeben und der Router übernimmt die Steuerung. Für eine API ist dasselbe Muster mit =404 besser, da das Zurückgeben von HTML bei einem fehlenden Endpunkt Bugs verschleiern würde.
Assets mit Content-Hashes im Namen können dauerhaft gecached werden — immutable und ein Ablaufdatum von einem Jahr sind sicher, da jede Änderung einen neuen Dateinamen erzeugt. index.html darf niemals auf diese Weise gecached werden, da die Nutzer sonst dauerhaft eine veraltete Version der App laden.
TLS mit Let’s Encrypt und certbot
Certbot bezieht kostenlose Zertifikate von Let’s Encrypt und kann Nginx automatisch konfigurieren. Installieren Sie das Plugin, führen Sie es einmal pro Domain aus, und das Tool erledigt den Rest.
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d app.example.com -d www.app.example.com
sudo certbot renew --dry-run
Certbot schreibt die Pfade zu den Zertifikaten in Ihren Server-Block und installiert einen Timer für die Erneuerung. Zertifikate sind 90 Tage gültig; die Erneuerung erfolgt automatisch, funktioniert jedoch nur, wenn die Erneuerungsprüfung Ihren Server über Port 80 erreichen kann. Sperren Sie diesen also nicht vollständig über die Firewall ab.
Der resultierende Block sieht so aus: ein HTTP-Server, der weiterleitet, und ein HTTPS-Server, der die Verbindung terminiert.
server {
listen 80;
server_name app.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
http2 on;
server_name app.example.com;
ssl_certificate /etc/letsencrypt/live/app.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/app.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
location / {
proxy_pass http://app;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
TLSv1.2 und TLSv1.3 sind heutzutage die einzigen Protokolle, die es wert sind, aktiviert zu werden. HSTS weist Browser an, einfaches HTTP für ein Jahr abzulehnen. Aktivieren Sie dies daher erst, wenn Sie sicher sind, dass HTTPS überall funktioniert – es ist schwierig, dies wieder rückgängig zu machen.
HTTP/2 und HTTP/3
HTTP/2 multiplexed viele Anfragen über eine einzige Verbindung und wird pro Server aktiviert. In modernen Nginx-Versionen (1.25.1 und neuer) lautet die Direktive http2 on;. In älteren Versionen ist es ein Flag in der listen-Zeile: listen 443 ssl http2;.
server {
listen 443 ssl;
http2 on;
# ...
}
HTTP/3 läuft über QUIC und UDP. Es benötigt einen Build mit dem QUIC-Modul, eine separate listen 443 quic reuseport;-Zeile und einen Alt-Svc: h3=":443"; ma=86400-Header, um es anzukündigen. Betrachten Sie dies als Optimierung, die Sie implementieren, sobald HTTP/2 stabil läuft, und nicht als ersten Schritt. Browser handeln beides automatisch über TLS aus, sodass in Ihrer App nichts geändert werden muss.
Load-Balancing-Methoden
Ein upstream-Block definiert einen Pool, und die Balancing-Methode entscheidet, welcher Server die nächste Anfrage erhält. Standardmäßig wird Round-robin verwendet.
upstream app {
least_conn;
server 10.0.0.11:3000 weight=2 max_fails=3 fail_timeout=15s;
server 10.0.0.12:3000;
server 10.0.0.13:3000 backup;
keepalive 64;
}
- Round-robin (Standard) durchläuft die Server zyklisch. Einfach und effektiv, wenn Anfragen in etwa die gleiche Last verursachen.
least_connsendet Anfragen an den Server mit den wenigsten aktiven Verbindungen. Besser geeignet, wenn die Dauer der Anfragen stark variiert, was bei APIs häufig der Fall ist.ip_hashbindet einen Client durch Hashing der Adresse an einen bestimmten Server. Nützlich für In-Memory-Sessions, allerdings auf Kosten einer ungleichmäßigen Lastverteilung und des Verlusts der Stickiness, wenn ein Server ausfällt.weightlenkt den Traffic bevorzugt auf eine leistungsstärkere Maschine oder wird bei einem Canary-Release eingesetzt.backupmarkiert einen Server, der nur dann Traffic erhält, wenn die primären Server nicht verfügbar sind.
max_fails und fail_timeout ermöglichen ein passives Health Checking: Nach max_fails Fehlern innerhalb von fail_timeout markiert Nginx den Server für diesen Zeitraum als nicht verfügbar. proxy_next_upstream entscheidet dann, welche Fehler auf einem anderen Backend erneut versucht werden.
proxy_next_upstream error timeout http_502 http_503 http_504;
Retries sind mächtig, aber nicht kostenlos: Sie ergeben nur bei idempotenten Anfragen Sinn. Versuchen Sie niemals blind einen POST-Request erneut, der möglicherweise bereits den Zustand geändert hat, es sei denn, das Upstream ist per Design idempotent.
Health Checks und Fehlerbehandlung
Nginx OSS verfügt über passive Checks; aktive Health Checks (health_check mit match) erfordern Nginx Plus. Passive Checks in Kombination mit einem Endpoint auf Anwendungsebene reichen für die meisten Teams völlig aus: Stellen Sie /healthz bereit, der die benötigten Abhängigkeiten – wie Datenbank und Cache – prüft und schnell antwortet, und richten Sie dann die Liveness Probe Ihrer Plattform darauf aus. Nutzen Sie dies, um Deployments zu steuern, indem Sie ein neues Backend starten, warten, bis es den Status „healthy“ erreicht hat, und anschließend das alte aus dem Upstream entfernen.
Da Konfigurations-Reloads „graceful“ ablaufen, besteht das Zero-Downtime-Muster darin, den Upstream so zu bearbeiten, dass er auf die neue Instanz zeigt, nginx -t, einen Reload durchzuführen und danach die alte Instanz auslaufen zu lassen (drain) und zu stoppen.
Caching mit proxy_cache
proxy_cache speichert Upstream-Antworten auf der Festplatte und liefert diese aus, ohne das Backend zu kontaktieren. Für leseintensive Endpunkte, die sich nur langsam ändern, ist dies der größte Performance-Gewinn, der auf der Edge-Ebene möglich ist.
proxy_cache_path /var/cache/nginx levels=1:2
keys_zone=app:10m max_size=1g inactive=60m;
server {
listen 80;
server_name app.example.com;
location /api/public/ {
proxy_pass http://app;
proxy_cache app;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_valid 200 302 10s;
proxy_cache_valid 404 1m;
proxy_cache_bypass $http_authorization $cookie_session;
proxy_no_cache $http_authorization;
add_header X-Cache-Status $upstream_cache_status;
}
}
proxy_cache_valid legt fest, wie lange jeder Statuscode gecacht wird. proxy_cache_bypass überspringt den Cache für Anfragen, die einen Session- oder Authorization-Header enthalten; proxy_no_cache verhindert das Speichern dieser Antworten, sodass die privaten Daten eines Benutzers niemals an einen anderen ausgeliefert werden. Der X-Cache-Status Header (HIT, MISS, BYPASS, EXPIRED) ist der schnellste Weg, um zu beweisen, dass das Caching funktioniert.
Zwei Warnhinweise: Cachen Sie nur Antworten, die sicher geteilt werden können – also öffentliche, nicht personalisierte Daten – und stellen Sie sicher, dass der Upstream einen Cache-Control Header sendet, der mit Ihrer Konfiguration übereinstimmt. Ein Cache-Key, der eine Variante (z. B. einen Language-Header oder einen Query-Parameter) ignoriert, wird bereitwillig den falschen Inhalt ausliefern.
Rate Limiting mit limit_req
Rate Limiting schützt Login-Endpoints, die Suche und öffentliche APIs vor Missbrauch und versehentlichen Floods. Es wird im http-Kontext definiert und in einem Location-Block angewendet.
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
limit_req_status 429;
server {
listen 80;
server_name app.example.com;
location /api/ {
limit_req zone=api burst=20 nodelay;
proxy_pass http://app;
}
location = /api/login {
limit_req zone=login burst=5 nodelay;
proxy_pass http://app;
}
}
Der Zone-Key ist normalerweise $binary_remote_addr (die Client-IP), und die Rate wird in Anfragen pro Sekunde oder Minute angegeben. burst erlaubt kurze Spitzen (Spikes), und nodelay verarbeitet den Burst sofort, anstatt ihn zu verteilen – was für interaktive Endpoints wünschenswert ist. Ohne nodelay werden überschüssige Anfragen verzögert, was dazu führen kann, dass sich eine UI träge anfühlt, anstatt einfach einen 429-Fehler zurückzugeben.
Hinter einem anderen Proxy oder einem CDN kann $binary_remote_addr die Adresse des Proxys sein, sodass der Limiter alle Nutzer als einen einzigen Client behandelt. Beheben Sie dies, indem Sie set_real_ip_from und real_ip_header konfigurieren, damit Nginx den tatsächlichen Client erkennt. Geben Sie zudem 429 anstelle des Standardwerts 503 zurück, damit Clients zwischen Rate Limiting und einem Systemausfall unterscheiden können.
WebSocket-Upgrade
Eine WebSocket-Verbindung beginnt als HTTP-Request mit einem Upgrade-Header und wird anschließend zu einem langlebigen, bidirektionalen Stream. Für das Proxying sind die Upgrade-Header sowie ein Connection-Wert erforderlich, der vom Request abhängt, weshalb ein map verwendet wird.
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443 ssl;
http2 on;
server_name app.example.com;
location /ws/ {
proxy_pass http://app;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}
Das read_timeout ist hierbei entscheidend: Ein inaktiver WebSocket mit einem kurzen Timeout wird von Nginx geschlossen, was beim Client als mysteriöser Verbindungsabbruch erscheint. Beachten Sie, dass HTTP/2 WebSockets nicht auf die gleiche Weise transportiert; Browser öffnen für das Upgrade eine separate HTTP/1.1-Verbindung, die Nginx automatisch auf demselben Port handhabt.
Nginx in Docker ausführen
Das offizielle nginx Image ist ein praktischer Weg, um Konfigurationen und statische Dateien zusammen mit deiner App auszuliefern. Die einzige Regel ist, dass der Hauptprozess des Containers im Vordergrund bleiben muss, weshalb der Befehl mit daemon off; endet.
# Dockerfile
FROM nginx:1.27-alpine
COPY nginx.conf /etc/nginx/conf.d/app.conf
COPY dist/ /usr/share/nginx/html/
EXPOSE 80 443
CMD ["nginx", "-g", "daemon off;"]
In Compose ist der App-Service über seinen Servicenamen erreichbar, daher ist der Upstream-Host einfach app. Nginx startet, bevor die App bereit ist; füge daher entweder einen Healthcheck hinzu und richte eine Abhängigkeit darauf ein, oder lass Nginx die Anfrage wiederholen.
# docker-compose.yml
services:
nginx:
image: nginx:1.27-alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/app.conf:ro
- ./certs:/etc/nginx/certs:ro
depends_on:
app:
condition: service_healthy
app:
build: .
expose:
- "3000"
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:3000/healthz"]
interval: 5s
retries: 10
Beachte expose anstelle von ports bei der App: Diese sollte nur innerhalb des Compose-Netzwerks erreichbar sein, niemals direkt vom Host aus. Der Upstream in der Nginx-Konfiguration wird zu server app:3000;.
Testen, Neuladen und Zero-Downtime-Konfigurationsänderungen
Jede Konfigurationsänderung sollte demselben Zyklus folgen: validieren, neuladen, verifizieren. Ein Reload ist graceful; ein Neustart hingegen nicht.
sudo nginx -t # test the configuration
sudo nginx -T # test and dump the full effective config
sudo systemctl reload nginx # graceful, no dropped connections
sudo systemctl status nginx
curl -I https://app.example.com
nginx -T wird zu selten genutzt und ist extrem hilfreich: Es gibt die zusammengeführte Konfiguration genau so aus, wie Nginx sie sieht, was Diskussionen über Vererbung und Includes beendet. Wenn -t fehlschlägt, nennt die Fehlermeldung die entsprechende Datei und Zeile.
Beim Neuladen sollte in einer zweiten Session eine Shell geöffnet bleiben, damit eine fehlerhafte Konfiguration Sie nicht aussperrt. In einem Container entspricht dies dem Senden von SIGHUP an den Master-Prozess oder dem Ausführen von nginx -s reload. Starten Sie einen stark ausgelasteten Produktions-Nginx niemals neu, um eine Konfigurationsänderung anzuwenden, wenn ein Reload ausreicht.
Best Practices
- Führen Sie
nginx -tvor jedem Reload aus; editieren und starten Sie niemals blind neu. - Verwenden Sie eine Datei pro Seite und aktivieren Sie diese über einen Symlink, damit Änderungen rückgängig gemacht werden können.
- Definieren Sie einen
upstream-Block mitkeepalive, anstatt die Backend-Adresse inline einzufügen. - Leiten Sie
Host,X-Real-IP,X-Forwarded-ForundX-Forwarded-Protoimmer weiter und setzen Sietrust proxyin der App. - Servieren Sie statische Assets und gehashte Bundles von der Festplatte mit langen, immutable Cache-Headern.
- Leiten Sie HTTP auf HTTPS um und aktivieren Sie HSTS erst, wenn HTTPS nachweislich funktioniert.
- Cachen Sie nur öffentliche, nicht-personalisierte Antworten und verwenden Sie niemals einen Cache-Key ohne dessen Varianten.
- Implementieren Sie Rate Limiting für Login- und öffentliche Endpunkte und geben Sie 429 statt 503 zurück.
- Lange Timeouts für WebSocket-Locations, kurze für Health Checks.
- Halten Sie Secrets und Zertifikate aus den Images heraus; mounten Sie diese zur Laufzeit schreibgeschützt.
Häufige Fehler
nginx -tüberspringen und die Seite durch einen Syntaxfehler offline nehmen.X-Forwarded-Protovergessen und anschließend eine Endlosschleife aus HTTPS-Redirects debuggen müssen.trust proxyin der App nicht aktivieren, sodass jede Anfrage so aussieht, als käme sie von localhost.proxy_passmit und ohne abschließenden Slash verwechseln und dadurch 404-Fehler erhalten.proxy_read_timeoutkürzer einstellen als eine legitime langsame Antwort, was zu 504-Fehlern führt.- Personalisierte Antworten cachen und so die Daten eines Benutzers an einen anderen ausliefern.
- WebSockets ohne den Upgrade-
mapproxien, wodurch Verbindungen sofort abbrechen. - Den Standard-Server als ersten Site-Block stehen lassen und so eine unbeabsichtigte App exponieren.
- HSTS aktivieren, bevor HTTPS überall funktioniert, und Benutzer für ein Jahr aussperren.
- Den App-Service in Compose mit
portsstatt mitexposeexponieren.
Wie geht es weiter?
Nginx ist das Eingangstor, und der Guide zu HTTP / HTTPS erklärt das Protokoll, das Nginx terminiert und weiterleitet. Um Nginx reproduzierbar neben deiner App zu betreiben, lies Docker & Deployment, und um den Host, auf dem es läuft, gesund zu halten, schau dir noch einmal Linux an. Wenn du bereit bist, Nginx mit Zertifikaten, DNS und Autoscaling im öffentlichen Internet bereitzustellen, führt der Guide zu Cloud Deployment diese Einzelteile zusammen.