Download Latest Version frankenphp-windows-x86_64.zip (60.2 MB) Google Add to Preferred Sources
Home / v1.13.0
Name Modified Size InfoDownloads / Week
Parent folder
frankenphp-mac-x86_64 2026-10-04 191.1 MB
frankenphp-mac-arm64 2026-10-04 180.8 MB
frankenphp-linux-x86_64-mimalloc 2026-10-04 174.7 MB
frankenphp-linux-x86_64-debug 2026-10-04 228.6 MB
frankenphp-linux-x86_64-gnu 2026-10-04 169.7 MB
frankenphp-linux-x86_64 2026-10-04 174.6 MB
frankenphp-linux-aarch64-gnu 2026-10-04 162.7 MB
frankenphp-linux-aarch64 2026-10-04 168.1 MB
frankenphp-windows-x86_64.zip 2026-10-04 60.2 MB
README.md 2026-10-04 12.0 kB
v1.13.0 source code.tar.gz 2026-10-04 4.0 MB
v1.13.0 source code.zip 2026-10-04 4.2 MB
Totals: 12 Items   1.5 GB 1

FrankenPHP 1.13.0 is a big one. It upgrades to Caddy 2.11.7, bringing Slowloris protection, the new url_pattern matcher, the Incremental header for streaming apps and many reverse proxy fixes. It ships with Mercure 1.0, the stable version of the real-time protocol. Configuration reloads are now safe: an invalid configuration is rejected before it replaces the running one, instead of leaving the server answering 500. This release also fixes 5 security vulnerabilities, 2 of them rated high. Upgrading is strongly recommended, and the upgrade notes below are worth a read first. Need help with the upgrade or with sizing threads and workers? Les-Tilleuls.coop, the company behind FrankenPHP, provides professional support, performance audits, custom development and training: contact@les-tilleuls.coop.

🔒 Security

  • High: Fix a document-root escape in SCRIPT_FILENAME resolution on Windows (GHSA-868c-7h7m-mmj9).
  • High: Fix header spoofing through dot-form header names: PHP maps Foo.Bar to HTTP_FOO_BAR like Foo-Bar. Caddy 2.11.7 now drops such headers by default, and the NewRequestWithContext() documentation warns library users (GHSA-qcrp-8483-f2f2).
  • Require a path segment boundary when splitting the CGI path, so /uploads/a.php.txt/b.php no longer executes uploads/a.php (GHSA-xxjp-cjxr-2x6m).
  • putenv() no longer writes to the process-wide OS environment, which leaked values across requests and threads (GHSA-996f-w38m-f574).
  • Fix a crash of the whole server process when frankenphp_log() receives a crafted array (GHSA-4prg-hv4r-g6mv).

🌐 Caddy 2.11.7

