/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

ToolRoleLink
🔒 CrowdSecCommunity IDS/IPSDashboard
☁️ CloudflareCDN · WAF · DNS · DDoSDashboard
📊 BetterStackMonitoring · Alerts · LogsStatus page
🌐 HugoStatic site generatorgohugo.io
🛡️ ModSecurityLocal WAF · OWASP CRS 4.xOWASP CRS
nginxReverse proxy · TLS 1.3nginx.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.

Migrating Grav → Hugo: 32 files, 0 regression

TL;DR

arleo.eu had been running on Grav CMS for ~3 years: flat-file, PHP-FPM, ModSecurity, Cloudflare. Everything worked. But operational debt was piling up: PHP upgrades, Grav plugins to patch, TTFB creeping past 800ms on some pages.

I migrated to Hugo (Go-based static site generator) in two weeks, keeping the same URLs, the same content, and both languages FR/EN. Zero regression on SEO, Cloudflare indexing, or internal links. Here’s how.

Why Hugo

I had 3 criteria:

  1. Performance — Pure static. No PHP, no DB. nginx serves pre-generated .html directly.
  2. Security — Attack surface divided by 10. No more PHP-FPM, no server-side execution on public pages.
  3. Clean multilingual — Hugo natively supports i18n via the index.{lang}.md convention (page bundles).

Hugo checks all the boxes. Alternatives evaluated: Eleventy (JS, but less mature i18n), Zola (Rust, awesome, but fewer themes), Gatsby (too heavy for a homelab).

Hugo MCP Server: Connecting Claude.ai to a Static Hugo Site

⚡ In short

Connect Claude.ai to a Hugo site hosted in a KVM VM in 30 minutes: a FastAPI server exposes 6 MCP tools (read, create, modify, delete pages, rebuild the site) via JSON-RPC 2.0, an OAuth proxy reuses existing infrastructure, and every modification automatically triggers a Hugo rebuild + Cloudflare cache purge.

The code is available on GitHub:

🧠 Why

Anthropic’s MCP (Model Context Protocol) allows Claude.ai to connect to external data sources via standardized tools. Unlike Grav CMS which is dynamic (PHP), Hugo generates pure static HTML — making content management via MCP even more powerful: every modification is compiled and deployed instantly.

KVM Media VM: migrating Sonarr, Radarr and SABnzbd into an isolated VM

⚡ TL;DR

Migrating the media stack (Sonarr, Radarr, SABnzbd) into a dedicated KVM VM running Ubuntu 24.04: security isolation, easy snapshots, QNAP NFS mounted inside the VM, nginx reverse proxy on the host. The migration fully preserves SQLite databases and existing configuration.

Target stack:

  • 🖥️ Host: NUC8i3BEH, Ubuntu Server, nginx reverse proxy, Plex (GPU transcoding)
  • 📦 VM media-vm: Ubuntu 24.04, 2 vCPU, 8 GB RAM, 120 GB (X5 NVMe), QNAP NFS
  • 🎬 Migrated services: Sonarr (port 8989), Radarr (port 7878), SABnzbd (port 6789)

🧠 Why isolate the media stack in a VM

Sonarr, Radarr and SABnzbd present a significant attack surface: network calls to external indexers, post-download script execution, filesystem access to the media library. Confining them in a VM provides:

Hugo on KVM: Installing an Ubuntu VM for a Static Site

⚡ In short

Progressive migration from Grav CMS to Hugo — a static site generator. The goal is to isolate Hugo in a dedicated KVM VM on the NUC8i3BEH, with nginx on the host as a reverse proxy. The generated static site is served by nginx inside the VM — no PHP, no database, no application attack surface.

  • 🖥️ Host: NUC8i3BEH Ubuntu 24.04 — nginx proxy + KVM
  • 🗄️ VM disk: Samsung X5 external NVMe (exFAT → ext4 loop image)
  • 🌐 Access: hugo-test.arleo.eu
  • 🎨 Theme: LoveIt

🧠 Why

Grav CMS is excellent but relies on PHP — a non-negligible attack surface. Hugo generates pure static HTML: no PHP, no database, no application vulnerability. Performance is also radically better — HTML is served directly by nginx without dynamic processing.

Grav MCP Server: connect Claude.ai to your website in 30 minutes

⚡ In short

Connect Claude.ai to your Grav website in 30 minutes: a PHP plugin exposes 9 tools (read, create, update, delete pages, manage plugins) via JSON-RPC 2.0, a FastAPI proxy handles OAuth 2.1 authentication, and nginx bridges the internet to your server. Result: Claude can read and modify your site content directly from a conversation.

Code available on GitHub:

🧠 Why

Anthropic’s MCP (Model Context Protocol) allows Claude.ai to connect to external data sources via standardized tools. Until now, no MCP plugin existed for Grav CMS.

Grav Google Indexing Plugin: automatically submit pages to Google

⚡ In short

Following the IndexNow plugin (Bing/Yandex), this second plugin completes the SEO pipeline by submitting modified pages directly to the Google Indexing API — with no Composer dependency, using a RS256 JWT signed in pure PHP from a Google Cloud service account.

Source code available on GitHub:

🧠 Why

IndexNow covers Bing and Yandex, but Google does not support IndexNow. To notify Google instantly, you need to use its dedicated API: Google Indexing API v3.

Hugo