I Hardened This VM by Hand. Lynis Scored It 68/100.

A while back I hardened this Debian VM by hand — patched it, cut the attack surface, put a default-deny host firewall in front of it, sandboxed the custom services. I audited my own box and fixed the drift I found. The problem with auditing your own box is that you grade your own homework. You check the things you already think to check. So this time I handed the job to something that has no idea what I meant to do and only reports what’s actually there: Lynis, the system-auditing tool from CISOfy. It ran 274 tests and gave the VM a hardening index of 68 / 100. ...

20 July 2026 · 7 min
Grafana Explore showing pfSense firewall logs flowing through Loki, with a log-volume chart above

Building a Homelab SIEM with Loki — Reading My Logs Instead of Hoping

I had dashboards showing me numbers — CPU, memory, network throughput. What I didn’t have was any way to answer “what actually happened?” When did someone try to log in? What did the firewall block? Those answers live in logs, and my logs were scattered across machines, unread. This post is how I pulled them into one searchable place. That’s a SIEM — Security Information and Event Management — and you can build a simple one at home. ...

19 July 2026 · 7 min
Obsidian with the Claudian sidebar open — Claude reformatting a SIEM runbook with tool calls visible

Claudian: A Claude Agent Inside My Obsidian Vault

My study notes live in Obsidian. My agent lives in a terminal. For a month those were two separate worlds: when I wanted Claude to clean up the vault, I drove Claude Code at it from outside — point the CLI at the folder, describe the job, check the result in Obsidian afterwards. Claudian collapses that into one window. It’s an open-source community plugin that embeds Claude Code inside Obsidian as a sidebar — the vault becomes the agent’s working directory, and the agent becomes part of the note-taking app. ...

18 July 2026 · 4 min

Metrics You Have to Remember to Look At Aren't Monitoring

I’d had Grafana dashboards for months. What I didn’t have was anything that told me when something broke — I had to remember to look. This is the alerting layer that fixes that, built on top of the existing Prometheus stack, plus the three things that got in the way. Stack: Prometheus · Alertmanager · ntfy · Docker 1. The gap I’d been ignoring My lab had a healthy observability stack: Prometheus scraping metrics, node_exporter for the host, snmp_exporter pulling throughput off pfSense, all drawn in Grafana. It looked complete. ...

18 July 2026 · 12 min

A Backup You Haven't Restored Is a Hypothesis

The identity provider quietly became load-bearing and had no backup. Building one taught me more about database internals than building the identity provider did. Stack: Bash · Postgres · SQLite · age · cron · OneDrive 1. Purpose The identity provider started as a nice-to-have. Single sign-on for a dashboard — pleasant, not critical. Then it took over the firewall’s login. That’s the moment the risk profile changed, and it changed without any decision being made about it. Nobody sat down and said “let’s make the firewall depend on this container.” It happened one integration at a time, and the dependency graph grew quietly underneath. ...

16 July 2026 · 9 min
Logged into pfSense as an identity-provider account over LDAP

Making the Firewall Authenticate Against My Identity Provider — and Proving the Bug Wasn't Mine

Bringing pfSense’s admin login into Authentik with MFA — via RADIUS, which turned out to be broken upstream, and then via LDAP, which wasn’t. This is as much about how you prove a bug isn’t yours as it is about the build. Stack: Authentik · pfSense · Docker · LDAP · RADIUS 1. Purpose With an identity provider already running and Grafana logging in through it, the obvious next question was: how far does this go? ...

16 July 2026 · 13 min
Grafana's login page with a Sign in with authentik button

One Login, MFA Everywhere: Adding an Identity Provider to the Homelab

Deploying Authentik as a self-hosted identity provider, and wiring Grafana into it with OIDC — so a service that has never heard of MFA suddenly requires it. Stack: Authentik · Caddy · Grafana · Docker · Debian 1. Purpose Every self-hosted service arrives with its own login. Ten services means ten accounts, ten passwords, and ten places to forget to enable MFA. Worse, some services have no authentication at all and just quietly assume nobody hostile is on your network. ...

15 July 2026 · 9 min
The self-hosted Vaultwarden vault, logged in and showing its security reports

Self-Hosting a Password Manager the Hard Way: Vaultwarden, Caddy, and Three Firewalls Fighting

Building a self-hosted password vault with a genuinely trusted TLS certificate and zero inbound ports open to the internet — and the four-layer debugging session that stood between me and a working container. Stack: Debian 13 · Docker · Caddy (custom build) · Vaultwarden · pfSense · WireGuard · DuckDNS 1. Purpose Self-hosted services are easy to do badly. It’s trivial to run a container, forward a port, click through a certificate warning, and call it done — and end up with something less secure than the cloud service you replaced. ...

