So schützen Sie Nginx mit der Coraza WAF mithilfe von Docker
Schritt-für-Schritt-Anleitung zur Bereitstellung der Coraza WAF als Reverse Proxy vor Nginx mithilfe von Docker und docker-compose, mit sofort einsatzbereitem OWASP-CRS-Schutz.
Coraza ist eine moderne, quelloffene WAF, die in Go geschrieben ist und vollständig kompatibel mit ModSecurity-Regeln und dem OWASP Core Rule Set (CRS) ist. Obwohl Coraza kein natives Nginx-Modul besitzt, besteht der empfohlene Ansatz darin, Caddy mit dem coraza-caddy-Plugin als WAF-Reverse-Proxy vor Nginx zu betreiben.
Diese Anleitung führt Sie durch ein Docker-basiertes Setup, bei dem Caddy+Coraza mithilfe von docker-compose vor einem bestehenden Nginx-Container sitzt. Am Ende haben Sie Nginx durch die Coraza WAF mit vollständiger OWASP-CRS-v4-Abdeckung geschützt, die SQL-Injection, XSS, Command-Injection und andere gängige Angriffe blockiert.
Voraussetzungen
- Docker und docker-compose auf Ihrem System installiert
- Grundkenntnisse in Docker- und Nginx-Konfiguration
- Eine Nginx-Site oder -Anwendung, die Sie schützen möchten (oder folgen Sie dem Beispiel)
Schritt-für-Schritt-Anleitung
Die Architektur verstehen
Da Coraza kein natives Nginx-Modul besitzt, verwendet das Setup Caddy als WAF-Reverse-Proxy. Der Anfragefluss lautet:
Client -> Caddy + Coraza WAF (:8080) -> Nginx (:80) -> Your Application
Caddy übernimmt die TLS-Terminierung (falls erforderlich) und führt die Coraza-WAF-Engine aus. Saubere Anfragen werden an Nginx weitergeleitet. Bösartige Anfragen werden blockiert, bevor sie Ihre Anwendung erreichen.
Dies ist ein Standard-Reverse-Proxy-Muster. Ihre Nginx-Konfiguration bleibt exakt gleich. Sie müssen lediglich die Caddy+Coraza-Schicht davor hinzufügen.
Das Projektverzeichnis erstellen
Erstellen Sie eine Verzeichnisstruktur für Ihr Setup:
mkdir -p coraza-nginx/{caddy,nginx}
cd coraza-nginx
Sie erhalten am Ende drei Dateien:
docker-compose.yml- orchestriert beide Containercaddy/Dockerfile- baut Caddy mit dem Coraza-Plugincaddy/Caddyfile- konfiguriert die WAF-Regeln und den Reverse Proxy
Das Caddy+Coraza-Dockerfile erstellen
Das offizielle Caddy-Docker-Image enthält das Coraza-Plugin nicht. Sie müssen ein eigenes Image mit xcaddy bauen, dem offiziellen Build-Tool von Caddy zum Hinzufügen von Plugins. Das coraza-caddy-Modul befindet sich unter dem v2-Modulpfad github.com/corazawaf/coraza-caddy/v2:
FROM caddy:2-builder AS builder
RUN xcaddy build \
--with github.com/corazawaf/coraza-caddy/v2
FROM caddy:2
COPY --from=builder /usr/bin/caddy /usr/bin/caddy
Speichern Sie dies als caddy/Dockerfile.
Dieser mehrstufige Build kompiliert Caddy mit dem coraza-caddy-Plugin in der Builder-Stufe und kopiert die Binärdatei anschließend in das schlanke Runtime-Image. Das resultierende Image ist genauso groß wie das Standard-Caddy-Image, nur mit hinzugefügten WAF-Fähigkeiten.
Die Caddyfile-Konfiguration schreiben
Erstellen Sie die Caddyfile, die die Coraza WAF konfiguriert und den Datenverkehr an Nginx weiterleitet:
{
auto_https off
order coraza_waf first
}
:8080 {
coraza_waf {
load_owasp_crs
directives `
Include @coraza.conf-recommended
Include @crs-setup.conf.example
Include @owasp_crs/*.conf
SecRuleEngine On
`
}
reverse_proxy nginx:80
}
Speichern Sie dies als caddy/Caddyfile.
Wichtige Konfiguration erklärt:
order coraza_waf first- stellt sicher, dass die WAF vor jedem anderen Handler ausgeführt wirdload_owasp_crs- lädt das im Modul eingebettete OWASP Core Rule Set (CRS v4); dies ist erforderlich, damit die untenstehenden Makros@crs-setup.conf.exampleund@owasp_crs/*.confaufgelöst werden könnenInclude @coraza.conf-recommended- lädt die empfohlenen Standardeinstellungen von CorazaInclude @crs-setup.conf.example- lädt die CRS-StandardkonfigurationInclude @owasp_crs/*.conf- lädt alle CRS-ErkennungsregelnSecRuleEngine On- aktiviert die Blockierung von Anfragen (nicht nur das Logging)reverse_proxy nginx:80- leitet sauberen Datenverkehr an Nginx weiter
Die docker-compose.yml erstellen
Erstellen Sie die docker-compose-Datei, die beide Dienste ausführt:
services:
caddy:
build:
context: ./caddy
ports:
- "8080:8080"
volumes:
- ./caddy/Caddyfile:/etc/caddy/Caddyfile:ro
depends_on:
- nginx
nginx:
image: nginx:alpine
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
- ./nginx/html:/usr/share/nginx/html:ro
Beachten Sie, dass Nginx keine Ports zum Host freigibt. Der gesamte Datenverkehr läuft zuerst durch Caddy+Coraza. Nur Port 8080 ist freigegeben, der WAF-geschützte Einstiegspunkt.
Eine Testseite zu Nginx hinzufügen
Erstellen Sie eine einfache Testseite, um zu überprüfen, ob das Setup funktioniert:
mkdir -p nginx/html
cat > nginx/default.conf <<'EOF'
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
EOF
cat > nginx/html/index.html <<'EOF'
<!DOCTYPE html>
<html>
<head><title>Protected by Coraza WAF</title></head>
<body>
<h1>It works!</h1>
<p>This page is served by Nginx, protected by Coraza WAF.</p>
</body>
</html>
EOF
Den Stack bauen und starten
Bauen Sie das eigene Caddy-Image und starten Sie beide Container:
docker compose build
docker compose up -d
Der erste Build dauert 1 bis 2 Minuten, da Caddy mit dem Coraza-Plugin kompiliert wird. Nachfolgende Starts erfolgen sofort, da Docker das gebaute Image cacht.
Überprüfen Sie, ob beide Container laufen:
docker compose ps
Sie sollten beide Container, caddy und nginx, mit dem Status "Up" sehen.
Normalen Datenverkehr testen
Öffnen Sie Ihren Browser oder verwenden Sie curl, um zu überprüfen, ob normale Anfragen funktionieren:
curl http://localhost:8080/
Sie sollten Ihre Testseite sehen ("It works!"). Das bestätigt, dass:
- Caddy Datenverkehr auf Port 8080 empfängt
- die Coraza WAF die Anfrage prüft und durchlässt
- Nginx die Seite über den Reverse Proxy von Caddy ausliefert
Die WAF-Blockierung testen
Testen Sie nun, ob die WAF tatsächlich Angriffe blockiert. Probieren Sie diese gängigen Angriffs-Payloads aus:
# SQL injection attempt - should return 403
curl -o /dev/null -w "HTTP %{http_code}\n" "http://localhost:8080/?id=1 OR 1=1"
# XSS attempt - should return 403
curl -o /dev/null -w "HTTP %{http_code}\n" "http://localhost:8080/?q=<script>alert(1)</script>"
# Scanner detection - should return 403
curl -o /dev/null -w "HTTP %{http_code}\n" -H "User-Agent: nikto" http://localhost:8080/
# Command injection - should return 403
curl -o /dev/null -w "HTTP %{http_code}\n" "http://localhost:8080/?cmd=;cat /etc/passwd"
Alle diese sollten HTTP 403 (Forbidden) zurückgeben. Wenn sie 200 zurückgeben, prüfen Sie, ob SecRuleEngine On in Ihrer Caddyfile gesetzt ist.
WAF-Logs anzeigen
Prüfen Sie die Caddy-Logs, um zu sehen, was Coraza blockiert und warum:
docker compose logs caddy | grep "waf"
Jede blockierte Anfrage erzeugt einen Log-Eintrag, der Folgendes zeigt:
- Die CRS-Regel, die ausgelöst hat (z. B.
REQUEST-941-APPLICATION-ATTACK-XSS) - Die Regel-ID und den Schweregrad
- Die übereinstimmenden Daten (welcher Teil der Anfrage die Regel ausgelöst hat)
- Den Anomalie-Score und den Blockierungsschwellenwert
Dies ist dasselbe OWASP-CRS-Logging-Format, das ModSecurity verwendet, sodass bestehende Log-Analyse-Tools und -Anleitungen anwendbar sind.
Für den Produktivbetrieb anpassen
Nehmen Sie für eine Bereitstellung im Produktivbetrieb diese Änderungen an Ihrer Caddyfile vor:
{
order coraza_waf first
}
yourdomain.com {
coraza_waf {
load_owasp_crs
directives `
Include @coraza.conf-recommended
Include @crs-setup.conf.example
Include @owasp_crs/*.conf
SecRuleEngine On
SecAuditEngine On
SecAuditLog /var/log/coraza/audit.log
SecAuditLogFormat json
`
}
reverse_proxy nginx:80
}
Änderungen gegenüber dem Test-Setup:
- Die Einstellung
auto_https offentfernt, sodass Caddy TLS automatisch mit Let's Encrypt übernimmt :8080durch Ihren tatsächlichen Domainnamen ersetzt- Audit-Logging (
SecAuditEngine) für die Sicherheitsüberwachung hinzugefügt - JSON-Audit-Log-Format für einfacheres Parsing hinzugefügt
Aktualisieren Sie außerdem docker-compose, um die Ports 80 und 443 anstelle von 8080 freizugeben, und fügen Sie ein Volume für Audit-Logs hinzu.
Fazit & Nächste Schritte
Sie haben nun Nginx durch die Coraza WAF mit dem OWASP Core Rule Set v4 geschützt. Das Setup blockiert SQL-Injection, XSS, Command-Injection, Scanner-Sonden und Hunderte weiterer Angriffsmuster sofort einsatzbereit.
Was Sie haben:
- Coraza WAF, die vor Nginx OWASP CRS v4 ausführt (die Version, die von coraza-coreruleset zum Build-Zeitpunkt gebündelt wird)
- Automatische Blockierung von OWASP-Top-10-Angriffen
- Detailliertes Logging aller blockierten Anfragen
- Eine saubere Trennung zwischen WAF- und Anwendungsschicht
Nächste Schritte:
- Überwachen Sie die WAF-Logs auf False Positives und passen Sie die Regeln bei Bedarf an
- Fügen Sie benutzerdefinierte
SecRule-Direktiven für anwendungsspezifischen Schutz hinzu - Richten Sie mit der
handle_errors-Direktive von Caddy eine eigene 403-Fehlerseite ein - Erwägen Sie, in Caddy Rate Limiting für DDoS-Schutz hinzuzufügen
- Für Kubernetes-Bereitstellungen finden Sie auf der Coraza-Anbieterseite Optionen für Ingress-Controller
Fehlerbehebung
Build schlägt fehl mit "xcaddy: command not found"
Stellen Sie sicher, dass Sie das Basis-Image caddy:2-builder in Ihrem Dockerfile verwenden. Dieses Image enthält xcaddy. Verwenden Sie nicht das reguläre caddy:2-Image für die Builder-Stufe.
Normale Anfragen geben 403 zurück
Ihre Anwendung löst möglicherweise CRS-Regeln aus (False Positives). Prüfen Sie die Logs mit docker compose logs caddy | grep "waf", um herauszufinden, welche Regel auslöst. Sie können in den Caddyfile-Direktiven Regelausschlüsse hinzufügen:
SecRuleRemoveById 942100
Ersetzen Sie 942100 durch die tatsächliche Regel-ID aus Ihren Logs.
Caddy kann keine Verbindung zu Nginx herstellen
Stellen Sie sicher, dass sich beide Dienste im selben Docker-Netzwerk befinden (docker-compose übernimmt dies automatisch). Überprüfen Sie, ob der Dienstname in reverse_proxy mit dem Dienstnamen in docker-compose.yml übereinstimmt. Prüfen Sie mit docker compose logs nginx, ob Nginx fehlerfrei läuft.
Änderungen an der Caddyfile werden nicht wirksam
Starten Sie den Caddy-Container neu, nachdem Sie die Caddyfile geändert haben:
docker compose restart caddy
Da die Caddyfile als schreibgeschütztes Volume eingebunden ist, müssen Sie nicht neu bauen.
Leistungsbedenken
Die Caddy+Coraza-Schicht fügt bei der Standard-CRS-Konfiguration einen einstelligen Millisekunden-Overhead pro Anfrage hinzu. Bei Sites mit hohem Datenverkehr können Sie den Overhead reduzieren, indem Sie das CRS-Paranoia-Level senken oder bestimmte Regelkategorien deaktivieren, die Sie nicht benötigen.
Häufig gestellte Fragen
Warum Caddy verwenden, anstatt Coraza direkt mit Nginx zu betreiben?
Coraza besitzt kein natives Nginx-Modul. ModSecurity hat eines (den ModSecurity-nginx-Connector), aber Coraza verfolgt einen anderen Ansatz: Es ist eine Go-Bibliothek, die sich in Go-basierte Proxys integriert. Caddy mit dem coraza-caddy-Plugin ist die beliebteste und am besten unterstützte Integration. Das Reverse-Proxy-Muster wird in der Produktion weit verbreitet eingesetzt und lässt Ihre Nginx-Konfiguration unangetastet.
Kann ich dieses Setup mit einem bereits laufenden Nginx verwenden?
Ja. Wenn Nginx auf dem Host läuft (nicht in Docker), betreiben Sie den Caddy+Coraza-Container und ändern Sie die reverse_proxy-Zeile so, dass sie auf die IP Ihres Hosts und den Nginx-Port zeigt. Zum Beispiel: reverse_proxy host.docker.internal:80 (unter Docker Desktop) oder reverse_proxy 172.17.0.1:80 (unter Linux). Aktualisieren Sie anschließend Ihr DNS oder Ihren Load Balancer, um den Datenverkehr an den Port des Caddy-Containers statt direkt an Nginx zu senden.
Funktioniert das mit Nginx Plus?
Ja. Die Caddy+Coraza-Schicht sitzt als Reverse Proxy vor Nginx. Es spielt keine Rolle, ob das Backend Nginx Open Source oder Nginx Plus ist. Die WAF prüft den Datenverkehr, bevor er Nginx erreicht, sodass alle Nginx-Plus-Funktionen (Load Balancing, Health Checks usw.) genau gleich funktionieren.
Wie aktualisiere ich die CRS-Regeln?
Die CRS-Regeln sind im coraza-caddy-Modul gebündelt (über dessen coraza-coreruleset-Abhängigkeit). Zum Aktualisieren bauen Sie Ihr Caddy-Image mit docker compose build --no-cache neu. Dies zieht die neueste coraza-caddy-Version, die das neueste gebündelte CRS enthält. Sie können eine bestimmte Version im Dockerfile festlegen: --with github.com/corazawaf/coraza-caddy/[email protected].
Wie hoch ist der Leistungs-Overhead?
In Tests fügt Coraza mit der Standard-CRS-Konfiguration 1 bis 5 ms Latenz pro Anfrage hinzu. Das ist vergleichbar mit ModSecurity. Der Overhead hängt von der Anzahl der aktivierten Regeln und dem Paranoia-Level ab. Für die meisten Anwendungen ist der Overhead im Vergleich zu den Antwortzeiten der Anwendung vernachlässigbar.