One binary, my code, a Caddyfile. That is the whole deployment of a small internal service I moved to FrankenPHP in staging this week.
The classic PHP deployment is a couple: Nginx in front, PHP-FPM behind, FastCGI between them. Two configs, two processes to supervise, one socket to misconfigure. It works, we all know it by heart, and knowing it by heart is the only reason we call it simple.
FrankenPHP folds the pair into one binary. It is Caddy, the Go web server, with PHP embedded inside. The request does not travel over FastCGI to a separate process pool. The server runs your script itself. You get HTTP/2, HTTP/3 and automatic HTTPS because Caddy brings them. For a container image this is honestly attractive. The Nginx-plus-FPM image with supervisord inside always felt like a small apartment with too many tenants.
There is also worker mode. The application boots once and stays in memory, requests are handled by the already-booted app. Same idea as RoadRunner or Octane, same wins, same fine print: request state must be cleaned, transactions must not leak between requests, memory must be watched. I wrote about that discipline in April, all of it applies here unchanged. Classic mode, one fresh script per request, is the safe entry.
Production material today: not yet. The project is young and moving fast, no stable 1.0. I would not move a money-handling monolith this week. But the staging experience is pleasant: config is short, TLS is automatic, one process to watch instead of three.
FPM solved process management for the shared-hosting era. Containers changed the question. A static binary that speaks modern HTTP and runs my app is a good answer to the new one.
I will keep the Nginx config around a while longer. Not because I need it. Because I know it by heart.