This is a repository for Infection Playground, hosted here: https://infection-php.dev
Please read documentation here: infection.github.io
- Twitter: [@infection_php][twitter]
- Mastodon: [@infection_php][mastodon]
- Discord: https://discord.gg/ZUmyHTJ
The project is based on dunglas/symfony-docker:
FrankenPHP (Caddy) and MySQL, PHP 8.5, Symfony 8. There is no Node.js: the frontend is served by
AssetMapper, Tailwind CSS is built by
symfonycasts/tailwind-bundle and the
Monaco Editor is taken from its npm package by the Dockerfile.
docker compose up --waitand open https://localhost (accept the self-signed certificate).
The database is migrated when the container starts. To recreate the dev and test databases:
make docker-app-reinstallTests, static analysis and coding standards:
make docker-analyzeRebuild the CSS while changing templates:
make docker-tailwind-watchPlayground runs use the PHARs in infection-builds/, their versions are in App\Infection\Runner.
The PHP version is the one of the Docker image.
Production runs compose.yaml + compose.prod.yaml on the droplet. Caddy gets and renews the
Let's Encrypt certificate for infection-php.dev automatically (ports 80 and 443 must be reachable),
and keeps it in the caddy_data volume.
The deploy scripts read the settings from the git-ignored secrets/ directory
(app_secret, mysql_db_name, mysql_db_user, mysql_password, mysql_root_password, ssh_user, ssh_host)
and talk to Docker on the droplet over SSH.
deploy/prod.shbuilds and pushes the image, then restarts the app; the container runs the Doctrine migrations on start.
deploy/backup.shdumps the production database to the git-ignored backups/ directory. Nothing backs it up automatically.
/explore lists the runs, ranked by the numbers of their JSON logs, which are copied into columns when a run
finishes. The runs made before Explore get their numbers once, after the deploy that adds it:
deploy/console.sh app:example:backfill-statsdeploy/console.sh runs any console command in the php container of the droplet.
- Docker Engine 20.10.10 or newer: the images are built on glibc 2.34+, whose threads need the
clone3syscall, which the seccomp profile of older Docker versions rejects. The deploy scripts check this and refuse to run. - Ports 80/tcp and 443/tcp (and 443/udp for HTTP/3) reachable from the internet. MySQL is not published.
- Some swap: the droplet has 2 GB of RAM for MySQL 8.4, FrankenPHP and the playground runs.
Until 2026 production ran a Docker swarm stack (nginx + php-fpm + MySQL 5.7, certificates from certbot).
deploy/migrate-from-swarm.sh moves it to this setup: it dumps the MySQL 5.7 database to backups/,
removes the swarm stack, loads the dump into MySQL 8.4 on a new volume, compares the row counts and
starts the app. The legacy volume infection_db-data is kept for a rollback.
Run it with DRY_RUN=1 first: that only takes the dump and changes nothing.
The droplet ran Docker 19.03 at that time, so Docker has to be upgraded before the switch (see the requirements above).