Skip to content

mattvb91/caddy-php

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

27 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

.github/workflows/ci_cd.yml codecov Total Downloads Latest Stable Version License

Control your Caddy instance through PHP

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.

Install

composer require mattvb91/caddy-php

Basic Usage

A 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       

Managing Hostnames

If you are managing hostnames dynamically (in a database) and can't build out the config with a list of existing hostnames because you need to manage them at runtime you can do the following:

The important part in this example is the host_group_name identifier which is later used to add / remove domains to this host.

$caddy = new Caddy();
$caddy->addApp(
    (new Http())->addServer(
        'server1', (new Http\Server())->addRoute(
        (new Route())->addHandle(
            new StaticResponse('host test', 200)
        )->addMatch((new Host('host_group_name'))
            ->setHosts(['localhost'])
        )
    )->addRoute((new Route())
        ->addHandle(new StaticResponse('Not found', 404))
        ->addMatch((new Host('notFound'))
            ->setHosts(['*.localhost'])
        )
    ))
);
$caddy->load();

Adding Hostnames

Now later on in a script or event on your system you can get your caddy configuration object and post a new domain to it under that route:

$caddy->addHostname('host_group_name', 'new.localhost')
$caddy->addHostname('host_group_name', 'another.localhost')
curl -v new.localhost
> GET / HTTP/1.1
> Host: new.localhost
> 
< HTTP/1.1 200 OK

curl -v another.localhost
> GET / HTTP/1.1
> Host: another.localhost
> 
< HTTP/1.1 200 OK

Removing Hostnames

$caddy->syncHosts('host_group_name'); //Sync from caddy current hostname list

$caddy->removeHostname('host_group_name', 'new.localhost');
$caddy->removeHostname('host_group_name', 'another.localhost');
curl -v new.localhost
> GET / HTTP/1.1
> Host: new.localhost
> 
< HTTP/1.1 404 Not Found

curl -v another.localhost
> GET / HTTP/1.1
> Host: another.localhost
> 
< HTTP/1.1 404 Not Found

Advanced Example

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.

About

PHP package to control your Caddy instance

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy