# display_errors off: Fehlerausgaben in der Produktion abschalten

> display_errors Off und mehr: Welche PHP-Einstellungen Fehlermeldungen von der Live-Website fernhalten, was Frameworks dazutun und wie Sie Lecks prüfen.

Quelle: https://phpsos.de/blog/display-errors-produktion/  
Stand: 25.10.2026  
Anbieter: PHP SOS, PHP-Notfallhilfe und Server-Sicherheit. Soforthilfe per WhatsApp: https://wa.me/491736494914?text=Hallo%20PHP%20SOS%2C%20wir%20brauchen%20Hilfe%20mit%20unserem%20PHP-Server.%20Firma%3A%20%E2%80%A6%20Website%3A%20%E2%80%A6

**Kurz gesagt:** Auf einer Live-Website gehört `display_errors = Off` in die php.ini, zusammen mit `display_startup_errors = Off`, `log_errors = On` und einem Fehlerlog außerhalb des Webroots. Zusätzlich müssen CMS und Frameworks im Produktivmodus laufen, sonst zeigen deren eigene Fehlerseiten die Details. Gesperrt mit `php_admin_flag` und nach jedem Update geprüft, bleiben Fehler im Log statt im Browser.

## Was eine einzige Fehlermeldung verrät

Eine Warnung am oberen Seitenrand, ein „Fatal error“ statt der Bestellübersicht: Solche Ausgaben sehen harmlos aus. Für einen Angreifer sind sie eine Landkarte. Sie zeigen vollständige Dateipfade, Namen von Datenbanken und Tabellen, eingesetzte Bibliotheken und oft die PHP-Version.

Gerade in Lagen wie PHP2Shell, in denen massenhaft nach verwundbaren Servern gesucht wird, sollte ein Server so wenig wie möglich über sich preisgeben. Das schließt keine Lücke im PHP-Interpreter, erschwert aber jeden weiteren Schritt nach einem Einbruch und macht gezielte Angriffe auf Ihre Anwendung mühsamer.

Hinzu kommt der Datenschutz. Fehlermeldungen können Teile von Anfragen enthalten, etwa E-Mail-Adressen aus Formularen. Was im Browser eines Besuchers erscheint, ist nicht mehr unter Ihrer Kontrolle.

## Die Standardwerte sind nicht für die Produktion gedacht

Viele gehen davon aus, dass PHP Fehler von sich aus verbirgt. Das PHP-Handbuch sagt etwas anderes: Der eingebaute Standardwert von `display_errors` ist 1, und `display_startup_errors` ist seit PHP 8.0 ebenfalls standardmäßig eingeschaltet. Erst die mitgelieferte Vorlage `php.ini-production` setzt beides auf Off. Das Handbuch nennt `display_errors` ausdrücklich eine Entwicklungsfunktion, die auf Systemen im Internet nie genutzt werden sollte.

Ob Ihr Server die Produktionsvorlage nutzt, ist nicht selbstverständlich. Container-Images starten teils ganz ohne php.ini, Hosting-Panels setzen eigene Werte, und nach einem Umzug wird gern die Entwicklungsvorlage kopiert.

## display_errors off: die Einstellungen im Überblick

Die folgenden Werte sind für Produktivserver sinnvoll. Die Konstanten wie `E_ALL` funktionieren nur in der php.ini; in der Apache-Konfiguration haben sie laut PHP-Handbuch keine Bedeutung und müssen als Zahl angegeben werden.

| Einstellung | Produktion | Zweck |
|---|---|---|
| `display_errors` | `Off` | keine Fehler im Browser |
| `display_startup_errors` | `Off` | keine Fehler beim Start von PHP in der Ausgabe |
| `log_errors` | `On` | Fehler ins Protokoll schreiben |
| `error_log` | Pfad außerhalb des Webroots | eigene Logdatei je Website oder Pool |
| `error_reporting` | `E_ALL` | alle Fehler protokollieren, nicht anzeigen |
| `html_errors` | `Off` | Klartext statt HTML in Protokollen |
| `zend.exception_ignore_args` | `On` | keine Funktionsargumente in Stacktraces |
| `fatal_error_backtraces` | `0` bis zum Update (nur PHP 8.5) | Übergangsmaßnahme laut php.net |

