Nginx Benutzerdefinierte Fehlerseiten: Verbessern Sie die Benutzererfahrung

Konfigurieren Sie nützliche Nginx-Benutzerdefinierte Fehlerseiten für 404-, 403- und 50x-Antworten, ohne echte Fehler zu verbergen.

Nginx Benutzerdefinierte Fehlerseiten: Verbessern Sie die Benutzererfahrung

Nginx-Benutzerdefinierte Fehlerseiten verwandeln einen rohen Fehler in einen klaren nächsten Schritt. Sie beheben nicht den defekten Link, die fehlende Datei oder die abgestürzte Upstream-App. Sie tun etwas Kleineres, aber dennoch Wertvolles: Sie sagen dem Besucher in einfacher Sprache, was passiert ist, und verhindern, dass er sich von Ihrer Seite ausgeschlossen fühlt.

Das ist bei gewöhnlichen Fehlern wichtig. Jemand folgt einem alten Dokumentationslink und erhält eine 404. Ein privater Dateipfad gibt 403 zurück. Ihre App startet während der Bereitstellung neu und Nginx sieht kurzzeitig 502. Ohne eine benutzerdefinierte Seite sehen Benutzer möglicherweise eine Standard-Serverantwort, die abrupt oder technisch wirkt. Mit einer guten statischen Seite wissen sie, ob sie suchen, zurückgehen, erneut versuchen oder warten sollen.

Die besten Fehlerseiten sind langweilige Betriebswerkzeuge. Sie sind statisch, schnell, zugänglich und ehrlich. Sie verbergen keine Ausfälle vor der Überwachung und geben keine internen Details an Benutzer weiter.

Beginnen Sie mit den Fehlern, die Benutzer tatsächlich sehen

Sie müssen nicht für jeden HTTP-Statuscode eine Seite entwerfen. Beginnen Sie mit den häufigen.

404 Nicht gefunden ist die erste Seite, die Sie anpassen sollten. Sie erscheint, wenn die angeforderte URL keiner Datei, Route oder Nginx-Location entspricht, die Inhalt zurückgibt. Alte Links, umbenannte Beiträge, gelöschte Dokumentationsseiten und manuell eingegebene URLs führen alle hierher.

Eine nützliche 404-Seite sagt etwa: „Wir konnten diese Seite nicht finden.“ Dann bietet sie einen Weg zurück zur Startseite, zum Dokumentationsindex, zum Produktbereich oder zur Suchseite. Geben Sie nicht dem Benutzer die Schuld. Die URL könnte schon lange falsch gewesen sein, bevor er darauf geklickt hat.

403 Verboten ist anders. Nginx hat die Anfrage verstanden, wird sie aber nicht bedienen. Ursachen sind Dateiberechtigungen, Zugriffsregeln, deaktivierte Verzeichnisauflistung, IP-Erlauben/Verweigern-Regeln oder Authentifizierungsanforderungen. Eine 403-Seite sollte ruhig und kurz sein. Wenn die Ressource privat ist, sagen Sie das. Wenn Benutzer möglicherweise Zugriff benötigen, verweisen Sie sie auf den richtigen Login- oder Support-Pfad.

Für app-basierte Seiten behandeln Sie 50x-Fehler sorgfältig:

  • 500 Interner Serverfehler bedeutet normalerweise, dass die Anwendung bei der Verarbeitung der Anfrage fehlgeschlagen ist.
  • 502 Bad Gateway bedeutet oft, dass Nginx keine gültige Antwort vom Upstream-Dienst erhalten hat.
  • 503 Dienst nicht verfügbar ist nützlich für Wartung, Überlastung oder einen absichtlich nicht verfügbaren Dienst.
  • 504 Gateway-Zeitüberschreitung bedeutet, dass Nginx zu lange auf die Upstream-Antwort gewartet hat.

Ein SaaS-Dashboard-Beispiel: Ihr App-Prozess startet während der Bereitstellung neu. Für einige Sekunden kann Nginx keine Verbindung zum Upstream herstellen und Benutzer sehen eine 502. Eine benutzerdefinierte Seite kann sagen: „Das Dashboard ist vorübergehend nicht verfügbar. Bitte aktualisieren Sie in einer Minute.“ Das ist nicht perfekt, aber klarer als ein Standard-Gateway-Fehler.

Erstellen Sie statische Fehlerdateien

Halten Sie Fehlerseiten außerhalb der Anwendungsabhängigkeitskette. Wenn die Datenbank ausgefallen ist, sollte die 500-Seite trotzdem geladen werden. Wenn die Node-, Python-, Ruby- oder PHP-App nicht gesund ist, sollte Nginx trotzdem den statischen Fallback bedienen.

Ein einfaches Dateilayout könnte sein:

/var/www/example.com/public/
  index.html
  assets/
/var/www/example.com/errors/
  404.html
  403.html
  50x.html

Halten Sie das HTML leichtgewichtig. Vermeiden Sie Skripte von Drittanbietern, schwere Bilder, clientseitige App-Bundles und alles, was das defekte Backend aufruft. Eine kleine CSS-Datei ist in Ordnung, wenn Nginx sie direkt ausliefern kann.

Ein minimales 404.html könnte sein:

<!doctype html>
<html lang="de">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Seite nicht gefunden</title>
</head>
<body>
  <main>
    <h1>Seite nicht gefunden</h1>
    <p>Die Seite wurde möglicherweise verschoben, oder der Link ist veraltet.</p>
    <p><a href="/">Zur Startseite</a></p>
  </main>
</body>
</html>

Das ist genug. Sie können es an Ihre Website anpassen, aber die Nachricht und die Links sind wichtiger als die Dekoration.

Binden Sie die Seiten mit error_page ein

In Nginx ordnet die Direktive error_page einen oder mehrere Statuscodes einem URI zu. Ein grundlegender Server-Block sieht so aus:

server {
    listen 80;
    server_name example.com www.example.com;

    root /var/www/example.com/public;

    error_page 404 /errors/404.html;
    error_page 403 /errors/403.html;
    error_page 500 502 503 504 /errors/50x.html;

    location /errors/ {
        internal;
        root /var/www/example.com;
    }

    location / {
        try_files $uri $uri/ =404;
    }
}

Die Pfadauflösung ist der Teil, der Menschen verwirrt. In diesem Beispiel verwenden Anfragen unter /errors/ root /var/www/example.com;, also wird /errors/404.html auf /var/www/example.com/errors/404.html abgebildet.

Die Direktive internal bedeutet, dass externe Clients /errors/404.html nicht direkt als normale URL anfordern können. Nginx kann sie trotzdem intern bedienen, wenn ein Fehler behandelt wird.

Nach der Bearbeitung der Konfiguration testen und neu laden:

sudo nginx -t
sudo systemctl reload nginx

Dann das Verhalten testen:

curl -I http://example.com/definitiv-fehlende-seite
curl -s http://example.com/definitiv-fehlende-seite | head

Der Status sollte immer noch 404 sein, auch wenn der Body Ihr freundliches HTML ist. Ein häufiger Fehler ist, versehentlich 200 OK für eine fehlende Seite zurückzugeben, was dazu führt, dass Überwachung und Suchmaschinen denken, die fehlende URL sei eine echte Seite.

Benutzerdefinierte Seiten hinter einem Reverse-Proxy

Wenn Nginx an eine Upstream-Anwendung weiterleitet, kann die App ihre eigenen Fehlerantworten zurückgeben. Standardmäßig werden Proxy-Antworten normalerweise an den Client zurückgegeben. Damit Nginx Upstream-Fehlerantworten abfängt und Ihre error_page-Regeln verwendet, aktivieren Sie proxy_intercept_errors im entsprechenden Kontext.

location /app/ {
    proxy_pass http://app_backend;
    proxy_intercept_errors on;

    error_page 502 503 504 /errors/50x.html;
}

Die Nginx-Dokumentation beschreibt proxy_intercept_errors als anwendbar auf Proxy-Antworten mit Statuscodes größer oder gleich 300, die dann zur error_page-Verarbeitung an Nginx umgeleitet werden können. In der Praxis sollten Sie es nicht überall einschalten, ohne nachzudenken.

Für Browserseiten ist das Abfangen von 502 oder 503 oft nützlich. Für JSON-APIs kann es falsch sein. API-Clients erwarten normalerweise einen strukturierten JSON-Fehlerbody, keine HTML-Seite. Möglicherweise benötigen Sie separate Locations:

location /api/ {
    proxy_pass http://api_backend;
    proxy_intercept_errors off;
}

location /dashboard/ {
    proxy_pass http://app_backend;
    proxy_intercept_errors on;
    error_page 502 503 504 /errors/50x.html;
}

Diese Aufteilung hält menschenorientierte Seiten freundlich, während maschinenlesbare API-Fehler erhalten bleiben.

Den richtigen Statuscode beibehalten

Nginx erlaubt es Ihnen, den Antwortcode mit error_page zu ändern, aber tun Sie das nur, wenn Sie es beabsichtigen. Dies ist eine gültige Syntax:

error_page 404 =200 /fallback.html;

