I'm blogging about Emacs, Drupal, php and exciting subjects
I upgraded this site from Drupal 10 to Drupal 11. The Drupal part went fine, eventually. What actually took the site down for four minutes had nothing to do with Drupal at all — it was a missing setgid bit, and I only found it because I've learned not to trust a Drupal error log to tell me the whole story.
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.
If you have ever wondered why Doctrine entities cannot be final, this is the article that answers it. And the answer stops being true in PHP 8.4.
This is the largest change in the Symfony 8 and Doctrine 4 move, and it is not really a framework change at all. It is a PHP language feature removing the need for a fifteen-year-old workaround.
You run Rector. It rewrites every docblock into an attribute. The diff looks perfect. You commit, deploy, and your entities are no longer recognised at all.
The code conversion is the easy part, and it is what every guide covers. The part that breaks things is a two-word change in a YAML file, and if you make it in the wrong order you get an application that cannot find its own database mapping.
Why you have to do this
Two deadlines, unrelated to each other.
Symfony 6.4 stops receiving bug fixes in November 2026. Security fixes continue for another year, until November 2027, but after that the version is done.
If you are on 6.4, this is your window. And the good news is that the upgrade is much less work than the version numbers suggest, provided you understand what Symfony is actually asking you to do.
Drupal ships a sensible robots.txt. It blocks the admin paths, the login and registration forms, the search pages, and the node creation forms. For a single-language site it does the job.
I run a site in Danish and Swedish. On that site, almost none of those rules do anything.
The proof
Google open sourced the matcher that Googlebot uses, and there is a Python port of it. So this is not an interpretation of the specification. It is the actual matching code, run against Drupal's actual default file.
Both tools do the same job. You describe how a machine should be configured, you keep that description in version control, and the tool makes the machine match. Most of what you learned from Puppet still applies.
The problem is the part that does not. Four differences are structural rather than cosmetic, and each one produces a specific kind of bad Ansible that is written almost exclusively by people who know Puppet well. This article covers the mapping first, then the four places where the mapping actively misleads you.
I have two servers and one OpenSearch node. The obvious move is to put a node on the second server and call it a cluster.
That works, and it is worth doing. But it does not give you high availability, and the reason is counterintuitive enough that a lot of people find out during their first outage. So this article covers the setup and the limitation together.
My robots.txt blocks nothing. Every page carries a meta robots tag permitting indexing. Google crawls the site happily and indexes almost everything within a few days of publication.
And when an AI assistant tried to read one of my articles, it was refused.
Not throttled, not rate-limited — refused, with a robots-level rejection, on a URL that no robots directive anywhere on my site excludes. The homepage fetched fine. Article pages did not. Google saw no problem at all.
Every example IP in the previous article was 203.0.113.10. That is not a number I invented, and it is not a real server. It comes from TEST-NET-3, one of three IPv4 ranges the IETF reserved specifically so that technical writers have addresses they can safely put in front of readers.
The reason these exist is not tidiness. It is that documentation leaks into production, reliably and at scale, and an address in an example is an address someone will eventually paste into a config file.
Subscribe to