Skip to content

Compile PHP from source, drop PECL, and monitor dependencies with Renovate - #739

Merged
jaydrogers merged 10 commits into
release/improve-buildsfrom
build-php-from-source-renovate
Oct 29, 2026
Merged

jaydrogers merged 10 commits into
release/improve-buildsfrom
build-php-from-source-renovate

Conversation

@jaydrogers

@jaydrogers jaydrogers commented Oct 28, 2026 •

Copy link
Copy Markdown
Member

During the last critical PHP release (#721), we waited hours for Docker Hub's php images, then PECL went down. This PR takes both out of our build.

flowchart LR
  subgraph Before
    direction LR
    A1[php.net] -. hours .-> A2[Docker Hub php images] --> A3[Our build] --> A4[PECL] --> A5[Publish]
  end
  subgraph After
    direction LR
    B1[php.net] --> B2[We compile PHP] --> B3[Our build] --> B4[Publish]
  end
Loading

What changes

  • We compile PHP ourselves, using docker-library's own Dockerfile, the same recipe as the official images. Only five lines change: the version, URL, and checksum, the Built by name, and the removed pecl update-channels call.
  • No PECL. redis builds from its GitHub source.
  • One file holds every version (scripts/conf/php-versions-base-config.yml). Renovate watches it and replaces Dependabot.
  • PHP 8.6 release candidates ship as 8.6-rc tags.
  • Fixes: auto-retry never actually retried, and a set -oe bug printed shell options into helper output. The Brotli workaround from Security: Patch Brotli for CVE-2026-111497 and upgrade FrankenPHP to 1.13.4 #737 is gone, because freshly compiled images already have the patched library.

No breaking changes

All 79 existing images were compared against what's live today (the 18 8.6-rc images are new):

Result
Extensions, settings, files, packages, users, entrypoints Identical
Extensions exercised against real MySQL, PostgreSQL, and Redis Identical
Image size Median +0.7%
php -v Says "Built by Server Side Up"
Libraries Newer where Debian and Alpine shipped fixes, such as curl 8.23

Special Thanks

Thanks to @tomschlick for #726, which started this.

jaydrogers and others added 5 commits October 28, 2026 18:23
`set -oe` without an option name makes /bin/sh print every shell option to stdout. Anything reading a helper's output got that dump first, such as the watcher URL lookup and the php.net checksum lookup. Use `set -e` (and `set -eu` in the s6 installer).

Thanks to @tomschlick for spotting this in #726.

Co-authored-by: Tom Schlick <tom@schlick.email>
Move each version that ships in an image (s6-overlay, php-fpm-healthcheck, the extension installer, FrankenPHP, Go, watcher, phpredis) into a `dependencies` block in php-versions-base-config.yml. CI and dev.sh pass the block as build args of the same name, and the Dockerfiles declare them without defaults so a missing pin fails the build.

Build redis from its GitHub source, with its liblzf submodule fetched separately, so no default build step depends on PECL. Pin watcher instead of downloading the latest release.
Stop waiting for Docker Hub's php images. A new build-php-base phase runs prepare-php-base.sh, which takes docker-library/php at a pinned commit, sets the PHP version, URL, and php.net SHA256, and removes `pecl update-channels`. Everything else matches the official images. Each base compiles once without the build cache, so OS security fixes ship on the next run, and is saved to the Depot Registry. The variations build on it through BASE_IMAGE.

get-php-versions.sh no longer checks Docker Hub, and a pinned patch_versions now replaces php.net's. Release candidates such as 8.6-rc build from php.net's release-candidates feed, and php_base_overrides lets a minor version change a variation's upstream variant. PHP 8.1 builds from the last docker-library commit that had it.
The compiled PHP bases install current Debian and Alpine packages, so they already ship the patched libbrotli for CVE-2026-111497. FrankenPHP's Bookworm Brotli build stays, because cbrotli needs libbrotli 1.1 or newer.
Replace Dependabot and get-nginx-versions.sh with Renovate. It reads the `# renovate:` comments in the base config and the lint workflow, checks each OS's NGINX package on nginx.org, groups GitHub Actions monthly, and merges the weekly docker-library/php bump once every check passes. Every other pin waits for a manual merge.
@github-actions

github-actions Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Images for PR #739

Build Test Publish
✅ 97 of 97 images built ✅ Every image passed on amd64 and arm64 ✅ Published to serversideup/php-dev

Try it:

docker run --rm -v "$PWD:/var/www/html" -p 8080:8080 serversideup/php-dev:739-8.5-fpm-nginx

Every image is on Docker Hub as serversideup/php-dev:739-<php>-<variation>-<os>. Browse all tags or view the run.

All images with sizes

Sizes are compressed, per architecture.

Variation PHP Base OS amd64 arm64 Image
cli 8.6-rc alpine3.23 53.8 MB 52.6 MB serversideup/php-dev:739-8.6-rc-cli-alpine3.23
cli 8.6-rc alpine3.24 53.8 MB 52.6 MB serversideup/php-dev:739-8.6-rc-cli-alpine3.24
cli 8.6-rc bookworm 197.1 MB 188.3 MB serversideup/php-dev:739-8.6-rc-cli-bookworm
cli 8.6-rc trixie 196.4 MB 186.9 MB serversideup/php-dev:739-8.6-rc-cli-trixie
cli 8.5.12 alpine3.23 48.7 MB 48.0 MB serversideup/php-dev:739-8.5.12-cli-alpine3.23
cli 8.5.12 alpine3.24 48.6 MB 48.1 MB serversideup/php-dev:739-8.5.12-cli-alpine3.24
cli 8.5.12 bookworm 198.2 MB 189.7 MB serversideup/php-dev:739-8.5.12-cli-bookworm
cli 8.5.12 trixie 197.5 MB 188.2 MB serversideup/php-dev:739-8.5.12-cli-trixie
cli 8.4.27 alpine3.23 45.4 MB 45.1 MB serversideup/php-dev:739-8.4.27-cli-alpine3.23
cli 8.4.27 alpine3.24 45.5 MB 45.1 MB serversideup/php-dev:739-8.4.27-cli-alpine3.24
cli 8.4.27 bookworm 194.1 MB 185.9 MB serversideup/php-dev:739-8.4.27-cli-bookworm
cli 8.4.27 trixie 193.4 MB 184.4 MB serversideup/php-dev:739-8.4.27-cli-trixie
cli 8.3.36 alpine3.23 41.3 MB 41.3 MB serversideup/php-dev:739-8.3.36-cli-alpine3.23
cli 8.3.36 alpine3.24 41.3 MB 41.4 MB serversideup/php-dev:739-8.3.36-cli-alpine3.24
cli 8.3.36 bookworm 189.1 MB 181.3 MB serversideup/php-dev:739-8.3.36-cli-bookworm
cli 8.3.36 trixie 188.4 MB 179.9 MB serversideup/php-dev:739-8.3.36-cli-trixie
cli 8.2.35 alpine3.23 40.5 MB 40.5 MB serversideup/php-dev:739-8.2.35-cli-alpine3.23
cli 8.2.35 alpine3.24 40.5 MB 40.6 MB serversideup/php-dev:739-8.2.35-cli-alpine3.24
cli 8.2.35 bookworm 188.1 MB 180.4 MB serversideup/php-dev:739-8.2.35-cli-bookworm
cli 8.2.35 trixie 187.5 MB 179.0 MB serversideup/php-dev:739-8.2.35-cli-trixie
cli 8.1.34 alpine3.22 39.4 MB 39.6 MB serversideup/php-dev:739-8.1.34-cli-alpine3.22
cli 8.1.34 bookworm 187.2 MB 179.4 MB serversideup/php-dev:739-8.1.34-cli-bookworm
cli 8.1.34 trixie 186.5 MB 178.0 MB serversideup/php-dev:739-8.1.34-cli-trixie
fpm 8.6-rc alpine3.23 42.2 MB 41.8 MB serversideup/php-dev:739-8.6-rc-fpm-alpine3.23
fpm 8.6-rc alpine3.24 42.2 MB 41.8 MB serversideup/php-dev:739-8.6-rc-fpm-alpine3.24
fpm 8.6-rc bookworm 185.6 MB 177.5 MB serversideup/php-dev:739-8.6-rc-fpm-bookworm
fpm 8.6-rc trixie 184.9 MB 176.0 MB serversideup/php-dev:739-8.6-rc-fpm-trixie
fpm 8.5.12 alpine3.23 42.5 MB 42.2 MB serversideup/php-dev:739-8.5.12-fpm-alpine3.23
fpm 8.5.12 alpine3.24 42.6 MB 42.3 MB serversideup/php-dev:739-8.5.12-fpm-alpine3.24
fpm 8.5.12 bookworm 186.0 MB 178.0 MB serversideup/php-dev:739-8.5.12-fpm-bookworm
fpm 8.5.12 trixie 185.3 MB 176.5 MB serversideup/php-dev:739-8.5.12-fpm-trixie
fpm 8.4.27 alpine3.23 40.3 MB 40.0 MB serversideup/php-dev:739-8.4.27-fpm-alpine3.23
fpm 8.4.27 alpine3.24 40.3 MB 40.1 MB serversideup/php-dev:739-8.4.27-fpm-alpine3.24
fpm 8.4.27 bookworm 183.7 MB 175.8 MB serversideup/php-dev:739-8.4.27-fpm-bookworm
fpm 8.4.27 trixie 183.1 MB 174.4 MB serversideup/php-dev:739-8.4.27-fpm-trixie
fpm 8.3.36 alpine3.23 37.0 MB 37.2 MB serversideup/php-dev:739-8.3.36-fpm-alpine3.23
fpm 8.3.36 alpine3.24 37.0 MB 37.3 MB serversideup/php-dev:739-8.3.36-fpm-alpine3.24
fpm 8.3.36 bookworm 180.5 MB 173.0 MB serversideup/php-dev:739-8.3.36-fpm-bookworm
fpm 8.3.36 trixie 179.8 MB 171.6 MB serversideup/php-dev:739-8.3.36-fpm-trixie
fpm 8.2.35 alpine3.23 36.3 MB 36.5 MB serversideup/php-dev:739-8.2.35-fpm-alpine3.23
fpm 8.2.35 alpine3.24 36.3 MB 36.5 MB serversideup/php-dev:739-8.2.35-fpm-alpine3.24
fpm 8.2.35 bookworm 179.8 MB 172.3 MB serversideup/php-dev:739-8.2.35-fpm-bookworm
fpm 8.2.35 trixie 179.1 MB 170.9 MB serversideup/php-dev:739-8.2.35-fpm-trixie
fpm 8.1.34 alpine3.22 35.4 MB 35.7 MB serversideup/php-dev:739-8.1.34-fpm-alpine3.22
fpm 8.1.34 bookworm 179.1 MB 171.6 MB serversideup/php-dev:739-8.1.34-fpm-bookworm
fpm 8.1.34 trixie 178.5 MB 170.2 MB serversideup/php-dev:739-8.1.34-fpm-trixie
fpm-apache 8.6-rc bookworm 191.9 MB 184.3 MB serversideup/php-dev:739-8.6-rc-fpm-apache-bookworm
fpm-apache 8.6-rc trixie 191.3 MB 182.9 MB serversideup/php-dev:739-8.6-rc-fpm-apache-trixie
fpm-apache 8.5.12 bookworm 192.3 MB 184.8 MB serversideup/php-dev:739-8.5.12-fpm-apache-bookworm
fpm-apache 8.5.12 trixie 191.7 MB 183.4 MB serversideup/php-dev:739-8.5.12-fpm-apache-trixie
fpm-apache 8.4.27 bookworm 190.0 MB 182.6 MB serversideup/php-dev:739-8.4.27-fpm-apache-bookworm
fpm-apache 8.4.27 trixie 189.5 MB 181.3 MB serversideup/php-dev:739-8.4.27-fpm-apache-trixie
fpm-apache 8.3.36 bookworm 186.8 MB 179.8 MB serversideup/php-dev:739-8.3.36-fpm-apache-bookworm
fpm-apache 8.3.36 trixie 186.2 MB 178.4 MB serversideup/php-dev:739-8.3.36-fpm-apache-trixie
fpm-apache 8.2.35 bookworm 186.1 MB 179.1 MB serversideup/php-dev:739-8.2.35-fpm-apache-bookworm
fpm-apache 8.2.35 trixie 185.5 MB 177.8 MB serversideup/php-dev:739-8.2.35-fpm-apache-trixie
fpm-apache 8.1.34 bookworm 185.5 MB 178.5 MB serversideup/php-dev:739-8.1.34-fpm-apache-bookworm
fpm-apache 8.1.34 trixie 184.9 MB 177.1 MB serversideup/php-dev:739-8.1.34-fpm-apache-trixie
fpm-nginx 8.6-rc alpine3.23 48.3 MB 48.3 MB serversideup/php-dev:739-8.6-rc-fpm-nginx-alpine3.23
fpm-nginx 8.6-rc alpine3.24 49.7 MB 49.7 MB serversideup/php-dev:739-8.6-rc-fpm-nginx-alpine3.24
fpm-nginx 8.6-rc bookworm 193.4 MB 185.7 MB serversideup/php-dev:739-8.6-rc-fpm-nginx-bookworm
fpm-nginx 8.6-rc trixie 199.7 MB 191.0 MB serversideup/php-dev:739-8.6-rc-fpm-nginx-trixie
fpm-nginx 8.5.12 alpine3.23 48.6 MB 48.7 MB serversideup/php-dev:739-8.5.12-fpm-nginx-alpine3.23
fpm-nginx 8.5.12 alpine3.24 50.1 MB 50.2 MB serversideup/php-dev:739-8.5.12-fpm-nginx-alpine3.24
fpm-nginx 8.5.12 bookworm 193.7 MB 186.1 MB serversideup/php-dev:739-8.5.12-fpm-nginx-bookworm
fpm-nginx 8.5.12 trixie 200.1 MB 191.5 MB serversideup/php-dev:739-8.5.12-fpm-nginx-trixie
fpm-nginx 8.4.27 alpine3.23 46.3 MB 46.6 MB serversideup/php-dev:739-8.4.27-fpm-nginx-alpine3.23
fpm-nginx 8.4.27 alpine3.24 47.8 MB 48.0 MB serversideup/php-dev:739-8.4.27-fpm-nginx-alpine3.24
fpm-nginx 8.4.27 bookworm 191.5 MB 184.0 MB serversideup/php-dev:739-8.4.27-fpm-nginx-bookworm
fpm-nginx 8.4.27 trixie 197.9 MB 189.4 MB serversideup/php-dev:739-8.4.27-fpm-nginx-trixie
fpm-nginx 8.3.36 alpine3.23 43.1 MB 43.7 MB serversideup/php-dev:739-8.3.36-fpm-nginx-alpine3.23
fpm-nginx 8.3.36 alpine3.24 44.5 MB 45.2 MB serversideup/php-dev:739-8.3.36-fpm-nginx-alpine3.24
fpm-nginx 8.3.36 bookworm 188.3 MB 181.1 MB serversideup/php-dev:739-8.3.36-fpm-nginx-bookworm
fpm-nginx 8.3.36 trixie 194.6 MB 186.5 MB serversideup/php-dev:739-8.3.36-fpm-nginx-trixie
fpm-nginx 8.2.35 alpine3.23 42.4 MB 43.0 MB serversideup/php-dev:739-8.2.35-fpm-nginx-alpine3.23
fpm-nginx 8.2.35 alpine3.24 43.8 MB 44.4 MB serversideup/php-dev:739-8.2.35-fpm-nginx-alpine3.24
fpm-nginx 8.2.35 bookworm 187.6 MB 180.5 MB serversideup/php-dev:739-8.2.35-fpm-nginx-bookworm
fpm-nginx 8.2.35 trixie 193.9 MB 185.8 MB serversideup/php-dev:739-8.2.35-fpm-nginx-trixie
fpm-nginx 8.1.34 alpine3.22 41.5 MB 42.2 MB serversideup/php-dev:739-8.1.34-fpm-nginx-alpine3.22
fpm-nginx 8.1.34 bookworm 186.9 MB 179.8 MB serversideup/php-dev:739-8.1.34-fpm-nginx-bookworm
fpm-nginx 8.1.34 trixie 193.3 MB 185.2 MB serversideup/php-dev:739-8.1.34-fpm-nginx-trixie
frankenphp 8.6-rc alpine3.23 76.5 MB 73.2 MB serversideup/php-dev:739-8.6-rc-frankenphp-alpine3.23
frankenphp 8.6-rc alpine3.24 76.5 MB 73.3 MB serversideup/php-dev:739-8.6-rc-frankenphp-alpine3.24
frankenphp 8.6-rc bookworm 220.2 MB 209.3 MB serversideup/php-dev:739-8.6-rc-frankenphp-bookworm
frankenphp 8.6-rc trixie 218.0 MB 206.5 MB serversideup/php-dev:739-8.6-rc-frankenphp-trixie
frankenphp 8.5.12 alpine3.23 77.8 MB 74.8 MB serversideup/php-dev:739-8.5.12-frankenphp-alpine3.23
frankenphp 8.5.12 alpine3.24 77.8 MB 74.9 MB serversideup/php-dev:739-8.5.12-frankenphp-alpine3.24
frankenphp 8.5.12 bookworm 221.4 MB 211.0 MB serversideup/php-dev:739-8.5.12-frankenphp-bookworm
frankenphp 8.5.12 trixie 219.4 MB 208.1 MB serversideup/php-dev:739-8.5.12-frankenphp-trixie
frankenphp 8.4.27 alpine3.23 73.5 MB 71.0 MB serversideup/php-dev:739-8.4.27-frankenphp-alpine3.23
frankenphp 8.4.27 alpine3.24 73.6 MB 71.1 MB serversideup/php-dev:739-8.4.27-frankenphp-alpine3.24
frankenphp 8.4.27 bookworm 217.3 MB 207.1 MB serversideup/php-dev:739-8.4.27-frankenphp-bookworm
frankenphp 8.4.27 trixie 215.2 MB 204.3 MB serversideup/php-dev:739-8.4.27-frankenphp-trixie
frankenphp 8.3.36 alpine3.23 68.6 MB 66.4 MB serversideup/php-dev:739-8.3.36-frankenphp-alpine3.23
frankenphp 8.3.36 alpine3.24 68.6 MB 66.4 MB serversideup/php-dev:739-8.3.36-frankenphp-alpine3.24
frankenphp 8.3.36 bookworm 212.3 MB 202.5 MB serversideup/php-dev:739-8.3.36-frankenphp-bookworm
frankenphp 8.3.36 trixie 210.2 MB 199.7 MB serversideup/php-dev:739-8.3.36-frankenphp-trixie

Updated on every push to this PR.

A base job whose runner dropped reports cancelled, not failure, so builds still ran and failed on a base image that was never saved. Build only when the base phase succeeded or was skipped (fork PRs).
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

Deploying serversideup-php with  Cloudflare Pages  Cloudflare Pages

Latest commit: 11d041c
Status: ✅  Deploy successful!
Preview URL: https://fa8c6c81.serversideup-php.pages.dev
Branch Preview URL: https://build-php-from-source-renova.serversideup-php.pages.dev

View logs

…lpine 3.23 and 3.24, Bookworm, and Trixie from the newest release candidate php.net lists. FrankenPHP uses the cli base, since docker-library builds every 8.6 image with ZTS. Upgrade install-php-extensions to 2.12.6 for its PHP 8.6 support.

phpredis 6.3.0 does not compile on PHP 8.6, so 8.6 builds phpredis at 810984b, the last develop commit before an added build option that install-php-extensions answers out of order."
…ION with FRANKENPHP_VERSION for synchronized updates
@jaydrogers
jaydrogers changed the base branch from main to release/improve-builds October 29, 2026 12:59
@jaydrogers
jaydrogers merged commit f9f7c55 into release/improve-builds Oct 29, 2026
215 checks passed
@jaydrogers
jaydrogers deleted the build-php-from-source-renovate branch October 29, 2026 13:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant