{"id":23806841,"url":"https://github.com/mattvb91/caddy-php","last_synced_at":"2025-07-30T13:02:54.643Z","repository":{"id":38818630,"uuid":"494139661","full_name":"mattvb91/caddy-php","owner":"mattvb91","description":"PHP package to control your Caddy instance","archived":false,"fork":false,"pushed_at":"2024-06-17T16:59:06.000Z","size":140,"stargazers_count":29,"open_issues_count":1,"forks_count":5,"subscribers_count":5,"default_branch":"develop","last_synced_at":"2024-12-02T10:45:11.695Z","etag":null,"topics":["caddy","caddy-api","caddy-server","caddy2","caddyserver","help-wanted","php"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mattvb91.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-05-19T16:01:42.000Z","updated_at":"2024-11-23T22:59:08.000Z","dependencies_parsed_at":"2024-02-04T16:36:24.342Z","dependency_job_id":null,"html_url":"https://github.com/mattvb91/caddy-php","commit_stats":{"total_commits":21,"total_committers":1,"mean_commits":21.0,"dds":0.0,"last_synced_commit":"5fb4a4611d8c2151225c486810c6d4201baaeaf9"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mattvb91%2Fcaddy-php","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mattvb91%2Fcaddy-php/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mattvb91%2Fcaddy-php/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mattvb91%2Fcaddy-php/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mattvb91","download_url":"https://codeload.github.com/mattvb91/caddy-php/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":232133902,"owners_count":18477299,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["caddy","caddy-api","caddy-server","caddy2","caddyserver","help-wanted","php"],"created_at":"2025-01-01T23:15:53.815Z","updated_at":"2025-01-01T23:15:54.619Z","avatar_url":"https://github.com/mattvb91.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/11991564/180657106-aec2eb78-def3-4bad-aa4e-44f1e6ef1628.png\" /\u003e\n\u003c/p\u003e\n\n[![.github/workflows/ci_cd.yml](https://github.com/mattvb91/caddy-php/actions/workflows/ci_cd.yml/badge.svg)](https://github.com/mattvb91/caddy-php/actions/workflows/ci_cd.yml)\n[![codecov](https://codecov.io/gh/mattvb91/caddy-php/branch/develop/graph/badge.svg?token=RYFGX2AW6J)](https://codecov.io/gh/mattvb91/caddy-php)\n\u003ca href=\"https://packagist.org/packages/mattvb91/caddy-php\"\u003e\u003cimg src=\"https://img.shields.io/packagist/dt/mattvb91/caddy-php\" alt=\"Total Downloads\"\u003e\u003c/a\u003e\n\u003ca href=\"https://packagist.org/packages/mattvb91/caddy-php\"\u003e\u003cimg src=\"https://img.shields.io/packagist/v/mattvb91/caddy-php\" alt=\"Latest Stable Version\"\u003e\u003c/a\u003e\n\u003ca href=\"https://packagist.org/packages/mattvb91/caddy-php\"\u003e\u003cimg src=\"https://img.shields.io/packagist/l/mattvb91/caddy-php\" alt=\"License\"\u003e\u003c/a\u003e\n\n### Control your Caddy instance through PHP\n\nThis is more of a proof of concept rather than a fully working project. This tries to replicate\nthe [caddy JSON API](https://caddyserver.com/docs/json/)\nstructure to work through chainable PHP classes.\n\nAt the moment there is only a tiny subset of commands available from Caddy 2.0 that covered my currently needed use\ncase.\n\n### Install\n\n```shell\ncomposer require mattvb91/caddy-php\n```\n\n### Basic Usage\n\nA basic example of a http server with a static response:\n\n```php\n$caddy = new Caddy();\n\n$caddy-\u003eaddApp(\n    (new Http())-\u003eaddServer(\n        'server1', (new Http\\Server())-\u003eaddRoute(\n        (new Route())-\u003eaddHandle(\n            new StaticResponse('Hello world', 200)\n        )\n    ))\n);\n\n$caddy-\u003eload();\n```\n\nThis will result in the following Caddy config:\n\n```json\n{\n  \"admin\": {\n    \"disabled\": false,\n    \"listen\": \":2019\"\n  },\n  \"apps\": {\n    \"http\": {\n      \"servers\": {\n        \"server1\": {\n          \"listen\": [\n            \":80\"\n          ],\n          \"routes\": [\n            {\n              \"handle\": [\n                {\n                  \"handler\": \"static_response\",\n                  \"body\": \"Hello world\",\n                  \"status_code\": 200\n                }\n              ]\n            }\n          ]\n        }\n      }\n    }\n  }\n}\n```\n\n```shell\ncurl -v localhost\n\n-----\n\u003c HTTP/1.1 200 OK\n\u003c Server: Caddy\nHello world       \n```\n\n## Managing Hostnames\n\nIf you are managing hostnames dynamically (in a database) and can't build out the config with a list of\nexisting hostnames because you need to manage them at runtime you can do the following:\n\nThe important part in this example is the `host_group_name` identifier which is later\nused to add / remove domains to this host.\n\n```php\n$caddy = new Caddy();\n$caddy-\u003eaddApp(\n    (new Http())-\u003eaddServer(\n        'server1', (new Http\\Server())-\u003eaddRoute(\n        (new Route())-\u003eaddHandle(\n            new StaticResponse('host test', 200)\n        )-\u003eaddMatch((new Host('host_group_name'))\n            -\u003esetHosts(['localhost'])\n        )\n    )-\u003eaddRoute((new Route())\n        -\u003eaddHandle(new StaticResponse('Not found', 404))\n        -\u003eaddMatch((new Host('notFound'))\n            -\u003esetHosts(['*.localhost'])\n        )\n    ))\n);\n$caddy-\u003eload();\n```\n\n### Adding Hostnames\n\nNow later on in a script or event on your system you can get your caddy configuration object and post\na new domain to it under that route:\n\n```php\n$caddy-\u003eaddHostname('host_group_name', 'new.localhost')\n$caddy-\u003eaddHostname('host_group_name', 'another.localhost')\n```\n\n```shell\ncurl -v new.localhost\n\u003e GET / HTTP/1.1\n\u003e Host: new.localhost\n\u003e \n\u003c HTTP/1.1 200 OK\n\ncurl -v another.localhost\n\u003e GET / HTTP/1.1\n\u003e Host: another.localhost\n\u003e \n\u003c HTTP/1.1 200 OK\n```\n\n### Removing Hostnames\n\n```php\n$caddy-\u003esyncHosts('host_group_name'); //Sync from caddy current hostname list\n\n$caddy-\u003eremoveHostname('host_group_name', 'new.localhost');\n$caddy-\u003eremoveHostname('host_group_name', 'another.localhost');\n```\n\n```shell\ncurl -v new.localhost\n\u003e GET / HTTP/1.1\n\u003e Host: new.localhost\n\u003e \n\u003c HTTP/1.1 404 Not Found\n\ncurl -v another.localhost\n\u003e GET / HTTP/1.1\n\u003e Host: another.localhost\n\u003e \n\u003c HTTP/1.1 404 Not Found\n```\n\n### Advanced Example\n\nLet's take a case where you want to have a Node frontend and a PHP backend taking requests on the `/api/*` route.\nIn this case the example breaks down to 2 reverse proxy's with a route matcher to filter the `/api/*` to the PHP\nupstream.\n\nThis assumes the 3 hosts (Caddy, Node, PHP) are all docker containers and accessible by container name within\nthe same docker network, so you may have to adjust your hostnames as required.\n\n```php\nuse mattvb91\\CaddyPhp\\Caddy;\nuse mattvb91\\CaddyPhp\\Config\\Apps\\Http;\nuse mattvb91\\CaddyPhp\\Config\\Apps\\Http\\Server;\nuse mattvb91\\CaddyPhp\\Config\\Apps\\Http\\Server\\Route;\nuse mattvb91\\CaddyPhp\\Config\\Apps\\Http\\Server\\Routes\\Handle\\ReverseProxy;\nuse mattvb91\\CaddyPhp\\Config\\Apps\\Http\\Server\\Routes\\Handle\\ReverseProxy\\Transport\\FastCGI;\nuse mattvb91\\CaddyPhp\\Config\\Apps\\Http\\Server\\Routes\\Handle\\ReverseProxy\\Upstream;\nuse mattvb91\\CaddyPhp\\Config\\Apps\\Http\\Server\\Routes\\Handle\\Subroute;\nuse mattvb91\\CaddyPhp\\Config\\Apps\\Http\\Server\\Routes\\Match\\Host;\nuse mattvb91\\CaddyPhp\\Config\\Apps\\Http\\Server\\Routes\\Match\\Path;\n\n$apiReverseProxy = (new ReverseProxy())\n    -\u003eaddUpstream((new Upstream())\n        -\u003esetDial('laravel-api:9000')\n    )-\u003eaddTransport((new FastCGI())\n        -\u003esetRoot('/app/public/index.php')\n        -\u003esetSplitPath([''])\n    );\n\n$apiMatchPath = (new Path())\n    -\u003esetPaths([\n        '/api/*',\n    ]);\n\n$backendAPIRoute = (new Route())\n    -\u003eaddHandle($apiReverseProxy)\n    -\u003eaddMatch($apiMatchPath);\n\n$route = new Route();\n$route-\u003eaddHandle((new Subroute())\n    -\u003eaddRoute($backendAPIRoute)\n    -\u003eaddRoute((new Route())\n        -\u003eaddHandle((new ReverseProxy())\n            -\u003eaddUpstream((new Upstream())\n                -\u003esetDial('nextjs:3000')\n            )\n        )\n    )\n)-\u003eaddMatch((new Host())\n    -\u003esetHosts([\n        'localhost',\n    ])\n)-\u003esetTerminal(true);\n\n$caddy = new Caddy();\n$caddy-\u003eaddApp((new Http())\n    -\u003eaddServer('myplatform', (new Server())\n        -\u003eaddRoute($route)\n    )\n);\n$caddy-\u003eload();\n\n```\n\nThis will post the following caddy config:\n\n```json\n{\n  \"admin\": {\n    \"disabled\": false,\n    \"listen\": \":2019\"\n  },\n  \"apps\": {\n    \"http\": {\n      \"servers\": {\n        \"myplatform\": {\n          \"listen\": [\n            \":80\"\n          ],\n          \"routes\": [\n            {\n              \"handle\": [\n                {\n                  \"handler\": \"subroute\",\n                  \"routes\": [\n                    {\n                      \"handle\": [\n                        {\n                          \"handler\": \"reverse_proxy\",\n                          \"transport\": {\n                            \"protocol\": \"fastcgi\",\n                            \"root\": \"/app/public/index.php\",\n                            \"split_path\": [\n                              \"\"\n                            ]\n                          },\n                          \"upstreams\": [\n                            {\n                              \"dial\": \"laravel-api:9000\"\n                            }\n                          ]\n                        }\n                      ],\n                      \"match\": [\n                        {\n                          \"path\": [\n                            \"/api/*\"\n                          ]\n                        }\n                      ]\n                    },\n                    {\n                      \"handle\": [\n                        {\n                          \"handler\": \"reverse_proxy\",\n                          \"upstreams\": [\n                            {\n                              \"dial\": \"nextjs:3000\"\n                            }\n                          ]\n                        }\n                      ]\n                    }\n                  ]\n                }\n              ],\n              \"match\": [\n                {\n                  \"host\": [\n                    \"localhost\"\n                  ]\n                }\n              ],\n              \"terminal\": true\n            }\n          ]\n        }\n      }\n    }\n  }\n}\n```\n\n```shell\ncurl -v localhost\n\n\u003c HTTP/1.1 200 OK\n\u003c Content-Type: text/html; charset=utf-8\n\u003c Server: Caddy\n\u003c X-Powered-By: Next.js\n\u003c Transfer-Encoding: chunked\n\u003c \n\u003c!DOCTYPE html\u003e\u003chtml\u003e....\n```\n\n```shell\ncurl -v localhost/api/testroute\n\n\u003c HTTP/1.1 200 OK\n\u003c Content-Type: application/json\n\u003c Server: Caddy\n\u003c X-Powered-By: PHP/8.1.7\n\u003c \n{\"status\":200}\n\n```\n\nTake a look in the tests for more examples.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmattvb91%2Fcaddy-php","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmattvb91%2Fcaddy-php","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmattvb91%2Fcaddy-php/lists"}