Coraza + Caddy → AWS WAFv2

Coraza + Caddy ↔ AWS WAFv2: integration to migration path.

No pre-prod catches CRS false positives the way real production traffic does — so Coraza + Caddy goes live at the origin behind AWS WAFv2 first, in detection-only, while AWS keeps blocking at the edge. Only after it has tuned to parity and proved itself in dual-block do we invert AWS to Count and, finally, disassociate the Web ACL — one reversible phase at a time, no cutover day.

The one thing we are loud about up front: Bot Control, Fraud Control, and Shield Advanced are network-effect SaaS features with no OSS parity. Each is an explicit retain-or-replace decision, never a silent loss.

The idea

Prove Coraza on real traffic before AWS stops blocking.

The topology that makes this zero-outage: AWS WAFv2 stays on CloudFront and the ALB at the edge while a Caddy reverse proxy compiled with Coraza sits at the origin, loading OWASP CRS. Coraza scores every request and streams a SIEM-native audit log in detection-only, so we build prod-grade exclusions from real traffic without AWS ever ceding its blocking role. Once Coraza matches AWS's coverage we move both into block, then flip AWS to Count, then disassociate the Web ACL — each step independent and reversible. The non-negotiable gate at the end is locking the origin security group to the CloudFront prefix list, so nobody bypasses Caddy by hitting the ALB directly.

The phases

Six steps. Each one reversible.

0

Baseline & inventory

We enumerate every Web ACL rule, version, and override action, pull 90-day fire counts via Athena, measure per-route body sizes, and document the origin security-group bypass risk and which paid SKUs (Shield Advanced, Bot Control, Fraud Control) are in use. Read-only.

Users see: No user impact.

Rollback: N/A

1

Coraza + Caddy goes live at origin in DETECT

Caddy compiled with the Coraza plugin stands up on ECS Fargate behind the existing ALB, running CRS at paranoia level 1 in detection-only. The AWS WAF at the edge is untouched and still blocks; Coraza scores and logs.

Users see: An extra hop adds under 2ms at P50.

Rollback: Flip the ALB target group back. Under 2 minutes.

2

Tune Coraza exclusions; AWS WAF still blocks

We query Coraza's audit log for anomaly-score hits that AWS WAF did not block — each a candidate false positive — and add per-route exclusions in a git-versioned, CI-tested exclusions file. Still detection-only throughout.

Users see: None — Coraza is still detection-only.

Rollback: Revert the exclusions file in git, then caddy reload. Under 1 minute.

3

Dual-block: AWS WAF and Coraza both enforce

Coraza flips to blocking via the Caddy admin API with zero connection drops. Both WAFs now block — defence in depth — and we watch the ALB 5xx and 403 rates, correlating any new blocks via the CloudFront request ID.

Users see: Possible new 403s for traffic AWS allowed but Coraza blocks; Phase 2 soak drives this near zero.

Rollback: Flip SecRuleEngine back to detection-only. Under 1 minute.

4

Invert: AWS WAF to Count, Coraza authoritative

Every AWS WAF rule moves to Count via an infrastructure-as-code change; AWS becomes observability and Coraza is the decision-of-record. We track AWS Count-matched but Coraza-allowed events as candidate coverage gaps.

Users see: None.

Rollback: Per-rule update back to Block. Under 5 minutes.

5

Retire AWS WAFv2

The Web ACL is disassociated and held read-only for a 30-day evidence window; CloudFront stays for caching and Shield Standard. Critically, the origin security group is locked to the CloudFront origin-facing prefix list only so nobody can bypass Caddy by hitting the ALB directly. Bot Control and Fraud Control are cancelled only if not replaced.

Users see: None for legitimate traffic. Attack traffic AWS would have blocked at the edge now reaches Caddy, raising origin egress slightly on attack days.

Rollback: Re-associate the Web ACL within the 30-day window. Under 5 minutes.

Feature parity

Where Coraza matches AWS WAF, and where it does not.

