RSSAmplifier

Blog

blog.thms.uk

Michael's blog

blog.thms.ukRSS feed ↗25 posts

Latest posts

Reducing Docker deploy downtime for Laravel and FrankenPHP

Every docker compose up -d took my site down longer than I liked. Three fixes: bake caches into the image, do the volume setup once, and split the deploy so the old container keeps serving.

When restart: always isn't enough: making Compose stacks recover at boot

Restart policies only cover containers that have already started. When AppArmor blocked dockerd's default profile at boot, thirteen containers stayed down for four hours. Here's my fix.

Exempting an IP from Mastodon's rate limits

My FediFetcher install kept tripping my own instance's rate limits. A Rack::Attack initialiser let me safelist its IP, once I'd worked out which IP Rails actually sees.

Setting up OIDC for Mastodon with Pocket ID

Setting up Pocket ID as an OIDC provider for a self-hosted Mastodon instance, including the undocumented settings needed to link an existing account without locking yourself out.

TIL: MySQL view security context after a migration

Dumped a database, imported it on a new server, and suddenly couldn't select from my view. Turns out views run as whoever created them, and mine no longer existed.

Everything I self-host (and a few things I don't)

A run-through of everything I self-host for myself and my family - from Headscale and Forgejo to Mastodon and Home Assistant - plus the few things I've decided not to.

Self-hosting a static site using Forgejo, Headscale, and Caddy

Self-hosting a static blog with push-to-deploy: Forgejo Actions ships the site over a Tailscale/Headscale tailnet to a Caddy reverse proxy, with no long-lived SSH keys to manage.

Using a Tailscale exit node on a Docker host

How to stop a Tailscale exit node from breaking Docker container networking, using Linux policy routing and a small systemd unit to make the fix permanent.

Moving Mastodon to Docker Compose

I finally moved my Mastodon server to Docker. Here's the full migration: inventorying dependency versions, keeping config in git, and importing the postgres dump and redis snapshot.

A multi-stage Dockerfile for Laravel and FrankenPHP

A walkthrough of a four-stage Dockerfile that ships a lean Laravel 13 image on FrankenPHP, plus the entrypoint and Compose services to actually run it.

Setting up a free Oracle VPS as a reverse proxy

Set up a zero-cost reverse proxy: an Oracle Always Free VPS running Caddy, linked to home origin servers via Tailscale, with automatic HTTPS and one-line site additions.

Auto-Deploying a static site from Forgejo to CloudFlare Pages

A step-by-step guide to deploying a static site from a self-hosted Forgejo instance to CloudFlare Pages, using a Forgejo Action that redeploys automatically on every push to main.

Re-verifying failed backups with Proxmox Backup Server

A simple script to re-verify failed backups in Proxmox Backup Server

FreshRSS mobile improvements

Using FreshRSS's Custom CSS and JS extensions to improve the mobile experience: flex-based multi-line article layout, summary spacing, and scroll-aware footer.

Self-Hosting Mastodon Behind Cloudflare Tunnel

A step-by-step guide to running Mastodon behind a Cloudflare Tunnel - ideal if you're self-hosting on a domestic connection without a static IP

Setting Up BIMI for Your Email

A step-by-step guide to setting up self-asserted BIMI: the DNS standard that puts your brand logo in recipients' inboxes, no certificate required.

On Serving Markdown to AI Agents

Cloudflare and Spatie have both shipped tools to serve Markdown to AI agents. I tried it - and discovered ChatGPT silently rejects text/markdown responses entirely.

Adding Plausible to Uptime Kuma Status Page

Struggling to connect Plausible to Uptime Kuma’s status page? The required Analytics ID and Script URL aren’t obvious - here’s what they actually are.

Investigating the performance of Laravel's `whereIn` vs `whereIntegerInRaw`

Revisiting a classic Laravel tip: does `whereIntegerInRaw()` outperform `whereIn()` in 2026?

Adding Plausible to Mastodon Using nginx `sub_filter`

Injecting Plausible Analytics into Mastodon using nginx sub_filter, CSP header overrides, and inline script hashes - plus why doing this is probably a bad idea.

Using Pi-hole as a DNS Server for my Tailnet

Use Pi-hole as a DNS server across your entire Tailnet with Tailscale, without forcing all traffic through an exit node. Ad blocking and internal DNS everywhere.

Configuring a Custom Block Page for Pi-hole

Set up a custom Pi-hole block page so users know when a domain is being filtered. It’s easy to enable and provides helpful context for anyone on your network.

Seeing the Full Conversation: Fetching Replies on Mastodon

Mastodon doesn't always show replies to posts from other instances. This post explores several ways to improve reply visibility and make conversations feel more complete.

Upgrading Mastodon from PostgreSQL 15 to PostgreSQL 17

Upgrading Mastodon’s database from PostgreSQL 15 to 17 on Ubuntu 24.04 is fast and easy using `pg_upgradecluster` with link mode. Here’s a quick guide with steps, tips, and cleanup.

OpenAI's crawler is overriding your Sentry sampling rate

After days of debugging unexplained span usage in Sentry - despite an ultra-low sampling rate - I discovered `traceparent` headers in requests traced back to OpenAI. Turns out, it's always AI.