15 July 2026 · 11 min
Before/after: GitHub repo → Cloudflare Pages → billalrehmani.pages.dev, versus the same build now served at the registered domain billsblog.dev

Registering My Own Domain: From a Pages Subdomain to billsblog.dev

The blog you’re reading just moved house. Same content, same build, the same Cloudflare Pages underneath — but the address on the door changed from billalrehmani.pages.dev to a domain that’s actually mine: billsblog.dev. Why bother — it already worked billalrehmani.pages.dev was fine. It served over HTTPS, it was fast, it was free. But pages.dev is Cloudflare’s namespace, not mine. For a portfolio I link from LinkedIn and want people to remember, “billalrehmani-dot-pages-dot-dev” is a mouthful and a borrowed address. Owning the domain means owning the identity — and, as it turned out, a bit more control over the security posture too. ...

13 July 2026 · 5 min
Before/after diagram: GitHub repo → GitHub Actions → github.io, versus GitHub repo → Cloudflare Pages → pages.dev with security headers

Moving the Blog off GitHub Pages — for Real Security Headers

The blog you’re reading changed builders. The git push that publishes it is identical; what runs on the other end isn’t. It used to be a GitHub Actions job that built the site and served it from yourlocalunemployed.github.io. Now Cloudflare Pages builds from the same repo and serves it at billalrehmani.pages.dev. I didn’t move for speed or for a nicer dashboard. I moved because GitHub Pages won’t let me set HTTP response headers, and for a blog that’s meant to be a security portfolio, that was the one limit I couldn’t design around. ...

12 July 2026 · 5 min
All three VLAN interfaces online at their gateway IPs on pfSense

Virtual VLAN Segmentation on pfSense — Three Isolated Zones, No Managed Switch

A flat network trusts every device on it equally. A smart plug, a guest’s phone, and the machine holding my important data all share one space — so if any one of them is compromised, the attacker can reach the rest. Network segmentation breaks that flat space into separate zones and controls what may cross between them, shrinking the blast radius of any single compromise. I wanted to build that properly — VLANs and a firewall — on VMware Workstation with pfSense CE, and design three zones at deliberately different trust levels: ...

12 July 2026 · 8 min
WireGuard handshake established over mobile data

Self-Hosted WireGuard Through a Nested Firewall — and the Four-Layer Debug to Make It Work

My lab is deliberately isolated — an automation VM (CLAUDDEB) sits behind a virtual pfSense firewall on a segment (10.10.0.0/24) that my home network can’t reach. That isolation is great until you’re out of the house and want to check your Grafana dashboards, which only listen inside that segment. I already use Tailscale for casual remote access, and I’ll be honest up front: for pure convenience, Tailscale wins — it punches through NAT automatically with zero firewall work. But this project wasn’t about convenience. It was about building the thing Tailscale is made of. Tailscale is WireGuard under the hood; hand-rolling raw WireGuard on pfSense teaches you how VPNs actually work — keys, peers, routing, firewall rules, NAT — at a level the managed tool deliberately hides. So I built it from scratch, kept Tailscale as my daily driver, and got a genuinely brutal debugging lesson in the process. ...

11 July 2026 · 7 min
Terminal summary of the VM hardening result

Hardening My Debian Home-Lab VM — Even Behind pfSense

My Debian automation VM already sits behind a pfSense firewall with egress containment — it can reach the internet but not my home network. So why harden the VM itself? Because “behind a firewall” is doing less work than it sounds. Two paths reach into the VM without ever crossing pfSense, and an honest audit of my own box turned up drift I didn’t expect. This is the write-up: what the audit found, what I changed, and the systemd sandbox mistake that quietly broke a service. ...

7 July 2026 · 6 min
A note pushed from the laptop appearing on the hub via get_recent

Syncing Claude Code Across Devices with a Custom MCP Hub over Tailscale

I run Claude Code on two machines: the Debian VM in my home lab (always on) and a Debian laptop (sleeps, roams, follows me to campus). I wanted the laptop to push notes, facts, and findings into a central store on the VM — from any network — so the home-lab agent could pick them up later. Claude Code’s built-in Remote Control turns a second device into a remote window onto one session. That’s not what I wanted. I wanted both machines to stay fully independent agents, linked through a shared tool. So I built a small MCP server on the VM and pointed the laptop’s Claude Code at it: the hub becomes just another tool the laptop can call. ...

7 July 2026 · 6 min
Grafana Node Exporter dashboard for the Debian VM

Building a Prometheus and Grafana Observability Stack for My Home Lab

My LaMetric display gives an at-a-glance read on the lab, but it’s a spot reading with no history — good for “is something on fire right now,” useless for “what happened overnight.” This project adds the layer underneath: a Prometheus + Grafana stack that scrapes my hosts continuously, stores the history, and draws real dashboards. Two targets: CLAUDDEB (my Debian automation VM) and my pfSense firewall, reusing the exact SNMP setup from the pfSense post — just pointed at something far more capable than a 37-pixel display. ...

