New greener region discount. Save 3% on Upsun resource usage. Learn how.
LoginFree trial
FeaturesPricingBlogAbout us
Blog

Up(sun) and running with FrankenPHP

PHPFrankenPHPsymfony
Florent Huck
Florent Huck
DevRel Engineer

We’re here to shed a little light on how you can use and configure FrankenPHP—a modern PHP app server, written in Go and designed to accelerate your PHP applications—on Upsun with our step-by-step guide.

How to start using FrankenPHP on Upsun

To perform the following steps in this guide, you need to host your PHP application on Upsun—for details on how to do so, follow this simple tutorial on how to host a Symfony Demo application on Upsun. 

Please note: if you’re using your own PHP codebase, you will need to replace all of the symfony CLI calls in this blogpost with upsun CLI calls, like:

upsun branch staging --type staging

Create a staging environment

As we never (ever) test new features directly on production, we will create a new environment to test and configure our Symfony Demo application to use FrankenPHP. 

To create a new environment on our project, use the following command:

symfony branch staging --type=staging

This command creates a new active staging environment (of type staging) and automatically switches your local Git branch to staging.

How to use FrankenPHP on Upsun 

Now it’s time to show you how to use FrankenPHP, this rad PHP web server was designed for a similar purpose to Swoole and RoadRunner: to increase the speed of your PHP application loading time. So, how do you configure it in Upsun? 

Kevin Dunglas, from Les Tilleuls, provides a built-in FrankenPHP image that can be used to run a FrankenPHP PHP server if preferred to the PHP-FPM server provided by Upsun.

To do so, open your source code in your favorite IDE, and let’s update your .upsun/config.yaml file by completing the following steps:

1. Find the applications.app.web section and change it accordingly: all of the HTTP calls need to pass through the application and the default upstream HTTP protocol needs to use tcp unix sockets. You also need to define a commands.start to start the FrankenPHP server. 


applications:
  app:
    ...
    web:
      locations:
        "/":
          root: "public"
          expires: 1h
          #passthru: "/index.php"
          passthru: true
          scripts: false
          allow: false
      upstream:
        # important for PHP we default to unix sockets
        socket_family: tcp
        protocol: http
      commands:
        start: ./frankenphp php-server --listen=localhost:$PORT --root=$PLATFORM_DOCUMENT_ROOT

Please note: this ./frankenPHP binary will be installed in a later step, by using a install-frankenphp.sh shell script—see step 4 below.

2. As FrankenPHP needs to write access to a .local folder, you need to add a mount (=writable folder within your app container) for FrankenPHP to do so. Please find the applications.app.mounts section in your .upsun/config.yaml and add the following .local mount configuration:

applications:
  app:
    ...  
    mounts:
      "/var": { source: storage, source_path: var }
      "/data": { source: storage, source_path: data }
      ".local": { source: storage, source_path: frankenphp-local}

3. Use a shell script to install FrankenPHP (only once) during the applications.app.hooks.build step:

applications:
  app:
    ...
    hooks:
      build: |
        set -x -e

        curl -fs https://get.symfony.com/cloud/configurator | bash

        NODE_VERSION=18 symfony-build

        bash ./install-frankenphp.sh

Please note: the curl call to the Symfony configurator is Symfony-specific and introduces new tools to deploy your Symfony demo application. If you’re using your own PHP code base, only add the last command line in your build hooks: bash ./install-frankenphp.sh

4. Create corresponding shell script install-frankenphp.sh at the root of your source code:

# install-frankenphp.sh

# contributors:
#  - Thomas DI LUCCIO <thomas.diluccio@platform.sh>
#  - Florent HUCK <florent.huck@platform.sh>

run() {
   # Run the compilation process.
   cd $PLATFORM_CACHE_DIR || exit 1;

   FRANKENPHP_PROJECT=$1;
   FRANKENPHP_VERSION=$2;

   FRANKENPHP_BINARY="${FRANKENPHP_PROJECT}_v$FRANKENPHP_VERSION"
   FRANKENPHP_BINARY="${FRANKENPHP_BINARY//\./_}"

   rm -Rf ${PLATFORM_CACHE_DIR}/${FRANKENPHP_BINARY}

   if [ ! -f "${PLATFORM_CACHE_DIR}/${FRANKENPHP_BINARY}" ]; then
       ensure_source "$FRANKENPHP_PROJECT" "$FRANKENPHP_VERSION";
       download_binary "$FRANKENPHP_PROJECT" "$FRANKENPHP_VERSION";
       move_binary "$FRANKENPHP_PROJECT" "$FRANKENPHP_BINARY";
   fi

   copy_lib "$FRANKENPHP_PROJECT" "$FRANKENPHP_BINARY";
   echo "FrankenPHP installation successful"
}

copy_lib() {
   echo "------------------------------------------------"
   echo " Copying compiled extension to PLATFORM_APP_DIR "
   echo "------------------------------------------------"

   FRANKENPHP_PROJECT=$1;
   FRANKENPHP_BINARY=$2;

   cp "${PLATFORM_CACHE_DIR}/${FRANKENPHP_BINARY}" "${PLATFORM_APP_DIR}/${FRANKENPHP_PROJECT}";
   cd ${PLATFORM_APP_DIR};
   chmod +x ${FRANKENPHP_PROJECT};
   echo "Success"
}

