- health.go: treat any HTTP response as reachable (only connection errors fail) - main.go: CheckRedirect in handleReturn to preserve 302 + Set-Cookie - middleware.go: Content-Length for POST/PUT/PATCH bodies, CheckRedirect in forwardToWAF and forwardToReturn - web/: replace stats panel with 3-state WAF indicator (DISABLED/ENABLED/FAILED) - README: update defaults, architecture, health check docs - .agents.md: update verified status for Wallarm integration |
||
|---|---|---|
| web | ||
| zoraxy_plugin | ||
| .agents.md | ||
| .gitignore | ||
| circuit_breaker.go | ||
| config.go | ||
| go.mod | ||
| health.go | ||
| hosts.go | ||
| main.go | ||
| middleware.go | ||
| README.md | ||
Firewall
Zoraxy plugin — Inline WAF inspection proxy with health checks, circuit breaker, and fail-open bypass. Works with Wallarm, ModSecurity, Coraza, or any inspection service that returns HTTP status codes.
Quick Install
The plugin is built into Zoraxy — just enable it from the Plugins panel. If you need to build from source:
git clone https://git.lohmar.co.uk/cclohmar/zoraxy-waf.git /opt/zoraxy/plugins/zoraxy-waf
cd /opt/zoraxy/plugins/zoraxy-waf
go build -buildvcs=false -o zoraxy-waf .
chown -R zoraxy:zoraxy /opt/zoraxy/plugins/zoraxy-waf
systemctl restart zoraxy
Then enable Firewall in Zoraxy → Plugins.
Configuration
Open the Firewall panel at /plugin.ui/zoraxy-firewall/:
| Setting | Default | Description |
|---|---|---|
| Enable | Off | Toggle WAF inspection on/off |
| WAF URL | http://127.0.0.1:8080 |
The firewall application itself (e.g., Wallarm, ModSecurity, Coraza) |
| Return Port | 8081 |
Port where inspected traffic returns to Zoraxy for routing |
| Health Interval | 5s |
How often to check if the WAF is reachable |
| Timeout | 10000ms |
Max wait time for an inspection verdict |
How It Works
Client → Zoraxy → Plugin → http://waf:8080 [Firewall App] → inspect
│
┌────┴──────────┐
│ 403 → BLOCK │
│ 2xx → RETURN │──→ Zoraxy (port 8080) → Backend
│ down → FAIL-OPEN│──→ Zoraxy routes directly
└───────────────┘
- Zoraxy proxies traffic to the firewall application at the configured WAF URL
- The firewall app inspects the request inline
- If blocked (403), the plugin drops the request
- If allowed (2xx), traffic returns to Zoraxy on the return port for routing to the final backend
- If the firewall app is unreachable, the circuit breaker opens and traffic bypasses inspection (fail-open)
Circuit Breaker
If the WAF fails 5 times within a 30-second window, the breaker opens. All traffic bypasses inspection (fail-open) for 10 seconds. After the cooldown, the next successful health check closes the breaker.
Health Check
The plugin periodically sends a HEAD request to the WAF URL. Any HTTP response (regardless of status code) means the WAF is reachable — the circuit breaker records success. Only connection errors (timeout, connection refused) trigger failures.
Inspection Protocol
The plugin proxies the full HTTP request to the WAF URL. The firewall application inspects it inline and returns an HTTP status code:
- 200–299 → Traffic is clean, returned to Zoraxy for routing
- 403 → Request is malicious, plugin blocks it
- 302 → Redirects are preserved (e.g. login session cookies) — the plugin does not follow redirects
- 5xx / timeout → Plugin fails open, breaker records failure
All HTTP response headers and status codes are passed through transparently. Redirects and Set-Cookie headers are preserved end-to-end.
Zoraxy Integration
To activate the plugin for specific proxy rules:
- Zoraxy → Plugins → enable Firewall
- Create a plugin group (e.g., "waf") → add the Firewall plugin
- Edit proxy rules → add the "waf" tag
The plugin uses Zoraxy's static capture to intercept all requests matched by tagged proxy rules.
API Endpoints
| Method | Path | Purpose |
|---|---|---|
GET |
/ui/api/config |
Get current configuration |
POST |
/ui/api/config/save |
Save configuration |
GET |
/ui/api/stats |
Metrics (total/allowed/blocked/bypassed) + circuit state + enabled flag |
POST |
/inspect |
Static capture — Zoraxy sends traffic here |
POST |
/verdict |
Return port — WAF sends async callbacks here |
Architecture
/opt/zoraxy/plugins/zoraxy-waf/
├── zoraxy-waf # Compiled plugin binary
├── waf_config.json # Runtime configuration (auto-created)
├── config.go # Config load/save (thread-safe)
├── main.go # Plugin entry, UI router, return listener
├── middleware.go # Inspection handler, WAF proxy, metrics
├── hosts.go # Backend resolution from Zoraxy proxy configs
├── circuit_breaker.go # Fail-open state machine
├── health.go # Background health check goroutine
├── web/ # Config panel UI — WAF status indicator
│ ├── index.html
│ ├── style.css
│ └── app.js
└── zoraxy_plugin/ # Vendored Zoraxy plugin SDK (LGPL)
Environment Variables
| Variable | Default | Description |
|---|---|---|
| none | — | All config is managed through the UI and persisted to waf_config.json |
License
Zoraxy plugin SDK is LGPL. This plugin is open source.
Credits
- Zoraxy — Reverse proxy and plugin system
- Compatible with any WAF that returns HTTP verdicts (Wallarm, ModSecurity, Coraza, custom)