FrankenPHP: A Modern PHP Server Built on Caddy
PHP isn’t dead — it’s just been waiting for a better runtime. FrankenPHP is an embeddable PHP server that sits directly inside Caddy, the popular Go web server. No separate PHP-FPM, no config hacks. Just PHP glued into a fast, HTTPS-by-default server.
If you’ve ever wished PHP could feel more like a modern language runtime (think Node.js or Go’s standard library), this is worth a look.
What It Does
FrankenPHP wraps PHP into Caddy as a native module. You run your PHP app through Caddy’s reverse proxy, but instead of forwarding to a separate PHP-FPM process, Caddy talks directly to an embedded PHP interpreter.
The core idea: one binary, one process, zero config for TLS. You get automatic HTTPS via Let’s Encrypt, HTTP/2, HTTP/3, and a PHP worker mode that keeps your app in memory between requests.
Why It’s Cool
A few things stand out:
-
Worker mode – Instead of spawning a new PHP process per request (like traditional mod_php or FPM), FrankenPHP keeps your PHP app running persistently. Your bootstrap code runs once. No more loading Laravel or Symfony from scratch on every page load. Think of it like PHP-FPM’s
pm = staticon steroids. -
Early Hints (103 status code) – Caddy sends
103 Early Hintsto the browser before your PHP script finishes. The browser can start preloading CSS, JS, or images while PHP is still generating the response. This can shave off significant time for real-world pages, especially on slower connections. -
Automatic HTTPS, HTTP/2/3, and config-as-code – This is Caddy’s superpower, but now it’s married to your PHP app. You don’t need a separate reverse proxy or TLS manager. Write a simple
Caddyfileand go. -
Single binary deployment – With
CGO_ENABLED=1, you can compile a static binary that includes both Caddy and PHP. No dependencies. No “install PHP 8.2, enable extensions, configure FPM.” Just drop the binary on a server and run. -
Compatible with existing frameworks – Works with Laravel, Symfony, WordPress, Drupal, etc. No code changes needed. If it runs on PHP-FPM, it runs on FrankenPHP.
How to Try It
The easiest way is via Docker:
docker run -v $PWD:/app -p 80:80 -p 443:443 dunglas/frankenphp
This serves your current directory as a PHP app. Caddy will automatically handle HTTPS if you have a domain pointed at it.
Or if you want to play locally without a domain name:
docker run -v $PWD:/app -p 8080:80 -p 8443:443 -e SERVER_NAME=localhost dunglas/frankenphp
Then open http://localhost:8080 (or https://localhost:8443 if you accept the self-signed cert).
For a production setup, check the GitHub README — it covers running bare-metal, using a custom Caddyfile, and compiling your own binary.
Final Thoughts
FrankenPHP isn’t going to replace every PHP setup. But if you’re tired of managing a stack of PHP-FPM, nginx, and certbot, it’s a breath of fresh air. Worker mode alone can dramatically improve performance for framework-heavy apps, and Early Hints gives you a cheap front-end speed boost.
It’s still relatively new, but the approach feels right. PHP needs tools that match modern expectations — and embedding it into a server that handles TLS, HTTP/2, and configuration with minimal fuss is a step in that direction.
Try it on a side project. You might not go back.
Follow @githubprojects for more developer tools and open source highlights.