FrankenPHP 1.12.7 shipped Caddy 2.11.4. This release includes everything from Caddy 2.11.6 and 2.11.7, including:

  • Slowloris protection: idle read/write timeouts reset on every successful read or write, so stalled connections are cut off while slow but progressing ones are left alone. Tune them per route with the new timeouts directive by @dunglas in caddy#7913.
  • url_pattern matcher: match requests with the URLPattern web standard (named groups, wildcards, regexps), the same syntax used by browsers and many frameworks. Captured groups become placeholders by @dunglas in caddy#7787.
  • Incremental header (RFC 10036): the standard replacement for NGINX's X-Accel-Buffering. Responses with Incremental: ?1 are streamed immediately by reverse_proxy and encode by @dunglas in caddy#8020.
  • Server-sent events behind encode now stream immediately instead of being buffered, which benefits Mercure by @SillyZir in caddy#7905.
  • Graceful shutdown waits for servers left over from previous configurations, so long-lived responses that started before a reload aren't cut off by @dunglas in caddy#8009.
  • tls_automate_names global option to manage certificates for names not served by a site block by @IslamElsayed in caddy#8015.
  • Faster TLS handshakes: certificate lookup is about twice as fast, with 10 allocations instead of 15 by @u5surf in caddy#8010.
  • Reverse proxy: partial responses are flushed properly by @WeidiDeng in caddy#7849, TCP half-close is propagated on upgraded streams by @btncwn in caddy#8027, and active health checks are isolated per check config by @SillyZir in caddy#7916.
  • expected_underscore_headers (by @bluegate-studio in caddy#7809) and expected_dot_headers keep specific headers that Caddy now drops.

📡 Mercure 1.0

FrankenPHP embeds Mercure 1.0 by @dunglas in #2611:

  • mercure_publish() now throws a ValueError for invalid updates (topic in the reserved /.well-known/mercure namespace, ID starting with #, control characters, invalid UTF-8, negative retry, no topic) and a RuntimeException carrying the hub's message when the dispatch fails.
  • Publisher and subscriber keys are bound to a trusted issuer with the new issuer block. The sample Caddyfile and php-server --mercure use it.

⚠️ Upgrade Notes

  • num_threads now counts the threads for requests no worker serves; worker threads come on top. A configuration that sets num_threads with workers declared starts more threads than before. If max_threads is below num_threads plus the worker threads, startup now fails with an error naming the three numbers. Defaults are unchanged (#2660).
  • Mercure: setting publisher_jwt or subscriber_jwt without protocol_version_compatibility is now a configuration error. Bind keys to a trusted issuer with the new issuer block instead (see #2611 and the sample Caddyfile). Hot reloading follows the protocol: $_SERVER['FRANKENPHP_HOT_RELOAD'] now advertises /.well-known/mercure?match=<topic>, so update any URL hardcoded with ?topic=.
  • Caddy: request headers are now limited to 16 KiB by default (raise it with max_header_size), stalled reads and writes are aborted after 1 minute, headers containing . are dropped like those containing _ already were, a wildcard site's client_auth no longer applies to more specific sites, and some invalid configurations are now rejected. See the Caddy 2.11.6 breaking changes.
  • Building PHP without --disable-zend-signals (ZTS) now makes FrankenPHP refuse to start with an explicit error, instead of hanging while memory grows (#2639).

✨ New Features

  • Extensions: Expose a thread API for Go-based PHP extensions: Thread(index) to get the request bound to a PHP thread, PHPThread.Pin() to keep Go objects alive, PHPThread.IsRequestDone(), and the frankenphp_thread_index() C function by @johanjanssens in #2305.
  • Config reloads: Validate a configuration before it replaces the running one. A missing worker file, a duplicated worker name or an inconsistent thread budget is now rejected and the running configuration keeps serving. Library users get frankenphp.Validate() by @nicolas-grekas in #2661.
  • Threads: num_threads counts the threads left for regular requests, and the startup log reports total_threads and worker_threads by @nicolas-grekas in #2660.
  • Opcache: Log opcache shared-memory restarts and count them in the new experimental frankenphp_opcache_restarts{reason} metric (PHP 8.4+). These restarts are unsafe under ZTS, so the counter should stay at zero by @nicolas-grekas in #2634.
  • php_server: Mirror php_server blocks on the FrankenPHP side, so requests and workers are properly scoped to their block by @AlliBalliBaba in #2499.
  • phpinfo: phpinfo() now has a FrankenPHP section listing the Caddy version, and Go code can add rows with frankenphp.AddPHPInfoEntry() by @henderkes in #2578.
  • CLI: php-cli uses PHP's built-in CLI SAPI on PHP 8.5+ by @withinboredom in #1757.
  • PHP 8.6: Compatibility with PHP 8.6 by @henderkes in #2600.
  • Upgrade to Go 1.27 by @alexandre-daubois in #2626.

🐛 Bug Fixes

  • Startup: Don't hang requests that arrive before regular threads are ready, which showed up as random 499/504 errors on the first requests after a container start by @ptondereau in #2612.
  • Workers: Log worker crashes at warn level with their exit status, instead of debug like a clean restart by @luminalpark in #2602.
  • Shutdown: Fix Shutdown() hanging forever on a worker that gave up during boot past max_consecutive_failures by @nicolas-grekas in #2662 and #2664.
  • Static builds: Stop the bundled parallel extension from turning recoverable Go faults into process crashes by @henderkes in #2651. Fixes #2650.
  • Extensions: Fix a possible use-after-free of the extensions array retained by register_extensions by @henderkes in #2646. Fixes #2629.
  • extgen: Fix grouped and nullable parameters, callables, mixed return values, method wrappers, constants and integer literals in generated extensions by @alexandre-daubois in #2596.

📖 Documentation

  • List runtime engine settings that persist between requests in worker mode (ini_set(), stream_context_set_default(), date_default_timezone_set(), chdir()…) by @dunglas in #2682.
  • Document HTTP request filtering differences by @ousamabenyounes in #2561.
  • Enhance the metrics documentation by @alexandre-daubois in #2316.
  • Add a Yii 3 page by @KalimeroMK in #2615.
  • Fix the broken Idiomorph CDN URL in the hot reload snippet by @quyt0 in #2642.
  • Add missing Turkish translations by @mertingen in #2663.

💖 New Contributors

  • @johanjanssens made their first contribution in #2305
  • @luminalpark made their first contribution in #2602
  • @KalimeroMK made their first contribution in #2615
  • @quyt0 made their first contribution in #2642

Full Changelog: https://github.com/php/frankenphp/compare/v1.12.7...v1.13.0

Source: README.md, updated 2026-10-04