Blog

The homelab

TL;DR: Two Raspberry Pi 5s under the TV stand. One runs Plex, the other hosts this website with a self-hosted GitHub Actions runner. Tailscale for private access, Cloudflare Tunnel so the public site needs zero open ports.

Hardware

Two Raspberry Pi 5s, one with 4 GB and one with 16 GB RAM. Both boot from NVMe over PCIe Gen 3. The NVMe matters more than I expected coming from SD card boot: Docker builds, git operations, anything disk-heavy is noticeably faster. Not a marginal difference.

The 4 GB one runs Plex. The 16 GB one does everything else.

Plex

The 4 GB Pi runs Plex Media Server with a decent-sized movie and TV library. Direct play keeps the CPU near idle, so 4 GB is plenty as long as you're not transcoding, and in 2026 clients handle basically everything natively so that's rarely an issue.

This website

The 16 GB Pi hosts jonasfoyn.com. Stack: Astro 5 (static HTML, zero JS by default), served by nginx in Docker. Deploys on push to main through a GitHub Actions self-hosted runner that lives on the Pi. It builds its own Docker image and restarts its own container.

Astro was a deliberate pick. Static HTML under nginx on constrained hardware is essentially unkillable. Nothing to crash, nothing to scale, nothing to go wrong at runtime.

Getting in from outside

Tailscale for everything private. Both Pis and my Mac are in the same mesh VPN, so SSH from anywhere works without touching the router. That's how I manage the machines and how I access Plex remotely without going through Plex's own relay servers.

Cloudflare Tunnel for the public website. A daemon on the Pi opens an outbound connection to Cloudflare; traffic hitting jonasfoyn.com routes through that tunnel to nginx. Zero inbound ports on the Pi, since the connection is always initiated from the Pi's side.

Why bother

Plex without licensing risk. A website on hardware I physically own. Both Pis together draw less power than a lightbulb.

Beyond that: dealing with real networking constraints, making things reliable enough to run unattended. It's good practice, and you learn things that don't show up when someone else is managing the hard parts.

The more interesting layer on top of all this (running Claude Code as an autonomous agent on the Pi, automated PR reviews, a system that accumulates knowledge across sessions) is in the follow-up post.