php/frankenphp

DevOps & Self-hosting

Serve PHP apps from one Go binary with built-in Caddy, worker mode and HTTP/2–3, for teams replacing nginx and PHP-FPM.

11,465
503
Go
MIT
4 years old

FrankenPHP is worth a look when you already run PHP behind nginx and PHP-FPM and want one process, one config and modern HTTP behaviour without a rewrite of the app. It is not a drop-in without reading the migration and known-issues pages first.

The problem

A typical PHP deployment splits responsibilities: nginx terminates TLS, serves static files and proxies requests, while PHP-FPM runs a pool of workers and PHP's classic per-request lifecycle throws away the bootstrap work on every hit. Changing that stack means touching two configs, two services and a TLS story, and the request lifecycle is fixed by the SAPI. FrankenPHP folds the web server and PHP into one binary, so the same process accepts the request, runs the handler and returns the response; the app code can stay largely the same while deployment and the request model change.

What's different

FrankenPHP embeds PHP in a Go process built on Caddy project instructionsCaddy. Caddy brings automatic HTTPS plus HTTP/2 and HTTP/3 project overview, and PHP bootstraps once in worker mode instead of per request worker mode docs. The documented payoff is that Laravel and Symfony can use their official worker integrations; the trade-off is that a long-lived worker changes how you think about state, so app code and extensions must behave in that mode. In classic mode the per-request lifecycle stays closer to PHP-FPM classic mode docs, which makes migration a mode choice rather than an all-or-nothing commitment.

Beyond the server core, there are Early Hints Early Hints, Mercure-based real-time push real-time and hot reloading for development hot reloading. FrankenPHP can also be used as a Go library to embed PHP in a net/http app Go library, which is a different use case: it makes PHP an implementation detail inside a Go service rather than a server you point at an existing project.

The important trade-off is scope: putting routing, TLS, static files, WebSocket-style push and the PHP runtime in one binary reduces moving parts, but it also means your web-server configuration is now FrankenPHP's Caddyfile rather than an nginx config that many teams already know. The migration guide exists for exactly that reason migration guide.

Who should try it

Good fit: a team running Laravel, Symfony, WordPress or Drupal on nginx plus PHP-FPM that wants a single deployable server, automatic TLS and worker mode, and is willing to test the app under a persistent worker. Framework-specific guides exist for Symfony, Laravel and WordPress, and community integrations cover Drupal, Joomla, TYPO3, Magento 2 and WoltLab.

Poor fit: a team that needs an exact nginx configuration, relies on per-request SAPI assumptions, or cannot test a persistent worker for state leaks. WordPress sites run with heavy third-party plugins are a particularly cautious case, because classic mode keeps the usual lifecycle.

Requirements and limitations

There are several install paths, not one requirement: a shell or PowerShell install script install script, standalone binaries bundling PHP 8.5 releases, maintainer-offered rpm, deb and apk packages, Homebrew Homebrew and Docker images Docker images. Extension availability differs by channel: the packaged routes install php-zts-<extension> from the same repositories, while other extensions go through PIE PIE. Check the extension you actually need against your chosen channel before committing.

Two ongoing constraints matter. First, worker mode is a behavioural change, so state and extension assumptions need checking, and the project keeps a known-issues page known issues for the sharp edges. Second, production deployment, performance tuning and observability have their own documentation productionperformanceobservability; this is a server you operate, not a library you add and forget. If you need to compile from source, there is a separate guide compile from source.

HotRepo's take

HotRepo has only one dated observation: #12 on the weekly Go board on 2026-10-26, at +67 stars that week, with no comparable daily-board history. That is a snapshot, not a trend, so persistence cannot be judged from it. The deciding question is practical: verify that the extensions your app needs are available in the install channel you plan to use, then test the app under worker mode before switching traffic.

Hacker News

FrankenPHP is now under PHP org
▲ 6 · 0 comments · June 6, 2025

Written by AI from the project's README, updated October 26, 2026. The project's own docs are the source of truth.