<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Mattias Geniar on ma.ttias.be</title><link>https://ma.ttias.be/</link><description>Recent content in Mattias Geniar on ma.ttias.be</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><managingEditor>mattias@ma.ttias.be (Mattias Geniar)</managingEditor><webMaster>mattias@ma.ttias.be (Mattias Geniar)</webMaster><lastBuildDate>Mon, 22 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://ma.ttias.be/index.xml" rel="self" type="application/rss+xml"/><item><title>Dealing with concurrent bridge-network creates &amp; host-port races in Docker</title><link>https://ma.ttias.be/docker-bridge-network-host-port-races/</link><pubDate>Mon, 22 Jun 2026 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/docker-bridge-network-host-port-races/</guid><description>&lt;p&gt;I&amp;rsquo;ve been moving our CI off GitHub-hosted runners onto our own arm64 hardware. The plan was straightforward: a pool of ephemeral runners on a dedicated CI box, and each test shard spins up its own MySQL, Redis, and ClickHouse as service containers, all under rootless Docker.&lt;/p&gt;</description></item><item><title>Letting Cloudflare serve Brotli-compressed data with nginx</title><link>https://ma.ttias.be/letting-cloudflare-serve-brotli-with-nginx/</link><pubDate>Mon, 15 Jun 2026 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/letting-cloudflare-serve-brotli-with-nginx/</guid><description>&lt;p&gt;Google PageSpeed flagged a stylesheet on ohdear.app the other day: &lt;code&gt;front.css&lt;/code&gt;, the bundle for its public-facing pages. That surprised me, because Cloudflare sits in front of ohdear.app and Cloudflare does Brotli, and a Brotli&amp;rsquo;d copy of that file is around 40 KB. Browsers were downloading just over 50 KB of gzip instead. So why wasn&amp;rsquo;t Brotli kicking in?&lt;/p&gt;</description></item><item><title>Linux debugging tools I use daily</title><link>https://ma.ttias.be/linux-debugging-tools-i-use-daily/</link><pubDate>Fri, 12 Jun 2026 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/linux-debugging-tools-i-use-daily/</guid><description>&lt;p&gt;Every server I run, including the fleet behind &lt;a href="https://ohdear.app" target="_blank" rel="noopener noreferrer"&gt;Oh Dear&lt;/a&gt;
&amp;rsquo;s uptime checks, has the same set of debugging tools installed before anything goes wrong. Not because the application needs them, but because the one time you reach for &lt;code&gt;strace&lt;/code&gt; is at 2am, the box is misbehaving, and &lt;code&gt;apt install&lt;/code&gt; is the last thing you want to be doing while you work out what broke.&lt;/p&gt;</description></item><item><title>The backup SSH daemon I run before every do-release-upgrade</title><link>https://ma.ttias.be/backup-sshd-do-release-upgrade/</link><pubDate>Wed, 10 Jun 2026 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/backup-sshd-do-release-upgrade/</guid><description>&lt;p&gt;I spent a chunk of the last few weeks upgrading a fleet of Ubuntu servers in place, one LTS to the next, with &lt;code&gt;do-release-upgrade&lt;/code&gt;. Dozens of boxes, mostly stateless, mostly boring once you&amp;rsquo;ve done the first few.&lt;/p&gt;</description></item><item><title>AI is a confidence booster</title><link>https://ma.ttias.be/ai-is-a-confidence-booster/</link><pubDate>Tue, 09 Jun 2026 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/ai-is-a-confidence-booster/</guid><description>&lt;p&gt;&lt;a href="https://www.acquisition.com/bio-alex" target="_blank" rel="noopener noreferrer"&gt;Alex Hormozi&lt;/a&gt;
has a solid definition of &lt;em&gt;confidence&lt;/em&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You don’t become confident by shouting affirmations in the mirror, but by having a stack of undeniable proof that you are who you say you are.&lt;/p&gt;</description></item><item><title>Transcribing my old podcast locally with open-source AI</title><link>https://ma.ttias.be/transcribing-syscast-with-local-ai/</link><pubDate>Tue, 09 Jun 2026 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/transcribing-syscast-with-local-ai/</guid><description>&lt;p&gt;Back in 2016 and 2017 I recorded a podcast called &lt;a href="https://ma.ttias.be/syscast/"&gt;Syscast&lt;/a&gt;
: interviews with people I admired in the Linux, open source and infrastructure world. &lt;a href="https://ma.ttias.be/syscast/1-matt-holt-creator-caddy-webserver/"&gt;Matt Holt about Caddy&lt;/a&gt;
, &lt;a href="https://ma.ttias.be/syscast/4-curl-libcurl-future-web-daniel-stenberg/"&gt;Daniel Stenberg about curl&lt;/a&gt;
, &lt;a href="https://ma.ttias.be/syscast/3-managing-secrets-vault-seth-vargo/"&gt;Seth Vargo about Vault&lt;/a&gt;
, and a handful more. Ten episodes, roughly ten hours of audio, and then life got in the way and I put it on pause.&lt;/p&gt;</description></item><item><title>Configuring Varnish on systemd in 2026: drop-in overrides, not varnish.params</title><link>https://ma.ttias.be/varnish-systemd-drop-in-overrides-2026/</link><pubDate>Mon, 08 Jun 2026 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/varnish-systemd-drop-in-overrides-2026/</guid><description>&lt;p&gt;Back in 2015 I wrote about &lt;a href="https://ma.ttias.be/running-varnish-4-x-on-systemd/"&gt;running Varnish 4.x on systemd&lt;/a&gt;
, when the RedHat-family packages moved your startup options out of &lt;code&gt;/etc/sysconfig/varnish&lt;/code&gt; and into a new &lt;code&gt;/etc/varnish/varnish.params&lt;/code&gt; file that the unit sourced.&lt;/p&gt;</description></item><item><title>Debugging cookie stripping in Varnish: client vs backend request in 2026</title><link>https://ma.ttias.be/debugging-varnish-cookie-stripping-2026/</link><pubDate>Sun, 07 Jun 2026 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/debugging-varnish-cookie-stripping-2026/</guid><description>&lt;p&gt;A long time ago I wrote a &lt;a href="https://ma.ttias.be/varnish-tip-see-cookies-stripped-vcl/"&gt;Varnish tip about seeing which cookies get stripped in your VCL&lt;/a&gt;
. The idea is still one of the most useful things you can do with &lt;code&gt;varnishlog&lt;/code&gt;: compare what the browser sent against what reached your backend, so you can confirm your cookie-stripping rules do what you think.&lt;/p&gt;</description></item><item><title>The ghost domain problem in DNS, and what we're doing about it</title><link>https://ma.ttias.be/the-ghost-domain-problem-in-dns/</link><pubDate>Sat, 06 Jun 2026 10:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/the-ghost-domain-problem-in-dns/</guid><description>&lt;p&gt;I wrote a piece over on the Oh Dear blog about a failure mode that most uptime monitoring gets wrong: a domain gets pulled from its registry&amp;rsquo;s zone, but its authoritative nameservers keep answering, and cached resolvers happily serve the stale delegation for days. Your monitoring says green. The domain is gone.&lt;/p&gt;</description></item><item><title>Reading the Varnish log in 2026: varnishlog -q, -g grouping and the VSL query language</title><link>https://ma.ttias.be/reading-the-varnish-log-vsl-queries-2026/</link><pubDate>Sat, 06 Jun 2026 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/reading-the-varnish-log-vsl-queries-2026/</guid><description>&lt;p&gt;Years ago I posted a handful of &lt;a href="https://ma.ttias.be/useful-varnish-3-0-commands-one-liners-with-varnishtop-and-varnishlog/"&gt;Varnish 3.0 one-liners for varnishtop and varnishlog&lt;/a&gt;
. They were all variations on the same idea: pick a log tag like &lt;code&gt;RxURL&lt;/code&gt; or &lt;code&gt;TxURL&lt;/code&gt;, then &lt;code&gt;grep&lt;/code&gt; for what you wanted.&lt;/p&gt;</description></item><item><title>Varnish in 2026: it's called Vinyl Cache now, and the mental model still holds</title><link>https://ma.ttias.be/varnish-vinyl-cache-2026/</link><pubDate>Fri, 05 Jun 2026 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/varnish-vinyl-cache-2026/</guid><description>&lt;p&gt;Back in 2016 I gave a talk called &lt;a href="https://ma.ttias.be/varnish-explained/"&gt;Varnish Explained&lt;/a&gt;
and wrote it up slide by slide. It still gets traffic, which is nice, except the version numbers on those slides are now a decade old and the project doesn&amp;rsquo;t even go by the same name anymore.&lt;/p&gt;</description></item><item><title>Running HTTP/3 with Caddy in 2026: it just works</title><link>https://ma.ttias.be/running-http3-with-caddy-2026/</link><pubDate>Thu, 04 Jun 2026 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/running-http3-with-caddy-2026/</guid><description>&lt;p&gt;When I &lt;a href="https://ma.ttias.be/how-run-http-3-with-caddy-2/"&gt;wrote about running HTTP/3 with Caddy in 2020&lt;/a&gt;
, it was a ritual. You opted in with an &lt;code&gt;experimental_http3&lt;/code&gt; global option, the protocol was still draft &lt;code&gt;h3-27&lt;/code&gt;, and to test it you needed a custom-compiled curl and a browser nightly with the right flags flipped. It worked, but it was clearly the bleeding edge.&lt;/p&gt;</description></item><item><title>Lessons learned: don't mix $timeout attributes and properties on queued Laravel jobs</title><link>https://ma.ttias.be/dont-mix-timeout-attributes-and-properties-laravel-jobs/</link><pubDate>Wed, 03 Jun 2026 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/dont-mix-timeout-attributes-and-properties-laravel-jobs/</guid><description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; the fix described in this post has since been &lt;a href="https://github.com/laravel/framework/pull/60369" target="_blank" rel="noopener noreferrer"&gt;merged into Laravel&lt;/a&gt;
and ships in the next &lt;code&gt;13.x&lt;/code&gt; release. From that release on, a child class&amp;rsquo;s plain &lt;code&gt;$timeout&lt;/code&gt; property correctly overrides an attribute inherited from a parent, so the specific footgun below no longer bites. This post stays up as a historical write-up: how the bug behaved, the subtle PHP reflection edge case behind it, and the fix that closed it.&lt;/p&gt;</description></item><item><title>QUIC and HTTP/3 in 2026: from Google experiment to IETF standard</title><link>https://ma.ttias.be/quic-http3-in-2026/</link><pubDate>Wed, 03 Jun 2026 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/quic-http3-in-2026/</guid><description>&lt;p&gt;Ten years ago I wrote about &lt;a href="https://ma.ttias.be/googles-quic-protocol-moving-web-tcp-udp/"&gt;Google&amp;rsquo;s QUIC protocol&lt;/a&gt;
, back when it was an experiment you could realistically only test against Google&amp;rsquo;s own servers. I was excited about it, and I ended that post hoping the spec would get standardised and show up in other browsers and servers.&lt;/p&gt;</description></item><item><title>Caching get_certificate lookups in Caddy</title><link>https://ma.ttias.be/caching-get-certificate-lookups-in-caddy/</link><pubDate>Tue, 02 Jun 2026 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/caching-get-certificate-lookups-in-caddy/</guid><description>&lt;p&gt;At &lt;a href="https://ohdear.app" target="_blank" rel="noopener noreferrer"&gt;Oh Dear&lt;/a&gt;
, our &lt;a href="https://ohdear.app/features/status-pages" target="_blank" rel="noopener noreferrer"&gt;status pages&lt;/a&gt;
can run on a customer&amp;rsquo;s own domain, and we&amp;rsquo;ve always served on-demand ACME certificates for them: someone points their domain at us, and &lt;a href="https://caddyserver.com" target="_blank" rel="noopener noreferrer"&gt;Caddy&lt;/a&gt;
provisions a Let&amp;rsquo;s Encrypt certificate for it automatically. We&amp;rsquo;re now adding a second option, letting customers bring their &lt;em&gt;own&lt;/em&gt; certificate. For that, Caddy doesn&amp;rsquo;t provision anything; it fetches the certificate from an HTTP backend in our app.&lt;/p&gt;</description></item><item><title>Serving HTTP/2 and HTTP/3 with Nginx in 2026</title><link>https://ma.ttias.be/serving-http2-http3-nginx-2026/</link><pubDate>Tue, 02 Jun 2026 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/serving-http2-http3-nginx-2026/</guid><description>&lt;p&gt;Back in 2016 I &lt;a href="https://ma.ttias.be/run-nginx-proxy-docker-container-http2/"&gt;wrapped nginx in a Docker container&lt;/a&gt;
just to get HTTP/2 working. Not because I love Docker, but because the server&amp;rsquo;s OpenSSL was too old to do ALPN, and the cleanest way to borrow a modern OpenSSL was to lift one out of an Alpine container. It worked, but it was a hack, and I knew it at the time.&lt;/p&gt;</description></item><item><title>More time to think</title><link>https://ma.ttias.be/more-time-to-think/</link><pubDate>Mon, 01 Jun 2026 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/more-time-to-think/</guid><description>&lt;p&gt;I&amp;rsquo;m finding myself thinking &lt;em&gt;longer&lt;/em&gt; about the code I write and the features that get developed, than I did &lt;em&gt;before&lt;/em&gt; the agentic coding era.&lt;/p&gt;</description></item><item><title>Finding Dutch audio across streaming services</title><link>https://ma.ttias.be/finding-dutch-audio-across-streaming-services/</link><pubDate>Tue, 28 Apr 2026 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/finding-dutch-audio-across-streaming-services/</guid><description>&lt;p&gt;We have 4 streaming services at home: Netflix, Disney+, Prime Video, and Apple TV+. Try finding &lt;em&gt;which&lt;/em&gt; films and series are actually available with Dutch audio.&lt;/p&gt;</description></item><item><title>Imposter: a single-phone party game, free and open source</title><link>https://ma.ttias.be/imposter-game/</link><pubDate>Mon, 27 Apr 2026 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/imposter-game/</guid><description>&lt;p&gt;Our babysitter recently played a fun game with our kids called &amp;ldquo;Fake It&amp;rdquo;. It&amp;rsquo;s a simple party game, not too complex, and doesn&amp;rsquo;t require any props. The app store is full of them, but they all hide ads or have a €9.99/week (week!) subscription model, all trying to trick you into buying or paying. But it&amp;rsquo;s such a simple game. Surely, I can just make my own version, right?&lt;/p&gt;</description></item><item><title>How we implemented a mobile-friendly Oh Dear UI with AI</title><link>https://ma.ttias.be/mobile-friendly-oh-dear-ui-with-ai/</link><pubDate>Fri, 06 Mar 2026 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/mobile-friendly-oh-dear-ui-with-ai/</guid><description>&lt;p&gt;We just shipped a &lt;a href="https://ohdear.app/news-and-updates/oh-dear-is-now-mobile-friendly" target="_blank" rel="noopener noreferrer"&gt;mobile-friendly version of Oh Dear&lt;/a&gt;
. It touched 226 files, added over 5,000 lines, and modified 160+ Blade templates. The PR took three weeks from first commit to merge.&lt;/p&gt;</description></item><item><title>My interview on Oh Dear on the Seahawk Podcast</title><link>https://ma.ttias.be/my-interview-on-oh-dear-on-the-seahawk-podcast/</link><pubDate>Wed, 11 Feb 2026 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/my-interview-on-oh-dear-on-the-seahawk-podcast/</guid><description>&lt;p&gt;A few weeks ago, I was invited to the &lt;a href="https://www.youtube.com/@seahawkmedia" target="_blank" rel="noopener noreferrer"&gt;Seahawk Media&lt;/a&gt;
podcast for a chat about &lt;a href="https://ohdear.app" target="_blank" rel="noopener noreferrer"&gt;Oh Dear&lt;/a&gt;
, our origin and where we&amp;rsquo;re headed as a company in the age of AI and easily-copied SaaS ideas.&lt;/p&gt;</description></item><item><title>Catching SQL performance issues in PHPUnit and Pest, as part of your test infrastructure</title><link>https://ma.ttias.be/catching-sql-performance-issues-in-phpunit-and-pest-as-part-of-your-test-infrastructure/</link><pubDate>Mon, 26 Jan 2026 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/catching-sql-performance-issues-in-phpunit-and-pest-as-part-of-your-test-infrastructure/</guid><description>&lt;p&gt;I&amp;rsquo;ve been on a bit of a SQL performance kick lately. Over at &lt;a href="https://ohdear.app" target="_blank" rel="noopener noreferrer"&gt;Oh Dear&lt;/a&gt;
, I wrote a &lt;a href="https://ohdear.app/news-and-updates/our-3-part-series-on-sql-performance-optimisations" target="_blank" rel="noopener noreferrer"&gt;3-part series about finding, fixing, and automatically detecting SQL performance issues&lt;/a&gt;
. The last part of that series covers how we catch regressions &lt;em&gt;before&lt;/em&gt; they hit production by running checks in our test suite.&lt;/p&gt;</description></item><item><title>Using AI is no longer optional</title><link>https://ma.ttias.be/ai-no-longer-optional/</link><pubDate>Fri, 09 Jan 2026 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/ai-no-longer-optional/</guid><description>&lt;p&gt;We&amp;rsquo;ve gone from generating funny images to AI being a core part of being a developer quite fast, haven&amp;rsquo;t we?&lt;/p&gt;</description></item><item><title>Web development is fun again</title><link>https://ma.ttias.be/web-development-is-fun-again/</link><pubDate>Sat, 03 Jan 2026 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/web-development-is-fun-again/</guid><description>&lt;p&gt;I remember when PHP 4 was a thing. jQuery was new and shiny. Sites were built with tables, not divs. Dreamweaver felt like a life hack. Designs were sliced in Photoshop. Databases lived in phpMyAdmin.&lt;/p&gt;</description></item><item><title>A fresh server for this blog</title><link>https://ma.ttias.be/a-fresh-server-for-this-blog/</link><pubDate>Sun, 28 Dec 2025 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/a-fresh-server-for-this-blog/</guid><description>&lt;p&gt;It&amp;rsquo;s been 1,067 days since I last posted &lt;a href="https://ma.ttias.be/oh-dear-2-0-launch/"&gt;something&lt;/a&gt;
on this blog. And instead of writing the blog post I wanted to write, I did everything &lt;em&gt;else&lt;/em&gt;.&lt;/p&gt;</description></item></channel></rss>