FrankenPHP has the ability to embed the source code and assets of PHP applications in a static, self-contained binary.
Thanks to this feature, PHP applications can be distributed as standalone binaries that include the application itself, the PHP interpreter, and Caddy, a production-level web server.
Learn more about this feature in the presentation made by Kévin at SymfonyCon 2023.
For embedding Laravel applications, read this specific documentation entry.
Before creating the self-contained binary be sure that your app is ready for embedding.
For instance, you likely want to:
- Install the production dependencies of the app
- Dump the autoloader
- Enable the production mode of your application (if any)
- Strip unneeded files such as
.git
or tests to reduce the size of your final binary
For instance, for a Symfony app, you can use the following commands:
# Export the project to get rid of .git/, etc
mkdir $TMPDIR/my-prepared-app
git archive HEAD | tar -x -C $TMPDIR/my-prepared-app
cd $TMPDIR/my-prepared-app
# Set proper environment variables
echo APP_ENV=prod > .env.local
echo APP_DEBUG=0 >> .env.local
# Remove the tests and other unneeded files to save space
# Alternatively, add these files with the export-ignore attribute in your .gitattributes file
rm -Rf tests/
# Install the dependencies
composer install --ignore-platform-reqs --no-dev -a
# Optimize .env
composer dump-env prod
To customize the configuration, you can put a Caddyfile
as well as a php.ini
file
in the main directory of the app to be embedded ($TMPDIR/my-prepared-app
in the previous example).
The easiest way to create a Linux binary is to use the Docker-based builder we provide.
-
Create a file named
static-build.Dockerfile
in the repository of your app:FROM --platform=linux/amd64 dunglas/frankenphp:static-builder # Copy your app WORKDIR /go/src/app/dist/app COPY . . # Build the static binary WORKDIR /go/src/app/ RUN EMBED=dist/app/ ./build-static.sh
[!CAUTION]
Some
.dockerignore
files (e.g. default Symfony Docker.dockerignore
) will ignore thevendor/
directory and.env
files. Be sure to adjust or remove the.dockerignore
file before the build. -
Build:
docker build -t static-app -f static-build.Dockerfile .
-
Extract the binary:
docker cp $(docker create --name static-app-tmp static-app):/go/src/app/dist/frankenphp-linux-x86_64 my-app ; docker rm static-app-tmp
The resulting binary is the file named my-app
in the current directory.
If you don't want to use Docker, or want to build a macOS binary, use the shell script we provide:
git clone https://github.com/dunglas/frankenphp
cd frankenphp
EMBED=/path/to/your/app ./build-static.sh
The resulting binary is the file named frankenphp-<os>-<arch>
in the dist/
directory.
This is it! The my-app
file (or dist/frankenphp-<os>-<arch>
on other OSes) contains your self-contained app!
To start the web app run:
./my-app php-server
If your app contains a worker script, start the worker with something like:
./my-app php-server --worker public/index.php
To enable HTTPS (a Let's Encrypt certificate is automatically created), HTTP/2, and HTTP/3, specify the domain name to use:
./my-app php-server --domain localhost
You can also run the PHP CLI scripts embedded in your binary:
./my-app php-cli bin/console
By default, the script will build extensions required by the composer.json
file of your project, if any.
If the composer.json
file doesn't exist, the default extensions are built, as documented in the static builds entry.
To customize the extensions, use the PHP_EXTENSIONS
environment variable.
Read the static build documentation to see how to customize the binary (extensions, PHP version...).
On Linux, the created binary is compressed using UPX.
On Mac, to reduce the size of the file before sending it, you can compress it.
We recommend xz
.