Skip to main content

Overview

Docker Compose simplifies deploying Coraza Proxy alongside backend services. The project includes two compose configurations:
  • docker-compose.yml - Basic multi-service setup
  • docker-compose.traefik.yml - Traefik reverse proxy integration

Basic Docker Compose Setup

Configuration

The basic docker-compose.yml sets up Coraza Proxy with test backends:
services:
  wafsec:
    image: wafsec:local
    container_name: wafsec
    restart: always
    volumes:
      - ./logs/:/tmp/log/coraza
    ports:
      - "8081:8081"
    environment:
      BACKENDS: |
        {
          "waf.test.local": ["web:80"],
          "api.test.local": ["api:8082"],
          "default": ["localhost:8080"]
        }
      CORAZA_RULES_PATH_APIS: >
        /app/profiles/coraza.conf:
        /app/profiles/pl2-crs-setup.conf:
        /app/coreruleset/rules/REQUEST-901-INITIALIZATION.conf:
        /app/coreruleset/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf:
        /app/coreruleset/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf:
        /app/coreruleset/rules/REQUEST-941-APPLICATION-ATTACK-XSS.conf:
        /app/coreruleset/rules/REQUEST-942-APPLICATION-ATTACK-SQLI.conf:
        /app/coreruleset/rules/REQUEST-949-BLOCKING-EVALUATION.conf
      CORAZA_RULES_PATH_SITES: >
        /app/profiles/coraza.conf:
        /app/profiles/pl1-crs-setup.conf:
        /app/coreruleset/rules/REQUEST-901-INITIALIZATION.conf:
        /app/coreruleset/rules/REQUEST-905-COMMON-EXCEPTIONS.conf:
        /app/coreruleset/rules/REQUEST-911-METHOD-ENFORCEMENT.conf:
        /app/coreruleset/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf:
        /app/coreruleset/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf:
        /app/coreruleset/rules/REQUEST-931-APPLICATION-ATTACK-RFI.conf:
        /app/coreruleset/rules/REQUEST-932-APPLICATION-ATTACK-RCE.conf:
        /app/coreruleset/rules/REQUEST-941-APPLICATION-ATTACK-XSS.conf:
        /app/coreruleset/rules/REQUEST-942-APPLICATION-ATTACK-SQLI.conf:
        /app/coreruleset/rules/REQUEST-943-APPLICATION-ATTACK-SESSION-FIXATION.conf:
        /app/coreruleset/rules/RESPONSE-955-WEB-SHELLS.conf
      PROXY_APIS_HOSTS: "api.test.local"
      PROXY_WEB_HOSTS: "waf.test.local"
    networks:
      - coraza

  api:
    build: ./docker/api
    container_name: test_api
    depends_on:
      - wafsec
    networks:
      - coraza

  web:
    build: ./docker/web
    container_name: test_web
    depends_on:
      - wafsec
    networks:
      - coraza

networks:
  coraza:
    external: true

Starting the Stack

1

Create the network

docker network create coraza
2

Build the image

docker build -t wafsec:local .
3

Start the services

docker-compose up -d
4

Verify services

docker-compose ps
docker-compose logs -f wafsec

Key Features

  • Volume Mounts: Logs persisted to ./logs/ directory
  • Restart Policy: always ensures high availability
  • Backend Routing: Host-based routing to different backends
  • Rule Separation: Different rule sets for APIs (PL2) vs websites (PL1)

Traefik Integration

Configuration

The docker-compose.traefik.yml integrates Coraza Proxy with Traefik reverse proxy:
services:
  traefik:
    image: traefik:v2.11
    container_name: traefik_coraza
    restart: always
    command:
      - "--log.level=DEBUG"
      - "--providers.docker=true"
      - "--providers.docker.exposedByDefault=false"
      - "--entrypoints.web.address=:80"
      - "--api.dashboard=true"
    ports:
      - "80:80"     # HTTP
      - "8080:8080" # Dashboard
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - internal_net
      - proxy_net

  wafsec:
    image: wafsec:local
    container_name: wafsec_coraza
    restart: on-failure:5
    depends_on:
      - traefik
    ports:
      - "8081:8081"
    environment:
      BACKENDS: |
        {
          "waf.test.local": ["web:80"],
          "api.test.local": ["api:8082"],
          "default": ["web:80"]
        }
      WAF_APIS_HOSTS: "api.test.local"
      WAF_WEB_HOSTS: "waf.test.local"
      WAF_RATE_LIMIT: 5
      WAF_RATE_BURST: 5
    labels:
      - "traefik.enable=true"
      # --- waf.test.local ---
      - "traefik.http.routers.waf.rule=Host(`waf.test.local`)"
      - "traefik.http.routers.waf.entrypoints=web"
      - "traefik.http.routers.waf.service=waf-service"
      # --- api.test.local ---
      - "traefik.http.routers.api.rule=Host(`api.test.local`)"
      - "traefik.http.routers.api.entrypoints=web"
      - "traefik.http.routers.api.service=waf-service"
      - "traefik.http.services.waf-service.loadbalancer.server.port=8081"
    networks:
      - internal_net

networks:
  internal_net:
    internal: true
  proxy_net:
    driver: bridge

Network Architecture

The Traefik setup uses two networks for security:
  • proxy_net: External traffic from Traefik to internet
  • internal_net: Internal communication between services (isolated)
Backend services (web, api) are on internal_net only, preventing direct external access.

Traefik Labels Explained

labels:
  - "traefik.enable=true"  # Enable Traefik routing
  
  # Router for waf.test.local
  - "traefik.http.routers.waf.rule=Host(`waf.test.local`)"
  - "traefik.http.routers.waf.entrypoints=web"
  - "traefik.http.routers.waf.service=waf-service"
  
  # Router for api.test.local
  - "traefik.http.routers.api.rule=Host(`api.test.local`)"
  - "traefik.http.routers.api.entrypoints=web"
  - "traefik.http.routers.api.service=waf-service"
  
  # Service configuration
  - "traefik.http.services.waf-service.loadbalancer.server.port=8081"

Starting the Traefik Stack

# Build the image
docker build -t wafsec:local .

# Start the stack
docker-compose -f docker-compose.traefik.yml up -d

# View logs
docker-compose -f docker-compose.traefik.yml logs -f

# Access Traefik dashboard
open http://localhost:8080

Testing the Setup

Add test domains to /etc/hosts:
127.0.0.1 waf.test.local
127.0.0.1 api.test.local
Test the endpoints:
# Test website endpoint
curl -H "Host: waf.test.local" http://localhost/

# Test API endpoint
curl -H "Host: api.test.local" http://localhost/api/status

# Test WAF blocking (XSS attempt)
curl -H "Host: waf.test.local" "http://localhost/?q=<script>alert(1)</script>"

Production Considerations

For production deployments:
  • Use external secrets management for sensitive environment variables
  • Configure HTTPS with TLS certificates in Traefik
  • Implement proper log rotation for audit logs
  • Set resource limits on containers

Resource Limits

Add resource constraints to prevent resource exhaustion:
wafsec:
  image: wafsec:local
  deploy:
    resources:
      limits:
        cpus: '2'
        memory: 1G
      reservations:
        cpus: '0.5'
        memory: 512M

Stopping Services

# Stop and remove containers
docker-compose down

# Stop and remove containers, volumes, and networks
docker-compose down -v

Next Steps

Configuration

Detailed environment variable reference

Docker Deployment

Standalone Docker deployment guide

Build docs developers (and LLMs) love