A Castor plugin that turns a PHP description of your stack into a Docker Compose environment, and gives you the tasks to drive it.
- 🚀 Automatic Docker Compose configuration generation
- 🔧 Pre-configured services for common infrastructure components
- 🎯 Service-specific tasks for common operations
- 🔒 On-demand, locally-trusted HTTPS (with mkcert support)
- 🌐 Caddy-based reverse proxy with automatic routing from Docker labels
- 📦 Multi-stage Docker builds with registry caching
- 👥 Multi-application, multi-language support in a single project
castor composer require castor-php/docker- Create a
castor.phpfile in your project root:
<?php
namespace project;
use Castor\Attribute\AsContext;
use Castor\Attribute\AsListener;
use Castor\Context;
use Castor\Docker\Event\RegisterServiceEvent;
use Castor\Docker\Service\PostgresService;
use Castor\Docker\Service\SymfonyService;
#[AsContext(default: true)]
function default_context(): Context
{
return new Context([
'root_domain' => 'myproject.test',
'registry' => 'ghcr.io/mycompany/myproject'
]);
}
#[AsListener(RegisterServiceEvent::class)]
function register_service(RegisterServiceEvent $event)
{
$postgresService = new PostgresService();
$event->addService($postgresService);
$event->addService(
(new SymfonyService(name: 'app', directory: __DIR__))
->withDatabaseService($postgresService)
->addDomain('myproject.test')
->allowHttpAccess()
);
}- Start your project infrastructure:
castor docker:build
castor docker:upThe global Caddy router serving your domains is started along with it, and stopped again when no project needs it anymore.
- See what it serves:
castor docker:aboutIt lists every URL the project answers on, with the service serving each of them.
The Caddy router is global: one instance, living outside of any project, serves every Castor Docker project on the machine. Ports 80 and 443 are bound once, projects run side by side, and the router survives their restarts.
docker:up starts it when the project routes a domain, docker:stop stops it
once no routed container is left running anywhere. It lives in
~/.castor/docker/router/, and these tasks are for the times you want to decide
yourself:
castor docker:router:enable # create, start and trust it
castor docker:router:status # is it running, which projects it serves
castor docker:router:logs # add --follow to tail them
castor docker:router:restart
castor docker:router:disableSet the router_autostart context variable to false, or
CASTOR_DOCKER_ROUTER_AUTOSTART=0 for a single command, to leave the router
entirely to those tasks.
Each project keeps its own compose network, and the router joins it on
docker:up rather than every project joining a shared one — so two projects can
both have a service named app without colliding in the Docker DNS. See the
router documentation for
the details.
Registering those two services also gave you tasks: castor app:bash,
castor app:install, castor app:symfony, castor postgres:client,
castor docker:logs, and more.
Prefer not to write it by hand? Let the plugin do it:
castor docker:service:install symfonyEverything is on https://castor-php.github.io/docker/:
- Getting started — installation, first environment, service configuration
- Services — PHP, Go, Rust, databases, cache, queue, search, router
- Tasks — the commands the plugin gives you
- Going further — multiple applications, custom images, writing your own service
See the example directory for a complete working project with multiple applications and services.
The documentation lives in doc/ and is built with MkDocs:
castor docs:serve # http://127.0.0.1:8000, rebuilds on change
castor docs:build # build the static site in tools/mkdocs/siteQuality tooling for the plugin itself:
castor qa:phpstan
castor qa:cs
vendor/bin/phpunitThis plugin is part of the Castor project, released under the MIT license.