erik.log

I'm Erik, a systems engineer based in Helsinki. I write about Linux, infrastructure, containers, and whatever else I'm tinkering with. Mostly notes to my future self.

Why I Switched from Nginx to Caddy (and Switched Back)

I spent two weeks running Caddy on my production reverse proxy. The automatic HTTPS was genuinely nice, and the Caddyfile syntax felt refreshing after years of nginx config blocks. But once I needed more granular control over caching headers and upstream health checks, I found myself fighting the abstraction more than benefiting from it. Here's what I learned.

Minimal Docker Compose for Side Projects

Every time I spin up a new VPS for a small project, I end up writing the same boilerplate. So I made a template. The idea is simple: one compose file, locked-down defaults, and nothing you don't need.

services: app: image: myapp:latest restart: unless-stopped read_only: true security_opt: - no-new-privileges:true cap_drop: - ALL

I always start with read_only: true and drop all capabilities. You'd be surprised how rarely you actually need write access to the filesystem inside a container.

Wireguard Site-to-Site: Connecting Two Hetzner Boxes

I have two Hetzner VPS instances that need to talk to each other over a private network. Hetzner's vSwitch works, but it's region-locked. Wireguard solves this in about 20 lines of config per side. I'll walk through the setup, including persistent keepalive for NAT traversal and a systemd unit that restarts on failure.

TIL: systemd-resolved Was Eating My DNS

Spent an embarrassing amount of time debugging why my containers couldn't resolve internal hostnames. Turns out systemd-resolved was binding to port 53 on localhost, which conflicted with my Pi-hole container. The fix was simple once I found it, but the symptoms were confusing.

Hardening a Fresh Ubuntu Server in 2026

My checklist every time I provision a new box: SSH key only, fail2ban, unattended upgrades, UFW with default deny, and a few sysctl tweaks. Nothing groundbreaking, but I keep forgetting the exact sysctl values for TCP hardening, so I'm writing them down here. Also includes a small Ansible playbook if you want to automate it.

Monitoring with Prometheus + Grafana on a Budget

You don't need a Kubernetes cluster to benefit from proper monitoring. I run Prometheus and Grafana on a single 2GB VPS alongside my actual services. Here's how I keep resource usage under control with smart retention policies and recording rules, plus my dashboard for tracking container health.