Head of Hybrid Platform Services & Datacenter at Dirk Rossmann GmbH. Background in AI research, enterprise infrastructure, and platform engineering.

E-mail: web1 [at] michaelkoester [dot] de

About me →

Making Rspamd's Blocklists Actually Work: A Private Unbound Resolver + Spamhaus DQS

Here’s a failure mode that hides in plain sight: if your spam filter resolves DNS through a public resolver like Google or Cloudflare, most DNS blocklists silently refuse to answer it. Spamhaus, URIBL, SURBL and friends all do this. Your filter keeps running, adds a few headers, and quietly lets listed senders through — because the lookups that should have flagged them never returned a useful answer.

The fix has three parts: run your own recursive resolver, subscribe to Spamhaus’s free Data Query Service (DQS), and set a reject policy that’s aggressive on definitive signals without inviting false positives. This post is the complete, reproducible setup. My stack is Postfix + Dovecot + Rspamd + ClamAV on MicroShift, managed with Flux; domains, keys and IPs are anonymized, but everything else is exact.

[Read More]

Claude Code as a Server Admin: From Migration to Daily Operations

Earlier this year I migrated my home server from Gentoo + Docker to Fedora Server 43 + MicroShift. Eight services: a full mail stack (Postfix, Dovecot, Rspamd, ClamAV), Nextcloud with Collabora Online, Vaultwarden, Paperless-NGX, Pihole, monitoring via Grafana Cloud — all on a single VPS, managed via GitOps with Flux CD.

Claude Code was my primary tool throughout. Not as a code generator I reviewed at arm’s length, but as something closer to a co-admin that I paired with in real time. This post is an honest look at what that actually looks like, with concrete examples.

[Read More]

Layered Backup for a Kubernetes Homelab: snapper, btrbk, and a Raspberry Pi

Running Kubernetes on a single VPS is convenient — but it concentrates risk. Every application, every PVC, every bit of state lives on one machine. If that machine disappears, so does everything else. Backup is not optional here; it’s the difference between a recoverable incident and a weekend rebuild.

This post explains the backup strategy I settled on for my homelab and why the layers are the way they are. The full technical reference — including step-by-step restore commands — is in the homelab documentation.

[Read More]

Hardening a Self-Hosted Mail Server: fail2ban, Postfix, and Dovecot

My home server runs a full mail stack — Postfix, Dovecot, Rspamd, ClamAV — on MicroShift. It’s exposed directly to the internet on ports 25 and 587. That means it gets attacked. Here’s how I protect it, what the attacks look like in the logs, and how I recently tightened the configuration after spotting a gap.

The Threat Landscape

Two distinct attack types show up regularly in the logs:

1. SASL Brute-Force — Attackers try username/password combinations via SMTP AUTH or IMAP. The pattern: multiple IPs, each trying a different username, typically in parallel waves.

[Read More]

One Month of MicroShift: A Homelab Retrospective

One month in. The migration from Gentoo + Docker to Fedora Server 43 + MicroShift is complete and everything is running in production: mail stack, Nextcloud, Vaultwarden, Paperless, Collabora Online, monitoring, and this website — all on a single VPS, orchestrated by Kubernetes, managed by GitOps. So far, so good.

But let me be honest about the complexity. The full documentation runs to eight major sections covering base system, storage, firewall, WireGuard, MicroShift, GitOps, TLS, and eight services with their operational scripts. Behind that documentation are 368 commits across two repositories in four weeks — 232 in the GitOps manifests repo alone, 136 in the runbook. That’s not a “deploy and forget” setup. Every one of those commits represents something that had to be figured out, fixed, or explicitly decided.

[Read More]

Btrfs vs. OpenZFS: Why Snapshot Space Accounting Is Hard

Both Btrfs and OpenZFS are copy-on-write filesystems with native snapshots. On the surface they look similar. Under the hood, they handle one fundamental question very differently: who owns a block of data, and how do you account for it when snapshots share it?

I ran into this the hard way. Enabling Btrfs quotas on a system with hundreds of snapshots crashed my Kubernetes cluster every hour — reliably, for the same reason, until I figured out what was happening.

[Read More]

Running a Self-Hosted Cloud on MicroShift

My home server runs a full self-hosted stack on a single VPS: Nextcloud, Vaultwarden, Paperless-NGX, a complete mail stack (Postfix + Dovecot + Rspamd + ClamAV), Collabora Online, and monitoring via Grafana Cloud — all on MicroShift, managed by Flux CD, behind a WireGuard VPN.

The whole thing runs on Btrfs with hourly snapshots sent to a Raspberry Pi. A GitHub Action creates a snapshot before every GitOps push. grub-btrfs registers every snapshot in the GRUB menu. If something breaks, rolling back takes thirty seconds.

[Read More]