This is getting FrankenPHP running with Caddy on Ubuntu 24.04 LTS without Docker
Warning: CakePHP doesn't currently come with a drop-in frankenphp worker script. The script sample works if you set $maxRequests
to 1 and let frankenphp restart it for every request. Development needs to be done to create a proper worker script.
Note: Frankenphp works fine in php_server
mode with the default webroot/index.php
👍
Installing a FrankenPHP environment on Ubuntu 24.04 LTS
Install some pre-reqs
1 | sudo apt install zip unzip curl -y |
Install PHP8.4 and Caddy
1 2 3 4 | sudo add-apt-repository ppa:ondrej /php -y sudo apt update sudo apt install caddy php8.4 php8.4-cli php8.4-{bz2,curl,mbstring,intl,xml} -y php - v |
Install frankenphp
1 2 | curl https: //frankenphp .dev /install .sh | sh sudo mv frankenphp /usr/local/bin/ |
Create a php.ini
1 2 3 4 5 6 7 8 | # create the /etc/frankenphp dir if you need to cp /etc/php/8 .4 /fpm/php .ini /etc/frankenphp/ # uncomment and edit the error_log value error_log= /var/log/php_errors .log sudo touch /var/log/php_errors .log sudo chown www-data:www-data /var/log/php_errors .log |
Create a config file for Caddy
/etc/caddy/Caddyfile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | # The Caddyfile is an easy way to configure your Caddy web server. # # Unless the file starts with a global options block, the first # uncommented line is always the address of your site. # # To use your own domain name (with automatic HTTPS), first make # sure your domain's A/AAAA DNS records are properly pointed to # this machine's public IP, then replace ":80" below with your # domain name. # { metrics frankenphp { worker { env DEBUG false file / var /www/html/webroot/index.php watch / var /www/html/webroot watch / var /www/html/vendor num 6 } } } tgnyt.australiaeast.cloudapp.azure.com, fphp.toggen.com.au { # Set this path to your site's directory. root * / var /www/html/webroot encode zstd br gzip file_server # Or serve a PHP site through php-fpm: # php_fastcgi localhost:9000 php_server { env PATH /usr/local/bin:/usr/bin env DEBUG true } log { format console output file / var /log/caddy.log } } # Refer to the Caddy docs for more information: |
To format the Caddyfile use
1 | sudo caddy fmt --overwrite |
Create a systemd .service file
/etc/systemd/system/frankenphp.service
Don't think CAP_NET_ADMIN is needed to remove this.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | [Unit] Description=FrankenPHP Server After=network.target network-online.target Requires=network-online.target [Service] Restart=on-failure Type=notify User=www-data Group=www-data ExecStartPre=/usr/local/bin/frankenphp validate --config /etc/caddy/Caddyfile ExecStart=/usr/local/bin/frankenphp run --config /etc/caddy/Caddyfile --adapter caddyfile ExecReload=/usr/local/bin/frankenphp reload --config /etc/caddy/Caddyfile --force TimeoutStopSec=5s LimitNOFILE=1048576 PrivateTmp=true ProtectSystem=full AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE [Install] WantedBy=multi-user.target |
Add writeable dirs for the user running frankenphp
1 2 | sudo mkdir /var/www/ {.config,. local } sudo chown www-data:www-data /var/www/ {.config,. local } |
The contents of the above directories once frankenphp starts
1 2 3 4 5 6 7 | # autosave /var/www/.config/caddy/autosave.json # certs letsencrypt config /var/www/.local/share/caddy/certificates /var/www/.local/share/caddy/acme /var/www/.local/share/caddy/acme/acme-v02.api.letsencrypt.org-directory |
Enable and start the service
1 2 | systemctl enable frankenphp.service systemctl start frankenphp.service |
Install CakePHP
1 2 3 4 | cd /var/www/html composer create-project --prefer-dist cakephp/app:~5.0 . # optional upgrade composer require cakephp/cakephp:~5.2 |
Deploy the worker script
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | <?php use App\Application; use App\Http\Server; use Cake\Core\PluginApplicationInterface; $workerServer = $_SERVER ; ignore_user_abort(true); require dirname(__DIR__) . '/vendor/autoload.php' ; $myApp = new Application( dirname(__DIR__) . '/config' ); $myApp ->bootstrap(); $server = new Server( $myApp ); error_log ( 'Worker started' ); $handler = static function () use ( $server , $myApp ) { error_log ( 'Worker handler' ); # DebugKit won't show up and will throw an error without this if ( $myApp instanceof PluginApplicationInterface) { $myApp ->pluginBootstrap(); } $server ->emit( $server ->run()); }; $maxRequests = (int)( $_SERVER [ 'MAX_REQUESTS' ] ?? 1); for ( $nbRequests = 0; ! $maxRequests || $nbRequests < $maxRequests ; ++ $nbRequests ) { error_log ( 'Worker handling request' ); $keepRunning = \frankenphp_handle_request( $handler ); gc_collect_cycles(); if (! $keepRunning ) break ; } |
Modify Cake\Http\Server.php
1 2 | mkdir src/Http cp vendor/cakephp/cakephp/src/Http/Server.php src/Http/ |
Change the following
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # change namespace # namespace Cake\Http; # to namespace App\Http; # add references to the Cake\Http classes use Cake\Http\Runner; use Cake\Http\MiddlewareQueue; use Cake\Http\ResponseEmitter; use Cake\Http\ServerRequestFactory; # comment out the call to bootstrap the app public function run( ?ServerRequestInterface $request = null, ?MiddlewareQueue $middlewareQueue = null, ): ResponseInterface { # $this ->bootstrap(); |
0 Comments