Better PHP Sites with the Caddy Web Server
How API Platform Leverages Caddy to Power Your PHP Apps
by Matt Holt API Platform Conference September 10, 2021 Lille, France
Typical PHP application architecture using PHP-FPM
Web server
Caddy or nginx
FastCGI responder
php-fpm
Client
Web browser, app, curl…
TLS +
HTTP/1.1, HTTP/2, HTTP/3, WebSockets, etc.
FastCGI
PHP worker
PHP worker
PHP worker
PHP
PHP
PHP
.php files
Page resources
CSS, JS, images...
Static files
Disk I/O
Some things web servers do for your PHP site
Web server
Caddy or nginx
TLS +
HTTP/1.1, HTTP/2, HTTP/3, WebSockets, etc.
FastCGI
Disk I/O
C A D D Y
Overview
Caddy is a highly extensible, self-hosted platform on which you can build, configure, and deploy long-running services ("apps").
Automatic HTTPS
Memory safety
Source: Prossimo, https://www.memorysafety.org/docs/memory-safety/
Heartbleed logo: https://heartbleed.com
Static binary
Extensible
Online Config API
$ curl "http://localhost:2019/config/" | jq
{
"apps": {
"http": {
"servers": {
"myserver": {
"listen": [":443"],
"routes": [
{
"match": [
{"host": ["example.com"]}
],
"handle": [
{"handler": "file_server"}
]
}
]
}
}
}
}
}
$ curl "http://localhost:2019/config/apps/http/servers/myserver/listen"
[":443"]
Config adapters
$ caddy run --config nginx.conf --adapter nginx
Caddyfile
Native PHP + FastCGI Support
php_fastcgi 127.0.0.1:9000
php_fastcgi php-fpm:9000
route {
# Add trailing slash for directory requests
file {path}/index.php
not path */
}
redir @canonicalPath {path}/ 308
# If the requested file does not exist, try index files
@indexFiles file {
try_files {path} {path}/index.php index.php
split_path .php
}
rewrite @indexFiles {http.matchers.file.relative}
# Proxy PHP files to the FastCGI responder
@phpFiles path *.php
reverse_proxy @phpFiles php-fpm:9000 {
transport fastcgi {
split .php
}
}
}
Traefik → Caddy
Typical Caddyfile config for PHP sites
H T T P S
Automatic HTTPS
How Automatic HTTPS Works
Provisions certificates when config is loaded.
The 3 ACME Challenges
HTTP
:80
TLS-ALPN
:443
DNS
1
2
3
ACME server (CA)
DNS server
Your server (Caddy)
✅ Rate limiting
✅ Failed validations
✅ Revocations
✅ Infrastructure outages
✅ Customer domains
Production Challenges of TLS
✅ OCSP problems
✅ Misconfigured storage
✅ Fleet coordination
✅ Dynamic updates
✅ Scaling millions of certs
✅ = Caddy handles it�(other scripts/tools… don't usually)
O N - D E M A N D T L S
On-Demand TLS
Provisions certificates "on-demand" at run-time.
More info in our wiki: https://caddy.community/t/serving-tens-of-thousands-of-domains-over-https-with-caddy/11179
On-Demand TLS Example
{
on_demand_tls {
ask http://localhost:5555/check
}
}
https://
tls {
on_demand
}
...
(The "ask" endpoint might be a PHP script that checks your database to see if the domain name is associated with a customer.)
A P I P L A T F O R M
"Caddy allowed us to dramatically simplify the setup we provide (both in dev and in prod). Its main strengths are batteries included and very easy to extend, and we need that for API Platform."
-Kévin Dunglas, creator of API Platform
API Platform Architecture Comparison
API Platform switched to Caddy in v2.6; see PR 1693
Ref: https://medium.com/@dunglas/api-platform-2-6-8bd3a506a9c4
NGINX | Caddy |
8 containers:
| 4 containers:
|
❌ No memory safety ( Heartbleed, etc; because C) | ✅ Memory-safe (Go) |
❌ Manual HTTPS | ✅ Automatic HTTPS that scales |
❌ Difficult to extend | ✅ Easily extensible |
❌ Usually has external dependencies | ✅ Static binary, no dependencies |
API Platform's Caddyfile
{
{$DEBUG}
servers {
protocol {
experimental_http3
}
}
}
{$SERVER_NAME}
log
@pwa expression `(
{header.Accept}.matches("\\btext/html\\b")
&& !{path}.matches("(?i)(?:^/docs|^/graphql|^/bundles/|^/_profiler|^/_wdt|\\.(?:json|html$|csv$|ya?ml$|xml$))")
)
|| {path} == "/favicon.ico"
|| {path} == "/manifest.json"
|| {path} == "/robots.txt"
|| {path}.startsWith("/_next")
|| {path}.startsWith("/sitemap")`
route {
root * /srv/api/public
mercure {
transport_url {$MERCURE_TRANSPORT_URL:bolt:///data/mercure.db}
publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG}
subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG}
anonymous
subscriptions
{$MERCURE_EXTRA_DIRECTIVES}
}
vulcain
push
header ?Link `</docs.jsonld>; rel="http://www.w3.org/ns/hydra/core#apiDocumentation", </.well-known/mercure>; rel="mercure"`
header ?Permissions-Policy "interest-cohort=()"
reverse_proxy @pwa http://{$PWA_UPSTREAM}
php_fastcgi unix//var/run/php/php-fpm.sock
encode zstd gzip
file_server
}
T H E P O I N T
Knowing Caddy gives you technical and competitive advantages for your sites
75%
of surveyed consumers would feel more likely to recommend or purchase from a company that sponsors open source
According to a scientifically rigorous* Twitter survey:
* not really
Support open source development
Corporations rely on open source, and open source relies on corporations.
Thank you