This is getting FrankenPHP running with Caddy on Ubuntu 24.04 LTS without Docker
Note: 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
Install some pre-reqs
sudo apt install zip unzip curl -y
Install PHP8.4 and Caddy
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
curl https://frankenphp.dev/install.sh | sh
sudo mv frankenphp /usr/local/bin/
Create a php.ini
# 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
# 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:
# https://caddyserver.com/docs/caddyfile
To format the Caddyfile use
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.
[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
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
# 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
systemctl enable frankenphp.service
systemctl start frankenphp.service
Install CakePHP
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
<?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
mkdir src/Http
cp vendor/cakephp/cakephp/src/Http/Server.php src/Http/
Change the following
# 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