`zend.exception_ignore_args` ist besonders wertvoll. Ohne diese Einstellung können Stacktraces in Logs und Fehlerseiten die Argumente von Funktionsaufrufen enthalten, also auch Passwörter oder Tokens, die gerade verarbeitet wurden.

```ini
; php.ini der Web-SAPI
display_errors = Off
display_startup_errors = Off
log_errors = On
error_log = /var/log/php/website-fehler.log
error_reporting = E_ALL
html_errors = Off
zend.exception_ignore_args = On
; nur PHP 8.5, Übergangsmaßnahme bis zum Update auf 8.5.12:
; fatal_error_backtraces = 0
```

Im FPM-Pool sperren Sie die wichtigsten Werte zusätzlich, damit keine Anwendung sie per `ini_set()` wieder einschaltet:

```ini
; z. B. /etc/php/8.3/fpm/pool.d/seite1.conf
php_admin_flag[display_errors] = off
php_admin_flag[display_startup_errors] = off
php_admin_flag[log_errors] = on
php_admin_value[error_log] = /var/log/php/seite1-fehler.log
```

Danach den jeweiligen PHP-Dienst neu starten. Wie das Sperren genau funktioniert, erklärt der Beitrag [php_admin_value: Einstellungen gegen Überschreiben sperren](https://phpsos.de/blog/php-admin-value-sperren/). Eine vollständige Grundkonfiguration finden Sie unter [php.ini sicher konfigurieren](https://phpsos.de/ratgeber/php-ini-sicher-konfigurieren/).

## Der zweite Schalter: Debug-Modus der Anwendung

PHP ist nur die halbe Miete. Moderne Frameworks fangen Fehler selbst ab und zeigen eigene, oft sehr ausführliche Fehlerseiten. Im Debug-Modus enthalten sie Quelltextauszüge, Konfigurationswerte und manchmal Umgebungsvariablen. Diese Seiten erscheinen auch dann, wenn `display_errors` in PHP abgeschaltet ist.

Prüfen Sie deshalb für jede Anwendung den eigenen Schalter. Bei WordPress sind das `WP_DEBUG` und `WP_DEBUG_DISPLAY` in der `wp-config.php`, bei Laravel und Symfony `APP_DEBUG` und die Umgebung in der `.env`-Datei, bei anderen Systemen der Produktivmodus laut Herstellerdokumentation. Auf einem Live-System gehört der Debug-Modus dauerhaft aus, auch „nur kurz zum Testen“ ist ein Risiko.

Wie Fehler in der Anwendung sauber behandelt werden, statt sie zu unterdrücken, beschreibt [Fehler und Exceptions in PHP](https://phpsos.de/php/fehler-und-exceptions/).

## So finden Sie Fehlerausgaben, bevor andere es tun

Einmal einstellen reicht nicht. Fehlerausgaben kehren nach Updates, Umzügen oder Panel-Änderungen zurück. Ein kurzer Prüfablauf hilft:

1. Die wirksamen Werte im Webkontext prüfen, nicht nur auf der Kommandozeile, etwa mit einer kurz abgelegten, danach sofort gelöschten Prüfdatei.
2. Den Debug-Modus jeder Anwendung in deren Konfigurationsdatei kontrollieren.
3. Ausgelieferte Seiten nach typischen Fehlertexten durchsuchen, wie im Codeblock unten.
4. In der Suchmaschine mit einer `site:`-Abfrage auf Ihre Domain nach Begriffen wie „Fatal error“ oder „Warning“ suchen.
5. Prüfen, ob das Fehlerlog beschrieben wird und nicht im Webroot liegt.

```bash
# Ausgelieferte Seiten nach PHP-Fehlertexten durchsuchen (nur eigene Domains)
for url in https://www.example.de/ https://www.example.de/kontakt/; do
  curl -s "$url" | grep -E -o "(Fatal error|Warning|Notice|Deprecated|Stack trace)[^<]{0,80}" | head -3
done
# Wird das Fehlerlog beschrieben?
ls -l /var/log/php/
```

> **Wichtig:**
> Fehler zu verstecken ist kein Ersatz dafür, sie zu beheben. Ein Log voller Warnungen ist ein Hinweis auf Wartungsbedarf, und nach einem Einbruch ist es oft eine wichtige Spur. Was Sie dabei protokollieren und was nicht, beschreibt [Sicher loggen: Fehler protokollieren ohne Datenleck](https://phpsos.de/blog/sicher-loggen-php/).

## Fazit: Leise im Browser, gesprächig im Log

Die Regel für Produktivserver ist einfach: Fehler gehören ins Protokoll, nicht auf die Website. In der Praxis scheitert sie an Standardwerten, die nicht für die Produktion gedacht sind, an Debug-Schaltern in Anwendungen und an Konfigurationen, die nach Updates oder Umzügen zurückfallen.

Wer `display_errors` und `display_startup_errors` abschaltet, die Werte im Pool sperrt, den Debug-Modus der Anwendung kontrolliert und das Ergebnis regelmäßig prüft, schließt eine der häufigsten Quellen unnötiger Informationspreisgabe. Der Aufwand ist gering, die Wirkung hält, solange die Prüfung Teil jedes Updates bleibt.

Ein Punkt sollte dabei nicht untergehen: Das Fehlerlog ist kein Abfalleimer. Wer es regelmäßig liest, erkennt fehlerhafte Updates, veraltete Funktionen und manchmal auch die ersten Spuren eines Angriffs, lange bevor Kunden etwas bemerken.

## Wie hilft PHP SOS konkret?

- **Prüfen:** Wir lesen die wirksamen Fehlereinstellungen je Website und Pool aus und suchen ausgelieferte Seiten nach Fehlerausgaben ab.
- **Umstellen:** Wir setzen PHP- und Anwendungseinstellungen für den Produktivbetrieb und sperren sie gegen Überschreiben.
- **Protokolle einrichten:** Fehlerlogs liegen außerhalb des Webroots, werden rotiert und sind für Ihre Entwickler zugänglich.
- **Dauerhaft halten:** Im [Security-Wartungsvertrag](https://phpsos.de/leistungen/security-wartungsvertrag/) prüfen wir die Einstellungen nach jedem Update erneut.


## Häufige Fragen

**Ist display_errors in PHP nicht ohnehin ausgeschaltet?**  
Nicht automatisch. Laut PHP-Handbuch ist der eingebaute Standardwert von display_errors 1. Erst die mitgelieferte Vorlage php.ini-production setzt Off. Ob Ihr Server diese Vorlage nutzt, hängt von Distribution, Panel oder Container-Image ab und sollte geprüft werden.

**Reicht display_errors = Off, wenn WordPress oder Laravel im Debug-Modus laufen?**  
Nein. Viele CMS und Frameworks bringen eigene Fehlerseiten mit, die unabhängig von PHP Details anzeigen können. Schalten Sie deshalb auch den Debug-Modus der Anwendung ab, zum Beispiel WP_DEBUG_DISPLAY bei WordPress oder APP_DEBUG bei Laravel und Symfony.

**Wohin gehen Fehler, wenn sie nicht mehr angezeigt werden?**  
Mit log_errors = On schreibt PHP sie in die Datei, die error_log nennt, oder in das Protokoll der jeweiligen Betriebsart, etwa das Fehlerlog von Apache oder PHP-FPM. Die Datei sollte außerhalb des Webroots liegen und regelmäßig rotiert werden.

**Was hat fatal_error_backtraces mit PHP2Shell zu tun?**  
Die Einstellung gibt es ab PHP 8.5 und ist standardmäßig aktiv. php.net nennt fatal_error_backtraces=0 mit anschließendem Neustart als eine der Übergangsmaßnahmen für PHP 8.5, solange das Update auf 8.5.12 noch aussteht. Sie ersetzt das Update nicht.

## Quellen

- [PHP-Handbuch: Fehlerbehandlung und Protokollierung](https://www.php.net/manual/en/errorfunc.configuration.php)
- [PHP-Handbuch: Konfiguration ändern (php_admin_flag)](https://www.php.net/manual/en/configuration.changes.php)
- [php.net: Sicherheitsmeldungen](https://www.php.net/)
- [OWASP Cheat Sheets](https://cheatsheetseries.owasp.org/)
