Caddyfile:
{ # Enable FrankenPHP frankenphp order php_server before file_server } localhost { # Enable compression (optional) encode zstd br gzip # Execute PHP files in the current directory and serve assets php_server }
Configure worker mode:
In this example FrankenPHP starts 2 workers per CPU
{ # ... frankenphp { worker ./public/index.php 2 } # ... }
Allow the browser to download resources or preconnect to a site before the final response was sent.
header('Link: </style.css>; rel=preload; as=style'); headers_send(103); // Do sluggish stuff 🐌
Caddyfile example configuration:
localhost { # ... # Enable Mercure hub mercure { # Transport to use (default to Bolt) transport_url {$MERCURE_TRANSPORT_URL:bolt:///data/mercure.db} # Publisher JWT key publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG} # Subscriber JWT key subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG} # Allow anonymous subscribers (double-check that it's what you want) anonymous # Enable the subscription API (double-check that it's what you want) subscriptions # Extra directives {$MERCURE_EXTRA_DIRECTIVES} # Development only, enables the mercure UI # demo } }
Publish a message to all clients
$hubUrl = 'https://localhost:8788/.well-known/mercure'; $jwt = '<JWT>'; $defaults = HttpClientInterface::OPTIONS_DEFAULTS; $client = HttpClient::create($defaults); $hub = new Hub($hubUrl, new StaticTokenProvider($jwt), null, null, $client); // The topic you want to publish to $topic = '/chat/messages'; $update = new Update($topic, 'MESSAGE TO ALL CLIENTS'); $hub->publish($update);
Receive the message:
let endpoint = "https://localhost:8788/.well-known/mercure" let topic = "/chat/messages"; let jwtToken = "<JWT>" let eventSource = new EventSource(`${endpoint}?topic=${encodeURIComponent(topic)}`, { headers: { Authorization: `Bearer ${jwtToken}`, }, }); let eventSource.onmessage = (event) => { console.log("Received event:", event.data); };
Enable it in the Caddyfile:
{ # ... servers { metrics } # ... }
The exporter is available under http://localhost:2019/metrics
Example metric:
# HELP caddy_http_request_duration_seconds Histogram of round-trip request durations. # TYPE caddy_http_request_duration_seconds histogram caddy_http_request_duration_seconds_bucket{code="200",handler="subroute",method="GET",server="srv0",le="0.005"} 564 ...
Scrape the metrics provided by FrankenPHP:
prometheus.yml:
scrape_configs: - job_name: 'franky' metrics_path: '/metrics' static_configs: - targets: [ "localhost:2019" ]
Restart without interrupting current users connection.
frankenphp reload -c Caddyfile
Wrap your PHP application into a self-contained binary.
FROM --platform=linux/amd64 dunglas/frankenphp:static-builder # Copy your app WORKDIR /go/src/app/dist/app COPY . . # Build the static binary WORKDIR /go/src/app/ RUN EMBED=dist/app/ ./build-static.sh
Create the self-contained binary using Docker:
docker build -t static-app -f static-build.Dockerfile . --load
Extract the binary (frankenphp-mac-arm64)
docker cp $(docker create --name static-app-tmp static-app):/go/src/app/dist/frankenphp-linux-x86_64 my-app ; docker rm static-app-tmp
Docker:
docker run -v $PWD:/app/public \ -p 80:80 -p 443:443 -p 443:443/udp \ dunglas/frankenphp
Standalone Binary
./frankenphp run -c Caddyfile
Standalone Binary - CLI
Does not require additional PHP to be installed!
./frankenphp php-cli /path/to/your/script.php
Feature idea:
Using GoRoutines to run e.g. the TYPO3 MessageBus (symfony/messenger) and the Scheduler
Join the Chat
Demo: https://franky.knallimall.org/