I'm blogging about Emacs, Drupal, php and exciting subjects

Provisioning a PHP web server with Ansible: MySQL, PHP-FPM, nginx and Let's Encrypt

Four packages, one playbook. This should be a boring afternoon, and it mostly is — except for one ordering problem that breaks almost every tutorial on the subject, in a way that only shows up on a genuinely fresh server.

So let me start there, because if you understand it the rest is just YAML.

The deadlock nobody warns you about

You write an nginx vhost template with TLS configured, because that is the end state you want:

Installing OpenVox 8 on Ubuntu 24.04: the open-source Puppet replacement

If you came here looking for how to install open-source Puppet on a current Ubuntu, the short answer is that you can't, and it is not your fault for not knowing. The instructions everyone wrote — add deb.puppetlabs.com, install puppet-agent — stopped producing new versions in early 2025.

This article covers what to do instead. If you are running Puppet today, the migration is at the bottom and it is less painful than you are probably expecting.

tmux and Emacs: settling the keybinding war

Run Emacs inside tmux with the stock configuration and you hit the problem within about four seconds. tmux's prefix key is C-b. In Emacs, C-b is backward-char — one of the six or seven keys you press most in any editing session.

So every tmux command now begins by moving your cursor one character left, and every attempt to move left now opens a tmux prefix that swallows whatever you type next. Both tools are behaving correctly. They just want the same key, and the collision is on a binding neither side can reasonably give up.

Multistage Docker builds for PHP: keeping composer install out of your rebuild loop

Here is the Dockerfile almost everyone writes first:

FROM php:8.3-fpm

RUN apt-get update && apt-get install -y git unzip libicu-dev \
    && docker-php-ext-install intl opcache pdo_mysql

COPY --from=composer:2 /usr/bin/composer /usr/local/bin/composer

WORKDIR /app
COPY . .
RUN composer install --no-dev

It works. It is also the reason your build takes ninety seconds every time you fix a typo.

Writing a polite web crawler

Every other piece of a search engine operates on data you already have. The crawler is the one component that reaches out and spends somebody else's money — their bandwidth, their CPU, their database connections — without asking first.

Ranking search results with BM25

So far in this series we have crawled pages, broken them into tokens, and built an index that can tell us which documents contain a term. That leaves the question every search engine actually lives or dies by: in what order do we show them?

A query for "puppet ubuntu" might match four hundred documents. The user will look at five. Getting those five right is the ranking problem, and for keyword search the answer has been more or less settled since the 1990s: BM25.

Publishing to Drupal via JSON:API: A Config-Managed REST Pipeline

Most guides to enabling REST or JSON:API in Drupal tell you to go to /admin/config/services, tick some checkboxes, and save. That's fine advice for a one-off experiment, and terrible advice for anything you intend to depend on. A permission granted by clicking a checkbox in an admin UI leaves no diff, no code review, no record of who enabled it or why, and no way to reproduce it on staging without either remembering to click the same checkbox there too or exporting config after the fact and hoping you caught everything it touched.

Email Self-Hosting in 2026: Is It Still Possible Without Getting Blacklisted?

Every year, on schedule, someone writes the obituary for self-hosted email. The argument is always the same shape: Gmail and Microsoft control the inbox, residential and small-VPS IP ranges are pre-blocked before you've sent a single message, and the only rational move is to hand your mail to a SaaS provider and get on with your life. I've heard some version of this argument every year for the last five, and every year I've kept running my own Postfix and Dovecot stack on a cheap VPS, for one domain, for myself. It still works. Mail still arrives. Nothing is on fire.

Production Infrastructure from First Principles

Building Reliable Systems with Ansible

Introduction

Most developers begin their careers thinking almost exclusively about applications.

They think about features, programming languages, frameworks, databases, and APIs. Success is measured by whether the application works, whether users can accomplish their tasks, and whether the next feature can be delivered before the deadline.

As software matures, however, another reality begins to emerge.

Applications do not exist in isolation.

Subscribe to