6 July 2026 · 6 min
pfSense WAN byte counter climbing under SNMP polling

Implementing LaMetric TIME to Network Part 2

In part 1 I got a LaMetric Time showing live health from my home lab over MQTT, so it worked across my network isolation — CPU, memory, disk, uptime, and the automation VM’s own traffic, all from a single Debian box. Useful, but those were really that box’s stats. The frame the display was named for is my network’s throughput — the traffic crossing my firewall — and that data lives on pfSense, not the Debian box. This is the follow-up: pulling real WAN in/out rates off pfSense over SNMP and putting them on the display. It’s shorter than the MQTT build, because the pipeline already exists; all I’m adding is a new data source. Getting numbers out of pfSense is the part worth writing down. ...

6 July 2026 · 8 min
A LaMetric Time smart display

Implementing LaMetric TIME to Network

I picked up a LaMetric Time — an 8x37 pixel smart display — and after locking it down on an isolated guest network, the next move was to make it useful: live health from my home lab. CPU, memory, network throughput — the numbers worth a glance. The interesting part is that a constraint I’d deliberately built into my network dictated the whole architecture. This is the write-up: the design decision, the pipeline, and the gotchas — because the gotchas are the useful part. ...

5 July 2026 · 7 min
SPT-AKI gameplay

Porting a Mod Through Claude Fable 5

This is my second SPT mod port — the first was BiggerBang, a full trader mod. This one is smaller in scope, but I ran the entire process through Claude Fable 5 in Claude Code: extraction, code review, the rewrite, and the debugging. My role was direction and judgement calls; the model did the implementation. The most interesting part of this post is what it found. ...

3 July 2026 · 5 min
The Spec Grabber HTML report

Created a SystemInfo Grabber Program with Claude AI

I wanted a small desktop tool that captures a snapshot of a machine — hardware, resource usage, network state — and writes it to a styled HTML report viewable in any browser. Useful for quick system audits and for keeping a record of a machine’s specs over time. I built it in one Claude Code session (Opus 4.8) on my Debian 13 laptop, then packaged it for Windows as well. ...

2 July 2026 · 4 min
pfSense dashboard after the rebuild

Debugging a Dead VMware NAT and Hardening My pfSense Containment Lab

I run my Claude Code work inside a Debian 13 VM (CLAUDDEB) on VMware Workstation Pro 17.6.4, with a pfSense 2.8.1 VM in front of it as a virtual router and firewall. pfSense exists in this setup for containment: if something on the Debian VM misbehaves — a prompt injection, a compromised dependency — it must not be able to reach my PC, my router’s admin page, or anything else on the home network. ...

2 July 2026 · 7 min
Escape from Tarkov

Porting a TypeScript Game Mod to C# and Hardening It for Community Release

SPT-AKI (Single Player Tarkov) 4.0 rewrote the entire server from JavaScript/TypeScript to C#/.NET. Every SPT 3.x mod — loaded as .ts/.js files with a package.json — had to be rebuilt as a compiled .dll against the new C# API. The mod I ported is BiggerBang, written for SPT 3.9 by Thunderbags, whose author had gone inactive. It adds a full custom trader (Boris Bangski) with an extensive inventory — ammo, weapons, magazines, grenades, injectors, containers, armour, equipment sets — and 13 quests. I ported it to C# for SPT 4.0.x, verified it against 4.0.13, fixed five bugs found along the way, and released it to the community. ...

29 June 2026 · 3 min
Arcadyan HWG2025 router

Hardening and Segmenting My Home Network on an Arcadyan HWG2025

This is a small home network — one router, a handful of devices. The point wasn’t complexity; it was applying the same discipline you would to a small office or lab environment. Treated that way, it doubles as practical study for Network+ and Security+. The router is an Arcadyan HWG2025 — the NBN-issued unit, Wi-Fi 7 with MLO, around 500 Mb down. An ISP router doesn’t give you much room to move, but it gives you enough to do this properly. ...

29 June 2026 · 3 min
The Hugo blog running on GitHub Pages

Self-Hosting a Hugo Blog with a Claude Code Publishing Pipeline

The blog you’re reading was published by the pipeline this post describes. Why Hugo, and why self-hosted I needed somewhere to document real technical work — networking, security, mod projects — that I could point to from LinkedIn. Hosted platforms were out: no content ownership, paywall friction, someone else’s branding. Hugo won on attack surface. It’s a single Go binary — no Node, no node_modules, no npm dependency tree to patch and audit. For a security portfolio, the blog itself should be as defensible as the work it documents. It builds to plain static files, so serving is trivial; the trade-off is owning uptime and patching, which for this use case is a feature. ...

29 June 2026 · 3 min