Highlights
- HTTP auth and IP whitelists now cover every domain a site serves. Until now,
ee authonly protected a site's own domain: the subsites of a WordPress subdomain multisite (*.example.com) and a site's alias domains were served with the global auth or with no auth at all. In v4.13.0, auth and whitelists apply to subdomain multisite subsites, plain alias domains and*.aliaswildcard aliases, and stay in sync when aliases are added or removed (auth-command#57, site-command#502). - No more auth leaking between sites. The nginx-proxy wildcard lookup no longer guesses from the host name: an unrelated site such as
shop.example.comno longer asks for the credentials of the multisiteexample.com, and subsites of multisites with 4+ labels (*.ms.dev.example.com) are now matched correctly (dockerfiles#354). - Existing sites are fixed on upgrade. A migration regenerates every site's auth and whitelist files, so subsites and aliases that were unprotected become protected with the site's existing credentials, without any manual step. The upgrade never applies a site's wildcard auth to another site, not even while the old nginx-proxy is still running (auth-command#58).
- Safer upgrades. When an upgrade fails before all containers are upgraded (for example because an image can't be pulled), EasyEngine now also undoes the auth file changes made earlier in the same run, so the host is left as it was and the next attempt starts cleanly (easyengine#1936).
- No slow requests after upgrading. Sites whose containers are recreated during the upgrade no longer serve intermittent ~3 s (sometimes 10 s+) requests until their nginx is reloaded by hand (easyengine#1937).
- Safer proxy reloads. EasyEngine now only reloads nginx-proxy when the regenerated config passes
nginx -t. A broken config is no longer loaded into the running proxy; ee warns with the nginx error instead (site-command#494). - Updated images: nginx-proxy 1.11.6, PHP 8.2.34 / 8.3.33 / 8.4.26 / 8.5.11, PHP 8.1.34 with refreshed Debian 13 packages, Redis 8.10.1, postfix on Debian 13.6, and a final rebuild of the PHP 7.4 and 8.0 images with the last Debian 11 security updates.
Upgrade notes
nginx-proxy: wildcard auth files are now looked up only for *.X hosts
dockerfiles#354 changes how the proxy picks the htpasswd and ACL file for a host:
htpasswd/<host>(andvhost.d/<host>_acl) if it exists;- for a host that is literally
*.X(a subdomain multisite or a*.Xalias):htpasswd/_wildcard.X(andvhost.d/_wildcard.X_acl); - otherwise the global
htpasswd/default(andvhost.d/default_acl).
The label-counting fallback added in v4.11.0 (dockerfiles#298), which tried _wildcard.<last 3 labels> and then _wildcard.<last 2 labels> for any host, is removed. The same mapping is now used for the IP whitelist include, including the /ee-admin/ and mailhog locations. Setups managed with ee auth are not affected: before this release, EasyEngine never wrote _wildcard.X files, so only hand-made files relied on the old fallback.
PHP sites get new images
Every site on PHP 8.1, 8.2, 8.3, 8.4 or 8.5 is recreated on its new easyengine/php<version>:v4.13.0 image during the upgrade: PHP 8.2.34, 8.3.33, 8.4.26 and 8.5.11, and PHP 8.1.34 (unchanged) with up-to-date Debian 13 packages. All five images are based on Debian 13.7. PHP 8.1 is end of life upstream and its official base image is no longer rebuilt, so the EasyEngine image now applies the Debian security updates itself at build time; plan to move 8.1 sites to a newer PHP version.
Sites on PHP 7.4 and 8.0 are recreated on the new easyengine/php7.4:v4.13.0 and easyengine/php8.0:v4.13.0 images during the upgrade, like every other WordPress and PHP site. PHP itself doesn't change (7.4.33 and 8.0.30, both end of life upstream); the images are rebuilt on the last Debian 11 security snapshot, which brings up to two years of Debian security updates that the old images (built 2024-09-13 and 2025-02-13) didn't have. Debian 11 is now end of life too, so this is the last build of these two images: future releases keep them at v4.13.0. Move these sites to a supported PHP version with ee site update <site> --php=8.4 (or 8.2, 8.3, 8.5) when you can.
New features
auth-command
- HTTP auth and IP whitelists now apply to all domains of a site: subdomain multisite subsites, alias domains and
*.aliaswildcard aliases. Plain aliases get their own files; only subdomain multisites and*.Xaliases get_wildcardfiles (auth-command#57). - Auth files follow alias changes: files for a new alias are written before the proxy starts serving it, removed again if the alias update fails, and removed for deleted aliases (auth-command#57).
- New upgrade migration that regenerates every site's auth and whitelist files (auth-command#57, auth-command#58).
site-command
- New hooks around alias domain updates (
site_alias_domains_before_update,site_alias_domains_updated,site_alias_domains_update_failed) for packages that keep per-domain proxy files (site-command#502). - Alias domain names are now validated on
ee site update --add-alias-domainsandee site create --type=html --alias-domains: only a hostname or*.hostnameis accepted, labels can't start with-or_or end with-, and the reserved namesdefault/default_admin_toolsare refused. Invalid names are listed in the error before anything changes. Existing invalid aliases can still be deleted (site-command#502).
core
- New hook
after_docker_image_migration, fired during an upgrade right after the image migration, once the updated global containers run. Packages can use it for changes that need the new containers (easyengine#1936).
Fixes
core
- A failed upgrade now also reverts the container migrations that ran earlier in the same run (for example when an image can't be pulled), and removes their records so the next attempt runs them again. Before, they stayed applied on the old containers and were never re-run. Once the image migration has completed, a later failure keeps them (easyengine#1936).
- After the upgrade recreates a WordPress or PHP site's containers, its nginx is reloaded, so it no longer keeps sending some requests to the removed temporary php container (each took ~3 s, sometimes 10 s+, until
ee site reload <site> --nginx). The same reload runs for each site when a failed upgrade rolls the sites back. If a reload fails, ee warns with the site name and the command to run (easyengine#1937).
auth-command
- Site delete now removes all of the site's auth and whitelist rows and every htpasswd and ACL file it used (the cleanup hook existed but was never loaded, so these were left behind) (auth-command#57).
- Usernames and passwords are shell-escaped when the htpasswd files are written: passwords with spaces,
$or;were silently cut or broke the command (auth-command#57). - Passwords and usernames are no longer written to
ee.log(auth-command#57). - htpasswd files are written atomically (temp file and rename), so a failed write keeps the previous file, including the global
defaultfile (auth-command#57). - Sites without auth or whitelist entries of their own no longer keep stale files, and correctly fall back to the global auth (auth-command#57).
- The upgrade migration backs up the auth files and restores them exactly if the upgrade fails. It holds the
_wildcard.*files back while the old nginx-proxy template runs and puts them in place once the new proxy is up, so sibling sites never pick up another site's wildcard auth during an upgrade, even when the upgrade fails or is interrupted. If a site's auth changed in between (for example after an interrupted upgrade), its files are regenerated from the current settings instead (auth-command#58).
site-command
- nginx-proxy is only reloaded when
nginx -tpasses, and the test now checks the regenerated config rather than the previous one. On failure, ee warns with the nginx error and skips the reload (site-command#494). - Adding or removing alias domains on a site with custom, self-signed or inherited SSL no longer aborts halfway with "Only Letsencrypt certificate renewal is supported." (which left the containers and the database out of sync). Let's Encrypt sites still get a renewed certificate, custom-cert sites get a warning to supply a certificate covering the new aliases, and self-signed sites keep HTTPS (site-command#488).
- Blank entries in alias lists (
a.com,,b.com,) are dropped instead of ending up in the proxy and nginx config; an update with nothing left to add or delete is refused (site-command#502).
site-type-wp
ee site create --type=wp --alias-domainsdrops blank entries and rejects invalid alias names (such as../evil,a..b,a.com.ordefault) before anything is created;--alias-domainswithout a value no longer creates the alias1(site-type-wp#239).--mu=subdomis refused when another site already has the alias*.<site>, which the multisite would also serve (site-type-wp#239).
site-type-php
ee site create --type=php --alias-domainsdrops blank entries and rejects invalid alias names before anything is created;--alias-domainswithout a value no longer creates the alias1(site-type-php#114).
nginx-proxy image
- Per-site IP whitelists now apply to subdomain multisite subsites and
*.Xaliases, including the/ee-admin/and mailhog locations (dockerfiles#354).
PHP 7.4 and 8.0 images
- The PHP 7.4 and 8.0 images build again: Debian 11's security repository was removed from
deb.debian.orgafter Debian 11 LTS ended, so their builds failed. They now use the finalbullseye-securitysnapshot fromsnapshot.debian.org(dockerfiles#355).
Improvements and maintenance
- The PHP 8.1 image now installs Debian security updates at build time, because the official PHP 8.1 base image is no longer rebuilt upstream (dockerfiles#360).
- The PHP 7.4 and 8.0 images are no longer built: Debian 11, their base, is end of life (dockerfiles#356).
- composer/composer updated to 2.2.30, which also fixes the core nightly and PR builds that had failed since 2026-07-21 (easyengine#1933).
- Development: php_codesniffer 3.13.6 (easyengine#1932); core CI moved to Node 24 GitHub Actions (easyengine#1934).
Docker image updates
All new images are tagged v4.13.0 (dockerfiles v4.13.0, matching the core version, as with v4.11.0).
| Image | 4.12.0 tag | 4.13.0 tag | Upstream change | PR |
|---|---|---|---|---|
| easyengine/nginx-proxy | v4.11.1 | v4.13.0 | jwilder/nginx-proxy 1.11.2 → 1.11.6, new wildcard auth/ACL lookup in nginx.tmpl
| #345, #354 |
| easyengine/php8.1 | v4.10.2 | v4.13.0 | PHP unchanged (8.1.34); Debian 13 packages upgraded at build time, now Debian 13.7 | #360 |
| easyengine/php8.2 | v4.11.0 | v4.13.0 | PHP 8.2.31 → 8.2.34 | #350, #360 |
| easyengine/php8.3 | v4.11.0 | v4.13.0 | PHP 8.3.31 → 8.3.33 | #348 |
| easyengine/php8.4 | v4.11.0 | v4.13.0 | PHP 8.4.22 → 8.4.26 | #352, #360 |
| easyengine/php8.5 | v4.11.1 | v4.13.0 | PHP 8.5.7 → 8.5.11 | #360 |
| easyengine/redis | v4.11.0 | v4.13.0 | Redis 8.8.0 → 8.10.1 | #351 |
| easyengine/postfix | v4.11.0 | v4.13.0 | Debian 13.5 → 13.6 (slim) | #344 |
| easyengine/php7.4 | v4.7.4 | v4.13.0 | Final rebuild on the last Debian 11 security snapshot; PHP unchanged (7.4.33) | #355 |
| easyengine/php8.0 | v4.8.1 | v4.13.0 | Final rebuild on the last Debian 11 security snapshot; PHP unchanged (8.0.30) | #355 |
Unchanged in this release: nginx v4.11.0, cron v4.11.0, mariadb v4.9.1 (still held back; the MariaDB upgrade isn't part of this release), mailhog v4.6.5, php5.6–7.3 v4.7.4, php (stable) v4.6.6, newrelic-daemon v4.11.1. Only the nginx-proxy bump is required for the new auth behaviour.
PHP 7.4 and 8.0 run on Debian 11, which is end of life, so v4.13.0 is their last image; like 5.6–7.3, they stay available but are no longer rebuilt (#356 removes them from the image builds).
Package versions
All tagged. Semver follows the Conventional Commit types of the merged PRs.
| Component | 4.12.0 | 4.13.0 | Why |
|---|---|---|---|
| easyengine (core) | 4.12.0 | 4.13.0 (tagged) | new features in bundled packages and the upgrade fixes (#1936, #1937) (EasyEngine uses minor versions for these) |
| dockerfiles | v4.11.1 | v4.13.0 (tagged) | fix(nginx-proxy)!, the PHP 7.4/8.0 build fix, base image bumps (PHP 8.1–8.5, nginx-proxy, redis, postfix) and the end of 7.4/8.0 builds
|
| auth-command | v1.2.1 | v1.3.1 (tagged) | feat(auth) (auth-command#57) + fix(migration) (auth-command#58)
|
| site-command | v3.7.6 | v3.8.0 (tagged) | feat(site) (site-command#502) + fixes (site-command#488, site-command#494)
|
| site-type-wp | v1.10.1 | v1.11.0 (tagged) | fix(site) (site-type-wp#239); minor bump because it now requires site-command v3.8.0
|
| site-type-php | v1.10.1 | v1.11.0 (tagged) | fix(site) (site-type-php#114); minor bump because it now requires site-command v3.8.0
|
| admin-tools, config, cron, dash, log, mailhog, service, shell | unchanged | unchanged | no changes since their pinned tags |
Contributors
What's Changed
- chore(composer): update auth-command to v1.3.1 #1938 @mrrobot47
- fix(migration): don't apply wildcard auth files on the old nginx-proxy template EasyEngine/auth-command#58 @mrrobot47
- fix(migration): reload site nginx after its containers are recreated #1937 @mrrobot47
- fix(migration): revert container migrations when a later upgrade step fails #1936 @mrrobot47
- chore(release): prepare v4.13.0 #1935 @mrrobot47
- chore(deps): bump php 8.2/8.4/8.5 and patch the php 8.1 base EasyEngine/dockerfiles#360 @mrrobot47
- ci(php): stop building EOL-base php 7.4 and 8.0 images EasyEngine/dockerfiles#356 @mrrobot47
- feat(auth): support http auth and ip whitelist on wildcard subdomains and alias domains EasyEngine/auth-command#57 @mrrobot47
- fix(site): validate alias domain names on site create EasyEngine/site-type-php#114 @mrrobot47
- fix(site): validate alias domain names on site create EasyEngine/site-type-wp#239 @mrrobot47
- feat(site): add alias domain hooks and validate alias domain names EasyEngine/site-command#502 @mrrobot47
- fix(php): use final bullseye-security snapshot for 7.4 and 8.0 EasyEngine/dockerfiles#355 @mrrobot47
- fix(nginx-proxy)!: apply wildcard htpasswd and ACL only to *.X hosts EasyEngine/dockerfiles#354 @mrrobot47
- ci: update GitHub Actions to Node 24 majors #1934 @mrrobot47
- fix(ssl): skip le renewal on alias-domain change for non-le sites EasyEngine/site-command#488 @mrrobot47
- chore(deps-dev): bump squizlabs/php_codesniffer from 3.13.5 to 3.13.6 #1932 @dependabot
- chore(deps): bump composer/composer from 2.2.28 to 2.2.30 #1933 @dependabot
- fix(proxy): only reload nginx-proxy when its config test passes EasyEngine/site-command#494 @mrrobot47
- chore(deps): bump php from 8.4.22-fpm to 8.4.25-fpm in /php/8.4 EasyEngine/dockerfiles#352 @dependabot
- chore(deps): bump redis from 8.8.0 to 8.10.1 in /redis EasyEngine/dockerfiles#351 @dependabot
- chore(deps): bump php from 8.2.31-fpm to 8.2.33-fpm in /php/8.2 EasyEngine/dockerfiles#350 @dependabot
- chore(deps): bump php from 8.3.31-fpm to 8.3.33-fpm in /php/8.3 EasyEngine/dockerfiles#348 @dependabot
- chore(deps): bump jwilder/nginx-proxy from 1.11.2 to 1.11.6 in /nginx-proxy EasyEngine/dockerfiles#345 @dependabot
- chore(deps): bump debian from 13.5-slim to 13.6-slim in /postfix EasyEngine/dockerfiles#344 @dependabot