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.

20-30 Minuten intermediate 11 steps
Zuletzt aktualisiert: Jul 18, 2026

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

1

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.

Tipp: Wenn Sie Nginx auf einem Host (nicht in Docker) betreiben, funktioniert dasselbe Muster. Betreiben Sie den Caddy+Coraza-Container und richten Sie dessen reverse_proxy-Direktive auf den Nginx-Port Ihres Hosts.
2

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 Container
  • caddy/Dockerfile - baut Caddy mit dem Coraza-Plugin
  • caddy/Caddyfile - konfiguriert die WAF-Regeln und den Reverse Proxy
3

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.

Tipp: Der Build dauert je nach Maschine 1 bis 2 Minuten. Das Builder-Image lädt Go-Abhängigkeiten herunter und kompiliert alles aus dem Quellcode. Für vollständig reproduzierbare Builds können Sie die Basis-Images auf eine bestimmte Version festlegen, zum Beispiel <code>caddy:2.10-builder</code> und <code>caddy:2.10</code>.
4

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 wird
  • load_owasp_crs - lädt das im Modul eingebettete OWASP Core Rule Set (CRS v4); dies ist erforderlich, damit die untenstehenden Makros @crs-setup.conf.example und @owasp_crs/*.conf aufgelöst werden können
  • Include @coraza.conf-recommended - lädt die empfohlenen Standardeinstellungen von Coraza
  • Include @crs-setup.conf.example - lädt die CRS-Standardkonfiguration
  • Include @owasp_crs/*.conf - lädt alle CRS-Erkennungsregeln
  • SecRuleEngine On - aktiviert die Blockierung von Anfragen (nicht nur das Logging)
  • reverse_proxy nginx:80 - leitet sauberen Datenverkehr an Nginx weiter
Warnung: Die Einstellung <code>auto_https off</code> deaktiviert automatisches HTTPS für diese Anleitung. Entfernen Sie diese Zeile für den Produktivbetrieb und konfigurieren Sie stattdessen Ihren Domainnamen anstelle von <code>:8080</code>.
5

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.

Tipp: Wenn Sie bereits einen laufenden Nginx-Container haben, können Sie nur den Caddy-Dienst hinzufügen und dessen reverse_proxy auf den Namen und Port Ihres bestehenden Containers richten.
6

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
7

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.

8

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
9

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.

10

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.

11

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 off entfernt, sodass Caddy TLS automatisch mit Let's Encrypt übernimmt
  • :8080 durch 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.

Tipp: Caddy übernimmt Let's Encrypt-Zertifikate automatisch, wenn Sie einen Domainnamen verwenden. Es ist keine zusätzliche TLS-Konfiguration erforderlich.

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.

Ähnliche Anleitungen