If you already reverse-proxy with Caddy (or you’re tired of ModSecurity glue), there’s a boring option that works well on a single VPS: put OWASP CRS in front of your apps and keep the ops surface small.
This post is the path I use when I want app-layer filtering (SQLi/XSS/scanners) without a compose stack.
What you actually need
For most small/medium self-hosted setups:
| Layer | Job | What does not solve it |
|---|---|---|
| Edge / scrubbing | Volumetric DDoS, big botnets | A reverse-proxy WAF alone |
| App-layer WAF | SQLi, XSS, scanner junk, bad bots that look like browsers | Geo-IP blocks forever |
| Auth / rate limits | Credential stuffing, noisy clients | CRS by itself |
Don’t sell yourself a WAF as a DDoS product. Use CRS for the application junk; keep rate limits / challenges / an upstream scrubber for the rest.
The packaging tradeoff
Common self-hosted WAF paths:
- Docker WAFs (SafeLine and friends) — great UI, more moving parts.
- Roll your own — Caddy/Nginx + Coraza/ModSecurity + CRS + dashboards — flexible, glue-heavy.
- Single binary — reverse proxy + Coraza + CRS + admin UI in one process.
I’ve been using option 3 via Tiyi: one Go binary, SQLite, local admin UI/CLI, free on a single node. Demo (install → site → block SQLi):
https://www.tiyisec.com/assets/video/tiyi-demo.mp4
Install (Linux)
curl -fsSL https://www.tiyisec.com/install.sh | sh
tiyi run
Open the admin UI, set the admin password on first run, then:
- Add an upstream (your real app)
- Add a site (hostname → upstream)
- Keep CRS enabled (default path)
- Hit the site with a trivial SQLi probe and confirm a block + security log
Exact CLI flags change with versions — the site/quickstart is the source of truth.
A minimal “did it work?” check
Once the site is live on the proxy port:
# should be blocked / challenged by CRS
curl -i "http://127.0.0.1:18080/?q=1%27%20OR%20%271%27%3D%271"
Then check the security/events view in the UI (or CLI logs). If nothing shows up, you’re usually testing the wrong host/port or bypassing the proxy.
When not to use this
- You need a full cloud WAAP / bot management suite
- You must stay on Nginx/Apache modules only
- You want multi-region active-active with a shared control plane on day one
For a homelab or a single production node where you already like Caddy semantics, the “one binary + CRS” shape is hard to beat.
Links
- Site: https://www.tiyisec.com/
- GitHub: https://github.com/zzmzm/tiyi
- Demo video: https://www.tiyisec.com/assets/video/tiyi-demo.mp4
If you’re comparing this to SafeLine/BunkerWeb/ModSecurity stacks, comment with your constraints (Docker OK? Caddy required? UI needed?) — happy to map tradeoffs.
Top comments (0)