CapabilityCoraza + CaddyAWS WAFv2Parity
Rule engine Coraza SecRules (ModSecurity v3 grammar, ~95%) AWS WAFv2 statement language (ByteMatch, RegexPatternSet) Partial
Managed ruleset OWASP CRS v4.x (self-operated cadence) AWS Managed Rules (CommonRuleSet, KnownBadInputs) At parity
Anomaly scoring OWASP CRS inbound/outbound score, per-PL thresholds Label-based scoring via manual statement composition Partial
Bot detection / ML None (CrowdSec plus JA3/JA4 substitute, network-effect gap) AWS WAF Bot Control (unverified-bot ML dataset) SaaS only
Account-takeover / fraud App-layer rate-limit plus HIBP substitute AWS WAF Fraud Control - ATP / ACFP SaaS only
DDoS absorption CloudFront plus AWS Shield Standard only at edge AWS Shield Advanced plus DDoS Response Team SaaS only
Rate limiting Caddy rate_limit plugin (separate from SecRule) RateBasedStatement (per-5min per IP/header/cookie) Partial
IP reputation Project Honeypot / CrowdSec Community Blocklist AWSManagedRulesAmazonIpReputationList (opaque feed) At parity
Body inspection SecRequestBodyLimit 13 MB at origin 8 KB ALB / 64 KB CloudFront managed OSS only
TLS / edge integration Caddy ACME plus reverse proxy in one binary Native attach to CloudFront / ALB / API Gateway / AppSync Partial
Logging / SIEM SecAuditEngine JSON, pre-log PII redaction Kinesis Firehose to S3; field redaction list only At parity
Cost model Compute plus EFS plus log egress; flat $5/ACL plus $1/rule plus $0.60/M requests plus add-ons Partial
Compliance (SOC 2 / PCI) Self-owned CRS cadence plus log custody boundary Vendor SOC 2 boundary you can outsource Partial

What we're honest about

The caveats most vendors leave out.

Bot Control's ML dataset has no OSS parity

AWS WAF Bot Control's unverified-bot detection draws on a fleet-wide signal dataset from AWS-hosted properties — a network-effect feature OSS cannot reproduce. CrowdSec plus JA3/JA4 plus user-agent checks catch script-kiddies only; expect roughly a 20 percent reduction in unverified-bot efficacy if you self-host. We keep Bot Control on a stub Web ACL or move bot management into the app, and we name the gap rather than paper over it.

Fraud Control - ATP is not reproducible in OSS

Account-takeover detection is backed by AWS-fleet-wide attacker telemetry — a stolen-credential signal corpus you cannot rebuild. HIBP covers known-breached passwords, not real-time attacker-tooling signatures. The honest substitute is app-layer rate-limiting plus HIBP k-anonymity plus risk-based MFA plus device fingerprinting — a separate workstream, not a WAF sub-task.

Shield Advanced and the DDoS Response Team

Shield Advanced's DDoS Response Team requires both the subscription and a WAFv2 association on the protected resource; disassociating the Web ACL may remove that mitigation path. Either keep Shield Advanced with a Count-only stub Web ACL to preserve the DRT path at near-zero rule cost, or accept DRT removal and self-operate during a DDoS with CloudFront, Shield Standard, and autoscaling Caddy. We make that go/no-go explicit per SKU.

You operate CRS cadence and own the boundary

AWS publishes Managed Rule versions on its own cadence; with CRS you operate that cadence yourself — Renovate on the CRS repo, a CI canary in detect before promoting to block. Caddy is also the proxy, so Caddy down means the app is down: we run at least three tasks across AZs with a health check that doesn't invoke Coraza. And API Gateway, AppSync, and Cognito can't be fronted by Caddy — those surfaces stay on AWS WAFv2 or accept removal.

Why this beats a flag day

Reversible per phase. Soaked before you disassociate.

Every per-phase change rolls back inside the documented window — under 2 minutes to flip the ALB target group, under 1 minute to revert an exclusion or drop Coraza back to detection-only, under 5 minutes to re-associate the Web ACL. And we never disassociate on optimism: AWS WAF must be Count-only or removed with Coraza's blocked-request rate within plus-or-minus 20 percent of the AWS baseline for at least 30 consecutive days, with the origin-SG bypass audit clean, before the safety net comes down.

See whether your WAF migrates off AWS WAFv2 cleanly.

A call with a senior security engineer. We inventory every Web ACL rule and attachment, map AWS Managed Rules to CRS, decide which paid SKUs — Bot Control, Fraud Control, Shield Advanced — stay or get replaced, and tell you honestly whether the cost case needs the scale before we promise savings.

Map my migration →