FrankenPHP includes built-in configuration validation to ensure your Caddyfile is correctly formatted and configured before deploying. This guide covers how to validate your configuration, interpret the output, and fix common issues.
To validate your FrankenPHP configuration inside the container:
docker compose exec -t franken bash
frankenphp validate --config=/etc/frankenphp/CaddyfileFor the worker mode container:
docker compose exec -t franken-worker bash
frankenphp validate --config=/etc/frankenphp/CaddyfileWhen your configuration is valid, you'll see output similar to:
2025/11/24 09:47:06.518 INFO using config from file {"file": "/etc/frankenphp/Caddyfile"}
2025/11/24 09:47:06.519 INFO adapted config to JSON {"adapter": "caddyfile"}
2025/11/24 09:47:06.519 INFO http.auto_https server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS {"server_name": "srv0", "https_port": 443}
2025/11/24 09:47:06.519 INFO http.auto_https enabling automatic HTTP->HTTPS redirects {"server_name": "srv0"}
2025/11/24 09:47:06.520 INFO http servers shutting down with eternal grace period
Valid configuration
The final line Valid configuration confirms your Caddyfile is syntactically correct and semantically valid.
INFO messages provide informational feedback about your configuration:
using config from file: Confirms the config file locationadapted config to JSON: Caddyfile successfully converted to Caddy's internal JSON formatserver is listening only on the HTTPS port: Caddy detected HTTPS configuration and automatically adds TLSenabling automatic HTTP->HTTPS redirects: Automatic redirects from HTTP to HTTPS are enabled
These messages are normal and do not require action.
WARN messages indicate potential issues that don't prevent the config from working:
2025/11/24 09:47:06.519 WARN Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies {"adapter": "caddyfile", "file": "/etc/frankenphp/Caddyfile", "line": 12}
Common warnings:
- Formatting Inconsistencies: Indentation or spacing issues
- Deprecated Directives: Using older configuration syntax
- Missing Recommended Options: Configuration works but could be improved
ERROR messages indicate problems that will prevent FrankenPHP from starting:
Error: adapting config using caddyfile: parsing caddyfile tokens for 'frankenphp': "max_threads" must be greater than or equal to "num_threads"
The configuration will not be valid until errors are resolved.
Warning Message:
WARN Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies
How to Fix:
Inside the container, format the Caddyfile:
docker compose exec -t franken bash
frankenphp fmt --overwrite /etc/frankenphp/Caddyfilenow let's check out configuration and ensure formatting is not show up
Error Message:
Error: "max_threads" must be greater than or equal to "num_threads"
How to Fix:
When we trying to modify /etc/frankenphp/Caddyfile.regular like below:
# Before (invalid)
frankenphp {
num_threads 16
max_threads 8 # ERROR: Less than num_threads
}it will invalid, if we run reload on frankenphp config
frankenphp reload --config=/etc/frankenphp/Caddyfile
# Error will show this
# 2025/11/24 09:55:30.509 INFO using config from file {"file": "/etc/frankenphp/Caddyfile"}
# Error: adapting config using caddyfile: parsing caddyfile tokens for 'frankenphp': "max_threads"" must be greater than or equal to "num_threads"ensure max_threads >= num_threads
how to fix?
# After (valid)
frankenphp {
num_threads 16
max_threads 32 # OK: Greater than num_threads
# or
max_threads auto # OK: Auto-scaling
}
and run format
frankenphp fmt --overwire --config=/etc/frankenphp/Caddyfileand then reload
frankenphp reload --config=/etc/frankenphp/Caddyfile
# 2025/11/24 09:59:47.709 INFO using config from file {"file": "/etc/frankenphp/Caddyfile"}
# 2025/11/24 09:59:47.710 INFO adapted config to JSON {"adapter": "caddyfile"}now notice that our configuration free-errors
Error Message:
Error: "num_threads" must be greater than worker "num" directive
How to Fix:
Ensure the number of threads is greater than the number of workers:
# Before (invalid)
frankenphp {
num_threads 4
worker {
file ./public/index.php
num 8 # ERROR: More workers than threads
}
}
# After (valid)
frankenphp {
num_threads 16
worker {
file ./public/index.php
num 8 # OK: Threads > Workers
}
}Error Message:
Error: parsing caddyfile tokens for 'frankenphp': missing required 'file' directive in worker block
How to Fix:
Ensure worker blocks include the required file directive:
# Before (invalid)
frankenphp {
worker {
num 8
}
}
# After (valid)
frankenphp {
worker {
file ./public/index.php # Required
num 8
}
}Error Message:
Error: worker file does not exist: /invalid/path/index.php
How to Fix:
Verify the worker file path exists inside the container:
docker compose exec -t franken bash
ls -la /var/www/html/public/index.phpUpdate the Caddyfile with the correct path:
frankenphp {
worker {
file ./public/index.php # Relative to SERVER_ROOT
# or
file /var/www/html/public/index.php # Absolute path
}
}-
Edit the Caddyfile:
vim docker/Caddyfile
-
Validate the configuration:
docker compose exec -t franken bash frankenphp validate --config=/etc/frankenphp/Caddyfile -
Fix any errors or warnings
-
Restart the container:
docker compose restart franken # or for worker mode docker compose restart franken-worker -
Verify the service is running:
docker compose logs franken
Check configuration syntax without starting FrankenPHP:
docker compose exec -t franken bash
frankenphp validate --config=/etc/frankenphp/Caddyfile --adapter caddyfileSee how Caddy interprets your Caddyfile:
docker compose exec -t franken bash
frankenphp adapt --config=/etc/frankenphp/Caddyfile --adapter caddyfile | jqThis outputs the JSON representation of your configuration, useful for debugging complex setups.
FrankenPHP supports reloading configuration without downtime:
docker compose exec -t franken bash
frankenphp reload --config=/etc/frankenphp/CaddyfileIf the new configuration is invalid, the reload will fail and the old configuration remains active.
Keep your Caddyfile formatted consistently:
caddy fmt --overwrite docker/CaddyfileAdd comments to your Caddyfile:
{
admin 0.0.0.0:2019 # Exposed for monitoring (use localhost in production)
metrics # Enable Prometheus metrics
}Always validate configuration changes in a non-production environment first.
After deploying configuration changes:
docker compose logs -f franken
docker compose logs -f franken-workerWatch for startup errors or warnings.
{
admin localhost:2019 # Restricted to localhost
metrics
frankenphp {
num_threads 32
worker {
file /var/www/html/public/index.php
num 24
# watch disabled for production
}
php_ini {
memory_limit 512M
opcache.memory_consumption 256
opcache.validate_timestamps 0
}
}
}
{$SERVER_NAME:localhost} {
root {$SERVER_ROOT:/var/www/html/public}
encode zstd br gzip
header {
X-Frame-Options DENY
X-Content-Type-Options nosniff
Strict-Transport-Security "max-age=31536000;"
}
php_server
}{
admin 0.0.0.0:2019
metrics
debug
frankenphp {
num_threads 8
worker {
file ./public/index.php
num 4
watch # Enable auto-reload
}
php_ini memory_limit 512M
}
}
localhost:8080 {
root ./public
encode gzip
php_server
}Before deploying configuration changes, verify:
- Configuration validates successfully
- No ERROR messages in validation output
- WARN messages reviewed and addressed
-
num_threads>=worker.num -
max_threads>=num_threads(if specified) - Worker
filedirective points to existing PHP file - Memory calculations verified:
num_threads × memory_limit < available_memory -
watchdirective disabled for production - Admin API restricted to localhost in production
- Configuration formatted with
caddy fmt - Changes tested in staging environment
- Logs monitored after deployment
- FrankenPHP Documentation: https://frankenphp.dev/docs/
- Caddy Documentation: https://caddyserver.com/docs/
- Project FrankenPHP Guide: frankenphp.md
- Performance Testing: frankenphp.md#performance-testing--monitoring
# Validate configuration
frankenphp validate --config=/etc/frankenphp/Caddyfile
# Format Caddyfile
caddy fmt --overwrite /etc/frankenphp/Caddyfile
# View JSON configuration
frankenphp adapt --config=/etc/frankenphp/Caddyfile --adapter caddyfile
# Reload configuration (no downtime)
frankenphp reload --config=/etc/frankenphp/Caddyfile
# Test PHP syntax
php -l /var/www/html/public/index.php