From 99444159835cbbabab4f9def613929c8cf5eed13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Wed, 25 Mar 2026 19:54:29 +0100 Subject: [PATCH 1/5] docs: add Symfony-specific page --- CONTRIBUTING.md | 72 +++++++-------- README.md | 7 +- docs/symfony.md | 233 ++++++++++++++++++++++++++++++++++++++++++++++++ docs/worker.md | 23 +---- 4 files changed, 275 insertions(+), 60 deletions(-) create mode 100644 docs/symfony.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ff68f1b2f8..c8f35ff678 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -90,60 +90,60 @@ curl -v http://127.0.0.1:8080/phpinfo.php 1. Configure Git to always use `lf` line endings - ```powershell - git config --global core.autocrlf false - git config --global core.eol lf - ``` + ```powershell + git config --global core.autocrlf false + git config --global core.eol lf + ``` 2. Install Visual Studio, Git, and Go: - ```powershell - winget install -e --id Microsoft.VisualStudio.2022.Community --override "--passive --wait --add Microsoft.VisualStudio.Workload.NativeDesktop --add Microsoft.VisualStudio.Component.VC.Llvm.Clang --includeRecommended" - winget install -e --id GoLang.Go - winget install -e --id Git.Git - ``` + ```powershell + winget install -e --id Microsoft.VisualStudio.2022.Community --override "--passive --wait --add Microsoft.VisualStudio.Workload.NativeDesktop --add Microsoft.VisualStudio.Component.VC.Llvm.Clang --includeRecommended" + winget install -e --id GoLang.Go + winget install -e --id Git.Git + ``` 3. Install vcpkg: - ```powershell - cd C:\ - git clone https://github.com/microsoft/vcpkg - .\vcpkg\bootstrap-vcpkg.bat - ``` + ```powershell + cd C:\ + git clone https://github.com/microsoft/vcpkg + .\vcpkg\bootstrap-vcpkg.bat + ``` 4. [Download the latest version of the watcher library for Windows](https://github.com/e-dant/watcher/releases) and extract it to a directory named `C:\watcher` 5. [Download the latest **Thread Safe** version of PHP and of the PHP SDK for Windows](https://windows.php.net/download/), extract them in directories named `C:\php` and `C:\php-devel` 6. Clone the FrankenPHP Git repository: - ```powershell - git clone https://github.com/php/frankenphp C:\frankenphp - cd C:\frankenphp - ``` + ```powershell + git clone https://github.com/php/frankenphp C:\frankenphp + cd C:\frankenphp + ``` 7. Install the dependencies: - ```powershell - C:\vcpkg\vcpkg.exe install - ``` + ```powershell + C:\vcpkg\vcpkg.exe install + ``` 8. Configure the needed environment variables (PowerShell): - ```powershell - $env:PATH += ';C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\Llvm\bin' - $env:CC = 'clang' - $env:CXX = 'clang++' - $env:CGO_CFLAGS = "-O0 -g -IC:\frankenphp\vcpkg_installed\x64-windows\include -IC:\watcher -IC:\php-devel\include -IC:\php-devel\include\main -IC:\php-devel\include\TSRM -IC:\php-devel\include\Zend -IC:\php-devel\include\ext" - $env:CGO_LDFLAGS = '-LC:\frankenphp\vcpkg_installed\x64-windows\lib -lbrotlienc -LC:\watcher -llibwatcher-c -LC:\php -LC:\php-devel\lib -lphp8ts -lphp8embed' - ``` + ```powershell + $env:PATH += ';C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\Llvm\bin' + $env:CC = 'clang' + $env:CXX = 'clang++' + $env:CGO_CFLAGS = "-O0 -g -IC:\frankenphp\vcpkg_installed\x64-windows\include -IC:\watcher -IC:\php-devel\include -IC:\php-devel\include\main -IC:\php-devel\include\TSRM -IC:\php-devel\include\Zend -IC:\php-devel\include\ext" + $env:CGO_LDFLAGS = '-LC:\frankenphp\vcpkg_installed\x64-windows\lib -lbrotlienc -LC:\watcher -llibwatcher-c -LC:\php -LC:\php-devel\lib -lphp8ts -lphp8embed' + ``` 9. Run the tests: - ```powershell - go test -race -ldflags '-extldflags="-fuse-ld=lld"' ./... - cd caddy - go test -race -ldflags '-extldflags="-fuse-ld=lld"' -tags nobadger,nomysql,nopgx ./... - cd .. - ``` + ```powershell + go test -race -ldflags '-extldflags="-fuse-ld=lld"' ./... + cd caddy + go test -race -ldflags '-extldflags="-fuse-ld=lld"' -tags nobadger,nomysql,nopgx ./... + cd .. + ``` 10. Build the binary: @@ -299,7 +299,7 @@ The steps assume the following environment: 4. Debug Go files from CLion - - Right click on a *.go file in the Project view on the left + - Right click on a \*.go file in the Project view on the left - Override file type → C/C++ Now you can place breakpoints in C, C++ and Go files. @@ -348,7 +348,7 @@ Use GoLand for primary Go development, but the debugger cannot debug C code. To debug C files from GoLand -- Right click on a *.c file in the Project view on the left +- Right click on a \*.c file in the Project view on the left - Override file type → Go Now you can place breakpoints in C, C++ and Go files. diff --git a/README.md b/README.md index a2010a7842..0ee36253d2 100644 --- a/README.md +++ b/README.md @@ -90,8 +90,8 @@ Our maintainers offer apk packages for all systems using `apk`. To install, run: VERSION=85 # 82-85 available echo "https://pkg.henderkes.com/api/packages/${VERSION}/alpine/main/php-zts" | sudo tee -a /etc/apk/repositories KEYFILE=$(curl -sJOw '%{filename_effective}' https://pkg.henderkes.com/api/packages/${VERSION}/alpine/key) -sudo mv ${KEYFILE} /etc/apk/keys/ && -sudo apk update && +sudo mv ${KEYFILE} /etc/apk/keys/ && +sudo apk update && sudo apk add frankenphp ``` @@ -170,6 +170,7 @@ Go to `https://localhost`, and enjoy! - [Compile from sources](https://frankenphp.dev/docs/compile/) - [Monitoring FrankenPHP](https://frankenphp.dev/docs/metrics/) - [WordPress integration](https://frankenphp.dev/docs/wordpress/) +- [Symfony integration](https://frankenphp.dev/docs/symfony/) - [Laravel integration](https://frankenphp.dev/docs/laravel/) - [Known issues](https://frankenphp.dev/docs/known-issues/) - [Demo app (Symfony) and benchmarks](https://github.com/dunglas/frankenphp-demo) @@ -178,7 +179,7 @@ Go to `https://localhost`, and enjoy! ## Examples and Skeletons -- [Symfony](https://github.com/dunglas/symfony-docker) +- [Symfony](https://frankenphp.dev/docs/symfony/) - [API Platform](https://api-platform.com/docs/symfony) - [Laravel](https://frankenphp.dev/docs/laravel/) - [Sulu](https://sulu.io/blog/running-sulu-with-frankenphp) diff --git a/docs/symfony.md b/docs/symfony.md new file mode 100644 index 0000000000..7c22a32256 --- /dev/null +++ b/docs/symfony.md @@ -0,0 +1,233 @@ +# Symfony + +## Docker + +For [Symfony](https://symfony.com) projects, we recommend using [Symfony Docker](https://github.com/dunglas/symfony-docker), the official Symfony Docker setup maintained by FrankenPHP's author. It provides a complete Docker-based environment with FrankenPHP, automatic HTTPS, HTTP/2, HTTP/3, and worker mode support out of the box. + +## Local Installation + +Alternatively, you can run your Symfony projects with FrankenPHP from your local machine: + +1. [Download the binary corresponding to your system](../README.md#standalone-binary) +2. Add the following configuration to a file named `Caddyfile` in the root directory of your Symfony project: + + ```caddyfile + # The domain name of your server + localhost { + # Set the webroot to the public/ directory + root public/ + # Enable compression (optional) + encode zstd br gzip + + + # Rewrite requests to non-existing files to the front controller + @phpRoute { + not file {path} + } + rewrite @phpRoute index.php + + @frontController path index.php + php @frontController { + # Optional: Enable worker mode for better performance + worker { + file ./public/index.php + } + } + + file_server { + hide *.php + } + } + ``` + + See the [performance documentation](performance.md) for further optimizations. + +3. Start FrankenPHP from the root directory of your Symfony project: `frankenphp run` + +## Worker Mode + +Since Symfony 7.4, FrankenPHP worker mode is natively supported. + +For older versions, install the FrankenPHP package of [PHP Runtime](https://github.com/php-runtime/runtime): + +```console +composer require runtime/frankenphp-symfony +``` + +Start your app server by defining the `APP_RUNTIME` environment variable to use the FrankenPHP Symfony Runtime: + +```console +docker run \ + -e FRANKENPHP_CONFIG="worker ./public/index.php" \ + -e APP_RUNTIME=Runtime\\FrankenPhpSymfony\\Runtime \ + -v $PWD:/app \ + -p 80:80 -p 443:443 -p 443:443/udp \ + dunglas/frankenphp +``` + +Learn more about [the worker mode](worker.md). + +## Hot Reload + +Hot reloading is enabled by default in [Symfony Docker](https://github.com/dunglas/symfony-docker). + +To use the [hot reload](hot-reload.md) feature without Symfony Docker, enable [Mercure](mercure.md) and add the `hot_reload` sub-directive to the `php` directive in your `Caddyfile`: + +```caddyfile +localhost + +mercure { + anonymous +} + +root public/ + +@phpRoute { + not path /.well-known/mercure* + not file {path} +} +rewrite @phpRoute index.php + +@frontController path index.php +php @frontController { + hot_reload + # Optional: enable worker in watch mode for better performance + worker { + file ./public/index.php + watch + } +} + +file_server { + hide *.php +} +``` + +Then, add the following code to your `templates/base.html.twig` file: + +```twig +{% if app.request.server.has('FRANKENPHP_HOT_RELOAD') %} + + + +{% endif %} +``` + +Finally, run `frankenphp run` from the root directory of your Symfony project. + +## Pre-Compressing Assets + +Symfony's [AssetMapper component](https://symfony.com/doc/current/frontend/asset_mapper.html) can pre-compress assets with Brotli and Zstandard during deployment. FrankenPHP (through Caddy's `file_server`) can serve these pre-compressed files directly, avoiding on-the-fly compression overhead. + +1. Compile and compress your assets: + + ```console + php bin/console asset-map:compile + ``` + +2. Update your `Caddyfile` to serve pre-compressed assets: + + ```caddyfile + { + frankenphp + } + + localhost { + root public/ + + @phpRoute { + not file {path} + } + rewrite @phpRoute index.php + + @frontController path index.php + php @frontController { + # Optional: Enable worker mode for better performance + worker { + file ./public/index.php + } + } + + @assets path /assets/* + file_server @assets { + precompressed zstd br gzip + } + + file_server { + hide *.php + } + } + ``` + +The `precompressed` directive tells Caddy to look for pre-compressed versions of the requested file (e.g., `app.css.zst`, `app.css.br`) and serve them directly if the client supports it. + +## Symfony Apps As Standalone Binaries + +Using [FrankenPHP's application embedding feature](embed.md), it's possible to distribute Symfony +apps as standalone binaries. + +Follow these steps to prepare and package your Symfony app: + +1. Prepare your app: + + ```console + # 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 + ``` + +2. Create a file named `static-build.Dockerfile` in the repository of your app: + + ```dockerfile + FROM --platform=linux/amd64 dunglas/frankenphp:static-builder-gnu + # If you intend to run the binary on musl-libc systems, use static-builder-musl instead + + # 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`](https://github.com/dunglas/symfony-docker/blob/main/.dockerignore)) + > will ignore the `vendor/` directory and `.env` files. Be sure to adjust or remove the `.dockerignore` file before the build. + +3. Build: + + ```console + docker build -t static-symfony-app -f static-build.Dockerfile . + ``` + +4. Extract the binary: + + ```console + docker cp $(docker create --name static-symfony-app-tmp static-symfony-app):/go/src/app/dist/frankenphp-linux-x86_64 my-app ; docker rm static-symfony-app-tmp + ``` + +5. Start the server: + + ```console + ./my-app php-server + ``` + +Learn more about the options available and how to build binaries for other OSes in the [applications embedding](embed.md) +documentation. diff --git a/docs/worker.md b/docs/worker.md index f952c305c5..65e7e3b0d9 100644 --- a/docs/worker.md +++ b/docs/worker.md @@ -37,28 +37,9 @@ frankenphp php-server --worker /path/to/your/worker/script.php --watch="/path/to This feature is often used in combination with [hot reloading](hot-reload.md). -## Symfony Runtime +## Symfony -> [!TIP] -> The following section is only necessary prior to Symfony 7.4, where native support for FrankenPHP worker mode was introduced. - -The worker mode of FrankenPHP is supported by the [Symfony Runtime Component](https://symfony.com/doc/current/components/runtime.html). -To start any Symfony application in a worker, install the FrankenPHP package of [PHP Runtime](https://github.com/php-runtime/runtime): - -```console -composer require runtime/frankenphp-symfony -``` - -Start your app server by defining the `APP_RUNTIME` environment variable to use the FrankenPHP Symfony Runtime: - -```console -docker run \ - -e FRANKENPHP_CONFIG="worker ./public/index.php" \ - -e APP_RUNTIME=Runtime\\FrankenPhpSymfony\\Runtime \ - -v $PWD:/app \ - -p 80:80 -p 443:443 -p 443:443/udp \ - dunglas/frankenphp -``` +See [the dedicated documentation](symfony.md#worker-mode). ## Laravel Octane From 45aa57880942ea0ba4dc001aea8a3f5ea4c5d468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 26 Mar 2026 09:54:11 +0100 Subject: [PATCH 2/5] review --- docs/symfony.md | 87 +++++++++---------------------------------------- 1 file changed, 16 insertions(+), 71 deletions(-) diff --git a/docs/symfony.md b/docs/symfony.md index 7c22a32256..f74d37db26 100644 --- a/docs/symfony.md +++ b/docs/symfony.md @@ -8,35 +8,16 @@ For [Symfony](https://symfony.com) projects, we recommend using [Symfony Docker] Alternatively, you can run your Symfony projects with FrankenPHP from your local machine: -1. [Download the binary corresponding to your system](../README.md#standalone-binary) +1. [Install FrankenPHP](../#getting-started) 2. Add the following configuration to a file named `Caddyfile` in the root directory of your Symfony project: ```caddyfile # The domain name of your server - localhost { - # Set the webroot to the public/ directory - root public/ - # Enable compression (optional) - encode zstd br gzip - - - # Rewrite requests to non-existing files to the front controller - @phpRoute { - not file {path} - } - rewrite @phpRoute index.php - - @frontController path index.php - php @frontController { - # Optional: Enable worker mode for better performance - worker { - file ./public/index.php - } - } - - file_server { - hide *.php - } + localhost + + php_server { + # Optional: Enable worker mode for better performance + worker index.php } ``` @@ -71,7 +52,7 @@ Learn more about [the worker mode](worker.md). Hot reloading is enabled by default in [Symfony Docker](https://github.com/dunglas/symfony-docker). -To use the [hot reload](hot-reload.md) feature without Symfony Docker, enable [Mercure](mercure.md) and add the `hot_reload` sub-directive to the `php` directive in your `Caddyfile`: +To use the [hot reload](hot-reload.md) feature without Symfony Docker, enable [Mercure](mercure.md) and add the `hot_reload` sub-directive to the `php_server` directive in your `Caddyfile`: ```caddyfile localhost @@ -80,26 +61,9 @@ mercure { anonymous } -root public/ - -@phpRoute { - not path /.well-known/mercure* - not file {path} -} -rewrite @phpRoute index.php - -@frontController path index.php -php @frontController { +php_server { hot_reload - # Optional: enable worker in watch mode for better performance - worker { - file ./public/index.php - watch - } -} - -file_server { - hide *.php + worker index.php } ``` @@ -128,34 +92,15 @@ Symfony's [AssetMapper component](https://symfony.com/doc/current/frontend/asset 2. Update your `Caddyfile` to serve pre-compressed assets: ```caddyfile - { - frankenphp + localhost + + @assets path /assets/* + file_server @assets { + precompressed zstd br gzip } - localhost { - root public/ - - @phpRoute { - not file {path} - } - rewrite @phpRoute index.php - - @frontController path index.php - php @frontController { - # Optional: Enable worker mode for better performance - worker { - file ./public/index.php - } - } - - @assets path /assets/* - file_server @assets { - precompressed zstd br gzip - } - - file_server { - hide *.php - } + php_server { + worker index.php } ``` From 374697b7bc90e948f2f5d747079d96353605844b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Wed, 25 Mar 2026 19:56:37 +0100 Subject: [PATCH 3/5] Update CONTRIBUTING.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Dunglas --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c8f35ff678..260d076c3a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -299,7 +299,7 @@ The steps assume the following environment: 4. Debug Go files from CLion - - Right click on a \*.go file in the Project view on the left + - Right click on a *.go file in the Project view on the left - Override file type → C/C++ Now you can place breakpoints in C, C++ and Go files. @@ -348,7 +348,7 @@ Use GoLand for primary Go development, but the debugger cannot debug C code. To debug C files from GoLand -- Right click on a \*.c file in the Project view on the left +- Right click on a *.c file in the Project view on the left - Override file type → Go Now you can place breakpoints in C, C++ and Go files. From 5eeb5971fbbd6ac18c6006752f7a193f3f656274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 26 Mar 2026 11:49:33 +0100 Subject: [PATCH 4/5] Update symfony.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Dunglas --- docs/symfony.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/symfony.md b/docs/symfony.md index f74d37db26..8df60dba9c 100644 --- a/docs/symfony.md +++ b/docs/symfony.md @@ -15,9 +15,10 @@ Alternatively, you can run your Symfony projects with FrankenPHP from your local # The domain name of your server localhost + root public/ php_server { # Optional: Enable worker mode for better performance - worker index.php + worker ./public/index.php } ``` @@ -61,9 +62,10 @@ mercure { anonymous } +root public/ php_server { hot_reload - worker index.php + worker ./public/index.php } ``` @@ -99,8 +101,9 @@ Symfony's [AssetMapper component](https://symfony.com/doc/current/frontend/asset precompressed zstd br gzip } + root public/ php_server { - worker index.php + worker ./public/index.php } ``` From 935119523607a55e36854336763b1e2524520ffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 26 Mar 2026 11:52:51 +0100 Subject: [PATCH 5/5] x-sendfile --- docs/symfony.md | 16 ++++++++++++++++ docs/x-sendfile.md | 12 +----------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/docs/symfony.md b/docs/symfony.md index 8df60dba9c..54acb5cefb 100644 --- a/docs/symfony.md +++ b/docs/symfony.md @@ -109,6 +109,22 @@ Symfony's [AssetMapper component](https://symfony.com/doc/current/frontend/asset The `precompressed` directive tells Caddy to look for pre-compressed versions of the requested file (e.g., `app.css.zst`, `app.css.br`) and serve them directly if the client supports it. +## Serving Large Static Files (`X-Sendfile`) + +FrankenPHP supports [efficiently serving large static files](x-sendfile.md) after executing PHP code (for access control, statistics, etc.). + +Symfony HttpFoundation [natively supports this feature](https://symfony.com/doc/current/components/http_foundation.html#serving-files). +After [configuring your `Caddyfile`](x-sendfile.md#configuration), it will automatically determine the correct value for the `X-Accel-Redirect` header and add it to the response: + +```php +use Symfony\Component\HttpFoundation\BinaryFileResponse; + +BinaryFileResponse::trustXSendfileTypeHeader(); +$response = new BinaryFileResponse(__DIR__.'/../private-files/file.txt'); + +// ... +``` + ## Symfony Apps As Standalone Binaries Using [FrankenPHP's application embedding feature](embed.md), it's possible to distribute Symfony diff --git a/docs/x-sendfile.md b/docs/x-sendfile.md index 8017f3d5b7..f9513c346d 100644 --- a/docs/x-sendfile.md +++ b/docs/x-sendfile.md @@ -58,14 +58,4 @@ header('X-Accel-Redirect: file.txt'); ## Projects using the Symfony HttpFoundation component (Symfony, Laravel, Drupal...) -Symfony HttpFoundation [natively supports this feature](https://symfony.com/doc/current/components/http_foundation.html#serving-files). -It will automatically determine the correct value for the `X-Accel-Redirect` header and add it to the response. - -```php -use Symfony\Component\HttpFoundation\BinaryFileResponse; - -BinaryFileResponse::trustXSendfileTypeHeader(); -$response = new BinaryFileResponse(__DIR__.'/../private-files/file.txt'); - -// ... -``` +See [the Symfony documentation](symfony.md#serving-large-static-files-x-sendfile) for details on using this feature with Symfony HttpFoundation.