Overview
Coraza Proxy uses a multi-stage Docker build to create a lightweight, production-ready container. The build process compiles the Go application and bundles the OWASP Core Rule Set in a secure Alpine-based image.
Dockerfile Breakdown
The Dockerfile uses a two-stage build process to minimize the final image size:
Build Stage
FROM golang:1.24-alpine AS builder
RUN apk add --no-cache git
WORKDIR /src
COPY . .
RUN go mod tidy
# Download Coraza and OWASP CRS
RUN git clone --depth 1 https://github.com/coreruleset/coreruleset /src/coreruleset
RUN go build -o /coraza-proxy main.go
The build stage:
Uses Go 1.24 on Alpine Linux
Installs git to clone the OWASP Core Rule Set
Compiles the application into a static binary
Downloads the latest CRS rules
Production Stage
FROM alpine:latest
RUN apk add --no-cache ca-certificates
RUN addgroup -S coraza && adduser -S coraza -G coraza
WORKDIR /app
COPY --from=builder /coraza-proxy /app/coraza-proxy
COPY --from=builder /src/coreruleset /app/coreruleset
COPY --from=builder /src/profiles /app/profiles
RUN mkdir -p /tmp/log/coraza && \
touch /tmp/log/coraza/audit.log && \
chown -R coraza:coraza /tmp/log/coraza
USER coraza
ENTRYPOINT [ "/app/coraza-proxy" ]
The production stage:
Uses minimal Alpine Linux base image
Creates a non-root user coraza for security
Copies the compiled binary and rule sets
Sets up logging directories with proper permissions
Runs as non-root user
Building the Image
Build the Docker image from the project root:
docker build -t wafsec:local .
The image is tagged as wafsec:local to match the compose file configurations.
Running the Container
Basic Run
Run the container with minimal configuration:
docker run -d \
--name coraza-proxy \
-p 8081:8081 \
-e BACKENDS='{"default":["localhost:5000"]}' \
wafsec:local
With Volume Mounts
Mount log files for persistence:
docker run -d \
--name coraza-proxy \
-p 8081:8081 \
-v ./logs:/tmp/log/coraza \
-e BACKENDS='{"waf.test.local":["web:80"]}' \
wafsec:local
With Custom Rules
Mount custom rule configurations:
docker run -d \
--name coraza-proxy \
-p 8081:8081 \
-v ./logs:/tmp/log/coraza \
-v ./custom-profiles:/app/profiles \
-e CORAZA_RULES_PATH_SITES="/app/profiles/coraza.conf:/app/coreruleset/rules/*.conf" \
wafsec:local
Security Considerations
The container runs as a non-root user (coraza) for security. Ensure any mounted volumes have appropriate permissions.
File Permissions
If mounting custom directories, set proper ownership:
# Create log directory with correct permissions
mkdir -p ./logs
chown -R 1000:1000 ./logs # Match the coraza user UID/GID
Image Size Optimization
The multi-stage build significantly reduces image size:
Build stage : ~800MB (includes Go compiler and build tools)
Final image : ~50MB (only Alpine + binary + rules)
Health Checks
Add a health check when running the container:
docker run -d \
--name coraza-proxy \
-p 8081:8081 \
--health-cmd= "wget --no-verbose --tries=1 --spider http://localhost:8081 || exit 1" \
--health-interval=30s \
--health-timeout=10s \
--health-retries=3 \
wafsec:local
Next Steps
Docker Compose Multi-container setup with Docker Compose
Configuration Environment variables and advanced configuration