/images/avatar.png

Break things. Fix them. Learn.

This site runs on an Intel NUC hosted at home, behind a standard fiber connection. Its main purpose is to serve as an experimentation ground for testing server configurations, automation scripts, and open source security tools.

Not a professional website — a homelab: we break things, fix them, and learn.

Migration in progress
The site is gradually migrating from Grav CMS to Hugo. Old URLs are preserved, but the visual rendering is evolving. If you spot a bug, report it.

🛠️ Tech stack

Tool Role Link
🔒 CrowdSec Community IDS/IPS Dashboard
☁️ Cloudflare CDN · WAF · DNS · DDoS Dashboard
📊 BetterStack Monitoring · Alerts · Logs Status page
🌐 Hugo Static site generator gohugo.io
🛡️ ModSecurity Local WAF · OWASP CRS 4.x OWASP CRS
nginx Reverse proxy · TLS 1.3 nginx.org

🌟 Don’t miss

Three articles that capture the spirit of this homelab:

📚 Full documentation is in Documentation and automation scripts in Scripts.

🐛 Found a vulnerability?

If you discover a bug, misconfiguration, or security vulnerability on this server, please report it. This homelab is public and I learn from my mistakes.

📨 Responsible disclosure: www.arleo.eu/security.txt

Any contribution to improving security is welcome.

CrowdSec AppSec + OpenResty: Modern WAF Without ModSecurity

After years running ModSecurity + OWASP CRS on nginx, I migrated arleo.eu to a more modern stack: CrowdSec AppSec on OpenResty. The result is a tighter inline WAF architecture — better integrated, easier to maintain, and fully coherent with the rest of the security stack.

Why Drop ModSecurity?

ModSecurity v2 is in maintenance mode. Managing OWASP CRS rules on classic nginx generates friction: frequent false positives, logs that are hard to correlate with CrowdSec, and a configuration spread across multiple tools with no unified view.

SRI on Hugo: automated hashes, auto-update and BetterStack alerting

Why SRI?

When your site loads resources from a third-party CDN — FontAwesome, Mermaid, Animate.css — you’re trusting an external party you have no control over. If jsdelivr.net gets compromised, or if a supposedly immutable version is silently mutated, your site can become an attack vector.

Subresource Integrity (SRI) solves this cleanly: every <link> or <script> tag carries an integrity="sha256-…" attribute that the browser verifies before executing the resource. If the hash doesn’t match, the browser blocks the load.

Postmortem: TypeIt broken by Mermaid in LoveIt theme

TL;DR

The LoveIt theme’s typewriter animation (TypeIt) stopped working on the home after adding Mermaid diagrams to posts. Cause: a #id-1 DOM selector shared between both libraries. When Mermaid finds an orphan block in a home summary, its initialization crashes, and the JS init chain stops before reaching TypeIt. Fix: add `

hugo-mcp Cloudflare plugin: smart cache purge

TL;DR

The Cloudflare plugin in hugo-mcp v2.0 implements 3 cache purge modes (full, partial, smart). The partial mode computes the linked URLs to invalidate (canonical + sitemap + RSS + listing + home) to preserve 95% of the CDN cache on every modification. Concretely: 6 URLs purged instead of wiping everything. This post details the computation, the pitfalls, and why smart became the default.

NUC Security Audit: ModSecurity Removed, 500 MB Recovered

⚡ TL;DR

A security stack audit on the homelab NUC reveals redundant double WAF inspection: ModSecurity + OWASP CRS load 11,872 rules into memory despite SecRuleEngine Off, running in parallel with CrowdSec AppSec which already covers the same surface. After removing the ModSecurity nginx module and five other targeted fixes, nginx drops from ~520 MB to ~27 MB PSS. Same security, memory footprint divided by 20.


🏗️ Architecture Before the Audit

The security stack had six stacked layers: