This is more of a proof of concept rather than a fully working project. This tries to replicate the caddy JSON API structure to work through chainable PHP classes.
At the moment there is only a tiny subset of commands available from Caddy 2.0 that covered my currently needed use case.
composer require mattvb91/caddy-phpA basic example of a http server with a static response:
$caddy = new Caddy();
$caddy->addApp(
(new Http())->addServer(
'server1', (new Http\Server())->addRoute(
(new Route())->addHandle(
new StaticResponse('Hello world', 200)
)
))
);
$caddy->load();This will result in the following Caddy config:
{
"admin": {
"disabled": false,
"listen": ":2019"
},
"apps": {
"http": {
"servers": {
"server1": {
"listen": [
":80"
],
"routes": [
{
"handle": [
{
"handler": "static_response",
"body": "Hello world",
"status_code": 200
}
]
}
]
}
}
}
}
}curl -v localhost
-----
< HTTP/1.1 200 OK
< Server: Caddy
Hello world Let's take a case where you want to have a Node frontend and a PHP backend taking requests on the /api/* route.
In this case the example breaks down to 2 reverse proxy's with a route matcher to filter the /api/* to the PHP upstream.
This assumes the 3 hosts (Caddy, Node, PHP) are all docker containers and accessible by container name within the same docker network, so you may have to adjust your hostnames as required.
use mattvb91\CaddyPhp\Caddy;
use mattvb91\CaddyPhp\Config\Apps\Http;
use mattvb91\CaddyPhp\Config\Apps\Http\Server;
use mattvb91\CaddyPhp\Config\Apps\Http\Server\Route;
use mattvb91\CaddyPhp\Config\Apps\Http\Server\Routes\Handle\ReverseProxy;
use mattvb91\CaddyPhp\Config\Apps\Http\Server\Routes\Handle\ReverseProxy\Transport\FastCGI;
use mattvb91\CaddyPhp\Config\Apps\Http\Server\Routes\Handle\ReverseProxy\Upstream;
use mattvb91\CaddyPhp\Config\Apps\Http\Server\Routes\Handle\Subroute;
use mattvb91\CaddyPhp\Config\Apps\Http\Server\Routes\Match\Host;
use mattvb91\CaddyPhp\Config\Apps\Http\Server\Routes\Match\Path;
$apiReverseProxy = (new ReverseProxy())
->addUpstream((new Upstream())
->setDial('laravel-api:9000')
)->addTransport((new FastCGI())
->setRoot('/app/public/index.php')
->setSplitPath([''])
);
$apiMatchPath = (new Path())
->setPaths([
'/api/*',
]);
$backendAPIRoute = (new Route())
->addHandle($apiReverseProxy)
->addMatch($apiMatchPath);
$route = new Route();
$route->addHandle((new Subroute())
->addRoute($backendAPIRoute)
->addRoute((new Route())
->addHandle((new ReverseProxy())
->addUpstream((new Upstream())
->setDial('nextjs:3000')
)
)
)
)->addMatch((new Host())
->setHosts([
'localhost',
])
)->setTerminal(true);
$caddy = new Caddy();
$caddy->addApp((new Http())
->addServer('myplatform', (new Server())
->addRoute($route)
)
);
$caddy->load();This will post the following caddy config:
{
"admin": {
"disabled": false,
"listen": ":2019"
},
"apps": {
"http": {
"servers": {
"myplatform": {
"listen": [
":80"
],
"routes": [
{
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"handler": "reverse_proxy",
"transport": {
"protocol": "fastcgi",
"root": "/app/public/index.php",
"split_path": [
""
]
},
"upstreams": [
{
"dial": "laravel-api:9000"
}
]
}
],
"match": [
{
"path": [
"/api/*"
]
}
]
},
{
"handle": [
{
"handler": "reverse_proxy",
"upstreams": [
{
"dial": "nextjs:3000"
}
]
}
]
}
]
}
],
"match": [
{
"host": [
"localhost"
]
}
],
"terminal": true
}
]
}
}
}
}
}curl -v localhost
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=utf-8
< Server: Caddy
< X-Powered-By: Next.js
< Transfer-Encoding: chunked
<
<!DOCTYPE html><html>....curl -v localhost/api/testroute
< HTTP/1.1 200 OK
< Content-Type: application/json
< Server: Caddy
< X-Powered-By: PHP/8.1.7
<
{"status":200}
Take a look in the tests for more examples.