ensure_source() {
   echo "-----------------------------------------------------------------------------------"
   echo " Ensuring that the $FRANKENPHP_PROJECT binary folder is available and up to date "
   echo "-----------------------------------------------------------------------------------"

   FRANKENPHP_PROJECT=$1;
   FRANKENPHP_VERSION=$2;

   mkdir -p "$PLATFORM_CACHE_DIR/$FRANKENPHP_PROJECT/$FRANKENPHP_VERSION";
   cd "$PLATFORM_CACHE_DIR/$FRANKENPHP_PROJECT/$FRANKENPHP_VERSION" || exit 1;
   echo "Success"
}

download_binary() {
   echo "---------------------------------------------------------------------"
   echo " Downloading FRANKENPHP_PROJECT binary source code "
   echo "---------------------------------------------------------------------"
   FRANKENPHP_PROJECT=$1;
   FRANKENPHP_VERSION=$2;
   wget https://github.com/dunglas/frankenphp/releases/download/$FRANKENPHP_VERSION/frankenphp-linux-x86_64
   mv frankenphp-linux-x86_64 ${FRANKENPHP_PROJECT}
   echo "Success"
}

move_binary() {
   echo "-----------------------------------------------------"
   echo " Moving and caching ${FRANKENPHP_PROJECT} binary "
   echo "-----------------------------------------------------"
   FRANKENPHP_PROJECT=$1;
   FRANKENPHP_BINARY=$2;
   cp "${PLATFORM_CACHE_DIR}/${FRANKENPHP_PROJECT}/${FRANKENPHP_VERSION}/${FRANKENPHP_PROJECT}" "${PLATFORM_CACHE_DIR}/${FRANKENPHP_BINARY}";
   chmod +x "${PLATFORM_CACHE_DIR}/${FRANKENPHP_BINARY}";
   echo "Success"
}

ensure_environment() {
   # If not running in an Upsun/Platform.sh build environment, do nothing.
   if [ -z "${PLATFORM_CACHE_DIR}" ]; then
       echo "Not running in an Upsun/Platform.sh build environment. Aborting FrankenPHP installation.";
       exit 0;
   fi
}

ensure_environment
# Get Latest version from Kevin Dunglas repo
VERSION=$(curl --silent "https://api.github.com/repos/dunglas/frankenphp/tags" | jq -r '.[0].name');
run "frankenphp" "$VERSION"

Please note: if you’re not using a Symfony application but your own PHP codebase, you can skip the following step.

5. Add the FrankenPHP runtime to your Symfony project. According to the FrankenPHP documentation page, you need to add the following bundle to the application: 

composer require runtime/frankenphp-symfony

6. Add an APP_RUNTIME environment variable—to tell Symfony to use the new FrankenPHP runtime, you need an environment variable, named APP_RUNTIME. To do so, in your .upsun/config.yaml, find the applications.app.variables section and add the following:

applications:
  app:
    ...  
    variables:
      php: ... 
      env: 
        APP_RUNTIME: 'Runtime\FrankenPhpSymfony\Runtime'

7. Deploy your changes to staging.

git add composer.json composer.lock symfony.lock .upsun/config.yaml install_frankenphp.sh
git commit -m "Use FrankenPHP instead of PHP-FPM"
symfony deploy   # or upsun push

8. Open your staging environment URL. To open the corresponding environment URL, use the following command:

symfony environment:url

9. Merge to production. When you’re good to go with your application behavior, you can merge it to the main production branch, using the following: 

symfony merge
symfony checkout main
git pull upsun main
symfony environment:delete staging
git fetch --prune

Please note: if you’re willing to use PHP commands directly on the server, like a Symfony console command, you need to use the FrankenPHP PHP-CLI ./frankenphp php-cli, like the following:

./frankenphp php-cli bin/console 

If you want to dive deeper into how to use FrankenPHP or other PHP servers, such as Swoole or RoadRunner, with your Symfony application on Upsun, take a look at this inspiring article from Sergii Dolgushev that is worth the read.

While focusing on installing FrankenPHP, this guide also serves as an introduction to using alternative PHP servers—often considered for the impressive performance they could bring—on Upsun.

The application only needs to boot once and then it remains in memory and stored in the cache, eliminating the need for instantiation with every incoming request. When using PHP-FPM, each time your application runs a PHP script, this PHP script is loaded in memory and then removed at the end of its execution. Furthermore, some alternative servers have embedded asynchronous capabilities that expand the technical horizon even more.

While the performance improvements from using an alternative PHP server like FrankenPHP are promising, it’s essential to proceed cautiously. Simply switching servers won’t solve deep-seated performance issues or other underlying problems—it’s more like a temporary fix for a more significant issue.

An excellent first step is to delve into the application and architecture observability dashboards to identify critical areas that need improvement. Once you thoroughly understand your application’s performance, you can consider moving to an alternative server to enhance efficiency and handling. Find out more about observability here.

Stay up to date on the latest from us over on our social media and community channels: Dev.toReddit, and Discord. Happy FrankenPHP’ing! 

Upsun Logo
Join the community