Caddy & FrankenPHP
Learn how to configure Caddy and FrankenPHP server.
Configuring Caddy
Similar to how Apache web server and Nginx integrate with PHP, Caddy is also integrated with PHP using Caddy's FastCGI reverse proxy. The basic idea is that when Caddy receives a request that should be processed with PHP (e.g, a request to a file name with a .php extension), the request is sent to PHP-FPM, where the PHP application is executed, and the response is sent back to Caddy to return to the user. At its simplest, the following is a fully functional Caddy site definition:
localhost {
# Set the project root
root ./
# Enable compression (optional)
encode zstd br gzip
# Configures multiple PHP-related settings
php_fastcgi unix//run/php/php-fpm.sock
# Remove Server: header
header -Server
# Redirect SAPI to errors.php
handle_errors {
rewrite /errors.php
file_server
}
# Execute PHP files from the public/ directory and serve assets
php_server {
root ./
try_files public/{path} index.php
}
}
For ad-hoc configuration, the server can controlled with the caddy command:
| Command | Service equivalent | Description |
|---|---|---|
caddy start |
systemctl start caddy |
Starts the server |
caddy stop |
systemctl stop caddy |
Stops the server |
caddy reload |
systemctl reload caddy |
Reload the server |
caddy stop && caddy start |
systemctl restart caddy |
Restarts the server |
Configuring FrankenPHP
Create a ./Caddyfile file at the project root (if it doesn't already exist) containing:
# Domain name of server
localhost {
# Set the project root
root ./
# Enable compression (optional)
encode zstd br gzip
# Remove Server: header
header -Server
# Redirect SAPI to errors.php
handle_errors {
rewrite /errors.php
file_server
}
# Execute PHP files from the public/ directory and serve assets
php_server {
root ./
try_files public/{path} index.php
}
}
Add APP_SKIP_ENV_FILE=1 to the .env file, as FrankenPHP
itself will load the .env file, bypassing the framework's parsing.
In the project folder, run the command to start the FrankenPHP app server:
frankenphp run
It is also possible to configure the server for better optimization and set PHP directives directly in the Caddyfile, as shown in the example:
{
frankenphp {
php_ini memory_limit 256M
php_ini max_execution_time 30
}
}
localhost {
# Set the project root
root ./
# Enable compression (optional)
encode zstd br gzip
# Remove Server: header
header -Server
# Redirect SAPI to errors.php
handle_errors {
rewrite /errors.php
file_server
}
# Execute PHP files from the public/ directory and serve assets
php_server {
root ./
try_files public/{path} index.php
}
}
You can configure it explicitly using the global frankenphp { ... } configuration:
{
frankenphp {
# Sets the number of PHP threads to start. Default: 2x the number of available CPUs.
num_threads <num_threads>
# Limits the number of additional PHP threads that can be started at runtime. Default: num_threads. Can be set to 'auto'.
max_threads <num_threads>
# Sets the maximum time a request may wait for a free PHP thread before timing out. Default: disabled.
max_wait_time <duration>
# Sets the maximum time an autoscaled thread may be idle before being deactivated. Default: 5s.
max_idle_time <duration>
# (experimental) Sets the maximum number of requests a PHP thread will handle before being restarted, useful for mitigating memory leaks. Applies to both regular and worker threads. Default: 0 (unlimited).
max_requests <num>
# Set a php.ini directive. Can be used several times to set multiple directives.
php_ini <key> <value>
worker {
# Sets the path to the worker script.
file <path>
# Sets the number of PHP threads to start, defaults to 2x the number of available CPUs.
num <num>
# Sets an extra environment variable to the given value. Can be specified more than once for multiple environment variables.
env <key> <value>
# Sets the path to watch for file changes. Can be specified more than once for multiple paths.
watch <path>
# Sets the name of the worker, used in logs and metrics. Default: absolute path of worker file
name <name>
# Sets the maximum number of consecutive failures before the worker is considered unhealthy, -1 means the worker will always restart. Default: 6.
max_consecutive_failures <num>
}
}
}