Bösartige Bots lassen sich nicht stoppen – stattdessen vor dem App-Server abfangen: Wie man mit nginx seltsame URLs bereinigt
nginx blackhole.conf zum Bereinigen seltsamer URLs
Sobald eine Webanwendung im Internet sichtbar ist, egal welches Framework verwendet wird, kommt eine Flut seltsamer Anfragen.
- Existierende
/wp-admin/ /index.php,/xmlrpc.php– obwohl kein PHP verwendet wird.git,.env,/cgi-bin/– sensible Dateien/Verzeichnissewso.php,shell.php,test.php…
Es handelt sich nicht um eigene Dienste, sondern um Weltweit‑verteilte Scanner und Bots, die prüfen, ob es Schwachstellen gibt. Ehrlich gesagt gibt es kaum einen Server, der davon verschont bleibt.
Glücklicherweise werden die meisten dieser Anfragen auf Anwendungsebene mit 400/404 beantwortet, wenn die Verteidigungsmechanismen gut eingerichtet sind. Das eigentliche Problem liegt jedoch danach.
- Log‑Rauschen – echte Benutzeranfragen werden von einer halben Seite seltsamer Anfragen verdrängt.
- CPU‑Verbrauch – auch wenn es nur ein wenig ist, fühlt man sich unwohl, wenn unnötige Berechnungen stattfinden.
- Müdigkeit – jedes Mal, wenn man die Logs öffnet, sieht man Zehntausende von
/wp-login.php‑Einträgen.
Deshalb schneide ich solche Anfragen vollständig vor dem App-Server ab – ein „Blackhole“ auf Host‑Ebene.
In diesem Beitrag erkläre ich:
- Warum ein erster Abbruch auf nginx‑Ebene sinnvoll ist
- Wie man mit einer Datei wie
blackhole.confgemeinsame Abbruchregeln verwaltet - Praktische nginx‑Konfigurationsbeispiele, die sofort einsatzbereit sind
1. Warum ein reiner App‑Abbruch unzureichend ist
Unsere übliche Vorgehensweise lautet:
- Nicht vorhandene URLs → 404
- Ausnahmebehandlung → 400/500
- Logging → APM / Log‑Collector
Funktional ist das in Ordnung, aber aus Betriebsperspektive gibt es mehrere Stolpersteine.
-
Log‑Rauschen * Der Fehler/404‑Anteil in APM und Logging wird durch Scanner stark verzerrt. * Man muss ständig visuell unterscheiden, ob es echte Benutzer oder Scanner sind.
-
Zu tiefe Abbruchschicht * Wenn die Anfrage den App-Server erreicht, hat sie bereits Framework, Middleware und Routing durchlaufen. * Man fragt sich: „Braucht es wirklich, bis hierher zu gehen?“
-
Kumulative Ressourcenbelastung * Einmalig ist es unbedeutend, aber 24‑h‑Tage Scanner‑Traffic summiert sich zu einer großen Anzahl von Anfragen.
Daher bevorzuge ich, solche „nützlosen“ Anfragen so früh wie möglich zu filtern.
2. Blackhole in nginx: sofort mit 444 abbrechen
nginx verfügt über einen eigene Statuscode, der nicht im HTTP‑Standard definiert ist:
return 444;
- Es werden weder Header noch Body gesendet.
- Die TCP‑Verbindung wird einfach stillschweigend getrennt.
- Für den Client bedeutet das lediglich: „Die Verbindung ist abgebrochen“.
Damit lassen sich 100 % seltsame URLs komplett ohne Antwort abkürzen.
Vorteile:
- Der App-Server wird nicht erreicht – keine CPU‑Last.
- Access‑Logs können optional komplett ausgelassen werden.
- Die Logs des App‑Servers bleiben sauber, da alle seltsamen URLs bereits auf nginx‑Ebene gefiltert wurden.
3. Ein blackhole.conf für alle Regeln
Anstatt jede Regel in jedem Server‑Block zu wiederholen, halte ich eine Datei blackhole.conf bereit, die gemeinsame Muster sammelt.
Beispiel:
# /etc/nginx/blackhole.conf (Pfad frei wählbar)
# === 1. Versteckte/Versionskontroll‑Verzeichnisse (.git, .env, IDEs) ===
location ~* (^|/)\.(git|hg|svn|bzr|DS_Store|idea|vscode)(/|$) { return 444; }
location ~* (^|/)\.env(\.|$) { return 444; }
location ~* (^|/)\.(?:bash_history|ssh|aws|npm|yarn)(/|$) { return 444; }
# === 2. Unbenutzte CMS‑Admin/Schwachstellen‑Scanner ===
location ^~ /administrator/ { return 444; } # Joomla etc.
location ^~ /phpmyadmin/ { return 444; } # wenn nicht genutzt
# === 3. PHP/CGI/WordPress‑Spuren ===
# Für Stacks ohne PHP (z. B. Node, Go, Python) empfohlen
location ~* \.(?:php\d*|phtml|phps|phar)(/|$) { return 444; }
location ^~ /cgi-bin/ { return 444; }
location ~* ^/(wp-admin|wp-includes|wp-content)(/|$) { return 444; }
# === 4. Häufig gescannte Dateien/Pfade ===
location ~* ^/(?:info|phpinfo|test|wso|shell|gecko|moon|root|manager|system_log)\.php(?:/|$)? {
return 444;
}
location ~* ^/(?:autoload_classmap|composer\.(?:json|lock)|package\.json|yarn\.lock|vendor)(?:/|$) {
return 444;
}
location ~* ^/(?:_profiler|xmrlpc|xmlrpc|phpversion)\.php(?:/|$)? {
return 444;
}
# === 5. Backups/Temporäre/Dumps ===
location ~* \.(?:bak|backup|old|orig|save|swp|swo|tmp|sql(?:\.gz)?|tgz|zip|rar)$ {
return 444;
}
# === 6. well-known: ACME nur zulassen, sonst abbrechen ===
location ^~ /.well-known/acme-challenge/ {
root /var/www/letsencrypt;
}
location ^~ /.well-known/ {
return 444;
}
# === 7. Method Guard (optional): selten genutzte Methoden blockieren ===
# TRACE, CONNECT, WebDAV‑Methoden blockieren, wenn nicht benötigt
if ($request_method !~ ^(GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS)$) {
return 405;
}
Dann fügen Sie in jedem Server‑Block nur eine Zeile ein:
http {
# ...
server {
listen 80;
server_name example.com;
include /etc/nginx/blackhole.conf;
# Rest der normalen Routing‑Einstellungen...
}
}
Damit werden die meisten „unbenutzten Pfad‑Schwachstellen‑Scans“ bereits vor dem App‑Server mit 444 abgewiesen.
4. Optional: Log‑Rauschen noch weiter reduzieren
Wenn Sie möchten, können Sie die Blackhole‑Anfragen nicht in den Access‑Logs protokollieren.
Beispiel mit map:
http {
# Muster, die in den Logs ausgelassen werden sollen
map $request_uri $drop_noise_log {
default 0;
~*^/(?:\.git|\.env) 1;
~*^/(wp-admin|wp-includes|cgi-bin) 1;
~*\.php(?:/|$) 1;
}
server {
listen 80;
server_name example.com;
include /etc/nginx/blackhole.conf;
# Nur wenn $drop_noise_log == 0 wird geloggt
access_log /var/log/nginx/access.log combined if=$drop_noise_log;
}
}
$drop_noise_log= 1 → kein Log.- Nur echte Benutzeranfragen bleiben sauber.
In der Praxis empfiehlt es sich, zunächst mit Logging zu starten, die Muster zu validieren und erst dann if=$drop_noise_log zu aktivieren.
5. Richtlinien, um Fehlalarme zu vermeiden
Bei solchen Abbruchregeln ist das Wichtigste, nicht zu aggressiv zu sein. Einige Leitlinien:
-
Regeln an die Stack‑Umgebung anpassen * Bei Projekten ohne PHP kann man
.phpkomplett blockieren. * Bei Laravel oder WordPress muss.php‑Blockierung ausgeschlossen werden. * Wenn/cgi-bintatsächlich genutzt wird, Regel entfernen. -
Zuerst 404/403 testen * Statt sofort 444 kann man
return 403;nutzen, um zu prüfen, ob legitime Benutzer betroffen sind. * Nach ein paar Tagen Monitoring kann man auf 444 umstellen. -
Gefährliche Pfade konservativ behandeln *
.git,.env, Backup‑Dateien,phpinfo.php– diese sollten immer 444 blockiert werden. -
Position und Priorität * nginx‑
location‑Matching hat Prioritäten (präzise, Präfix, Regex). * Legen Sieinclude blackhole.conffrüh im Server‑Block ab, bevor die Haupt‑location /‑Handler folgen.
6. App, WAF, nginx: Jeder in seiner Rolle
Die vorgestellte Methode ist ein erster Schritt zur Rauschreduzierung.
- nginx‑Blackhole: Entfernt unnötige, nicht existierende Pfade früh.
- App‑Level‑Validierung: Domain‑Logik, Rechte, Eingabe‑Validierung – service‑spezifisch.
- WAF/Schutz‑Lösung: Muster‑/Signature‑basierte Angriffe, L7‑DDoS, fortgeschrittene Bot‑Filter.
Die Schichten ergänzen sich, ersetzen sich nicht. Der nginx‑Blackhole ist dabei ein kleiner, aber wirkungsvoller Trick: einfach zu implementieren, große Wirkung, und sogar ein Bonus für die mentale Gesundheit des DevOps‑Teams.
Fazit
Für jede öffentlich zugängliche Anwendung ist das Vermeiden von seltsamen URL‑Scans praktisch unmöglich. Stattdessen kann man die Perspektive ändern:
„Wenn sie kommen, lass sie nicht bis zur App gelangen – schneide sie vor dem nginx ab.“
Mit einer einzigen blackhole.conf und 444‑Antworten reduziert man:
- Sauberere App‑Logs
- Einfachere Analyse
- Leicht mehr Ressourcenfreiraum
Der größte Gewinn ist die Freude, wenn man morgens die Logs öffnet und statt einer endlosen /wp-login.php‑Reihe nur echte Benutzeranfragen sieht.
Wenn Sie bereits nginx betreiben, nutzen Sie diese Gelegenheit, um Ihre eigene blackhole.conf zu erstellen und einzubinden. Nach ein paar Tagen werden Sie sich fragen, warum Sie das nicht früher gemacht haben.

Es sind keine Kommentare vorhanden.