Introduction to FrankenPHP

FrankenPHP is a new PHP runtime designed to modernize PHP architecture. It is built on top of Caddy, and it includes Caddy’s built-in features such as automatic SSL, native support for HTTP3, and Early Hints. It also supports compression methods like Gzip, Brotli, and Zstd. Additionally, it features a built-in Mercure hub, enabling real-time push events without the need for additional libraries or SDKs.

With all these features, FrankenPHP promises faster performance out-of-the-box, simpler configuration, and an improved Developer Experience (DX) compared to traditional PHP setups like PHP-FPM.

Here is how it compares:

Feature FrankenPHP PHP-FPM
Performance Great performance with worker mode and direct communication with the web server, reducing latency. Good performance, but it requires FastCGI communication which may introduce some overhead.
Scalability Excellent scalability. It can be compiled into a single binary, making it easy to run on serverless architectures. Good scalability, but often requires manual tuning of process pools on both the PHP-FPM and the web server side (usually Nginx).
Complexity Generally simple with minimal configuration overhead, thanks to Caddy’s configuration. Somewhat complex, involving separate configurations for PHP-FPM and the web server (usually Nginx).

Getting Started

Running FrankenPHP requires Docker. It is pre-packaged in a single Docker image, so you don’t need to install PHP binaries and modules yourself. Once you have Docker installed, you need to create the index.php file, which will serve as the homepage.

In this example, let’s keep it simple. I will just print the PHP info table.


You can now run the following Docker command to start the site:

docker run -v $PWD:/app/public -p 80:80 -p 443:443 -p 443:443/udp dunglas/frankenphp

This command mounts the current directory to the /app/public directory in the Docker container and maps ports 80 and 443 from the container to the host machine, as well as 443/udp to enable HTTP3.

Caddy also generates SSL certificates and loads the site over HTTPS. However, your browser won’t recognize the SSL certificate for localhost, so you will receive an error when you load the site.

SSL error message

There are a few ways we can create a workaround to let HTTPS load on localhost. The easiest and quickest method that works in different scenarios is to enable the flag in Chrome at chrome://flags/#allow-insecure-localhost. Restart Chrome, and then reload the page.

Loaded localhost site

Now, your localhost runs on the FrankenPHP server API. If you inspect the response in Chrome, you’ll see that it’s compressed with zstd and served through HTTP3.

It’s impressive that we can have it running with just a single command.

Running a Framework

FrankenPHP is not limited to just running a simple PHP file. It is compatible and can run a full-fledged PHP framework such as Symfony, Laravel, or any other PHP framework. The only thing you need to do is mount the framework directory to the /app/public directory in the Docker container. For example, to run a Laravel application, you can run the following command:

docker run -v $PWD:/app -p 80:80 -p 443:443 -p 443:443/udp dunglas/frankenphp

It’s that simple. FrankenPHP will automatically detect the files and serve the Laravel application.

Laravel app running

Wrapping Up

All these features like automatic SSL, HTTP3, and modern compression make developing and running PHP applications much easier and faster. If you’re coming from nginx or Apache, like me, the only thing you need to get used to is the Caddyfile configuration. But once you get accustomed to it, you’ll find it much simpler and more powerful than traditional web server configurations.

I think FrankenPHP is a great choice for modern PHP applications. It’s fast, scalable, and easy to use. I highly recommend it for any PHP developers looking to give it a try.