Für die meisten Websites wäre das eine schlechte Idee. Eine fehlende Seite sollte eine 404 bleiben. Suchmaschinen, Uptime-Checks, Analysen und Benutzer profitieren alle von der Wahrheit.

Es gibt legitime Fälle für das Ändern von Codes, wie das Weiterleiten bestimmter Fehler an eine benannte Location oder das Zurückgeben einer Wartungsseite mit 503. Aber als Standardregel sollten Sie den ursprünglichen Fehlerstatus beibehalten.

Für Wartungsarbeiten können Sie explizit sein:

location / {
    return 503;
}

error_page 503 /errors/maintenance.html;

location = /errors/maintenance.html {
    root /var/www/example.com;
    internal;
}

Wenn Sie ein CDN oder einen Load Balancer vor Nginx verwenden, denken Sie daran, dass dieser möglicherweise ein eigenes Fehlerseitenverhalten hat. Entscheiden Sie, welche Ebene welche Fehler besitzt. Andernfalls testen Sie möglicherweise Nginx direkt und sehen eine Seite, während Benutzer hinter dem CDN eine andere sehen.

Schreiben Sie Fehlerseiten für Menschen

Der Inhalt sollte drei Fragen schnell beantworten:

  • Was ist passiert?
  • Ist es vorübergehend?
  • Was kann ich als nächstes tun?

Für eine 404 sind nützliche nächste Schritte: Suche, Startseite, Dokumentationsindex oder Kontakt zum Support, wenn die fehlende Seite existieren sollte. Für eine 503 ist nützliche Anleitung: später erneut versuchen oder eine Statusseite überprüfen. Für eine 403 verweisen Sie auf Anmelde- oder Zugriffsanforderungsanweisungen, falls zutreffend.

Vermeiden Sie Stack-Traces, Upstream-Hostnamen, Dateisystempfade, Paketversionen, interne IPs, Anfrage-IDs ohne Erklärung und Vorfall-Details. Eine Anfrage-ID kann nützlich sein, wenn der Support sie verwenden kann, aber kennzeichnen Sie sie klar:

<p>Wenn Sie den Support kontaktieren, geben Sie diese Anfrage-ID an: <code>$request_id</code></p>

Um Variablen wie $request_id einzufügen, benötigen Sie ein Konfigurationsmuster, das dies unterstützt. Statische HTML-Dateien erweitern Nginx-Variablen nicht von selbst. Viele Teams halten öffentliche Fehlerseiten statisch und verlassen sich stattdessen auf Protokolle für Anfrage-IDs.

Barrierefreiheit ist Teil der Nützlichkeit. Verwenden Sie eine klare h1, lesbaren Kontrast, normale Links und einfachen Text. Machen Sie die einzige Wiederherstellungsaktion nicht zu einem winzigen Symbol oder einem skriptgesteuerten Button.

Testen Sie die Seiten absichtlich

Warten Sie nicht, bis Benutzer Ihre Fehlerseiten finden. Testen Sie sie nach jeder Änderung.

Für 404:

curl -i https://example.com/keine-solche-seite

Für 403 erstellen Sie eine kontrollierte Test-Location oder verwenden Sie eine private Testdatei. Lockern Sie nicht die Produktionsberechtigungen, nur um einen Fehler auszulösen.

Für 502 oder 503 testen Sie in der Staging-Umgebung, indem Sie eine Location auf einen nicht verfügbaren Upstream verweisen:

location /defekter-upstream-test/ {
    proxy_pass http://127.0.0.1:59999;
    proxy_intercept_errors on;
    error_page 502 503 504 /errors/50x.html;
}

Dann fordern Sie es an und bestätigen sowohl den Statuscode als auch den Body:

curl -i https://staging.example.com/defekter-upstream-test/

Beobachten Sie auch die Protokolle:

sudo tail -f /var/log/nginx/error.log /var/log/nginx/access.log

Eine gut aussehende Fehlerseite sollte das betriebliche Signal nicht löschen. Ihre Alarme sollten immer noch ausgelöst werden, wenn die 50x-Raten steigen.

Nginx-Benutzerdefinierte Fehlerseiten sind eine kleine Konfigurationsaufgabe mit einer echten Benutzerauswirkung. Beginnen Sie mit 404, 403 und den häufigen 50x-Fehlern. Servieren Sie statische Dateien direkt von Nginx. Bewahren Sie genaue Statuscodes. Verwenden Sie proxy_intercept_errors nur dort, wo HTML-Fallbacks sinnvoll sind. Testen Sie dann die Seiten genauso, wie Sie jedes andere Produktionsverhalten testen.