Claws Up: Tightening Caddy + CrowdSec with OpenClaw
I use OpenClaw as my hands-on ops assistant when I need quick, precise fixes across a homelab. This week I asked it to review the health of my Caddy + CrowdSec stack, clean up a config drift issue, and improve my Telegram notifications so I wouldn’t need to open the CrowdSec dashboard every time an alert fires.
Here’s what it did and how I would repeat the process.
1) Verify the stack is healthy
OpenClaw ran a basic sanity check:
- Caddy bouncer is active and pulling decisions
- CrowdSec is parsing access logs normally
- Alerts and decisions are being generated as expected
That gave me confidence that the stack itself was working before I changed anything.
2) Fix a subtle coverage gap
I assumed CrowdSec was enforced on every virtual host, but the Caddyfile told a different story. Only one site had the crowdsec directive inside its server block.
OpenClaw updated each site to include the directive, so every vhost is now protected:
1alpha.example.com {
2 import logjson actual
3 crowdsec
4 route {
5 import sec-headers
6 reverse_proxy 172.10.10.10:8080
7 }
8}
Then it reloaded Caddy and confirmed the bouncer was still pulling decisions.
3) Enrich Telegram alerts with real attack context
CrowdSec already sends Telegram messages, but the default payload only tells you scenario + IP. I wanted:
- Target domain (which vhost)
- The exact URL (method + path)
- User-Agent
- ASN and country
OpenClaw updated the notification template to pull those fields from the alert metadata:
1format: |
2 {
3 "chat_id": "<chat_id>",
4 "text": "{{ range . -}}{{ $a := . -}}Scenario: {{ $a.GetScenario }} | {{ $a.GetScope }}:{{ $a.GetValue }}\nTarget: {{ $a.GetMeta \"target_fqdn\" }}\nRequest: {{ $a.GetMeta \"http_verb\" }} {{ $a.GetMeta \"http_path\" }}\nUser-Agent: {{ $a.GetMeta \"http_user_agent\" }}\nASN: {{ $a.GetMeta \"ASNNumber\" }} ({{ $a.GetMeta \"ASNOrg\" }})\nCountry: {{ $a.GetMeta \"IsoCode\" }}\nDecisions:\n{{ range $a.Decisions -}}- {{ .Value }} -> {{ .Type }} ({{ .Duration }})\n{{ end -}}---\n{{ end -}}",
5 "disable_web_page_preview": true
6 }
Finally, it triggered a test notification using a recent attack pattern so I could see the exact output in Telegram. Now I get domain + path + ASN + country at a glance.
Takeaways
- Don’t assume coverage—check each vhost.
- Enrich your alerts so the message contains everything you need for triage.
- Use OpenClaw for fast, safe changes when you already know what you want.
If you’re running Caddy + CrowdSec, these small tweaks make daily ops much easier and faster.
A quick reflection
This used to mean hours of Googling, reading config syntax, and trial‑and‑error debugging just to get it right. Now it’s a few minutes end‑to‑end, stable and reliable. This is what AI should feel like.