Docker
このコンテンツはまだ日本語訳がありません。
Debian Trixie images with Apache 2.4, PHP-FPM and HTTP/2 for Yii2 applications
These are container images, not Composer extensions. Use them to run an existing Yii application; they do not create an application or install the Yii framework by themselves.
Each image runs Apache (event MPM, HTTP/2, HTTPS) in front of PHP-FPM under supervisord, serves the application
from /var/www/app/web, and prepares the application at startup (directories, Composer, migrations) through an
entrypoint configured with environment variables.
Images are published to ghcr.io/yii2-extensions/apache for linux/amd64 and linux/arm64.
| Tag | Example | Lifecycle |
|---|---|---|
<php>-debian-<variant> | 8.5-debian-prod | Rolling: rebuilt weekly from the latest release to pick up PHP and Debian security patches. |
<php>-debian-<variant>-v<version> | 8.5-debian-prod-v2.0.0 | Frozen at release time. |
latest | latest | Rolling: the prod variant of the newest stable PHP version (currently 8.5). |
- PHP versions:
8.3,8.4,8.5. PHP 8.6 is built in CI from its release candidate as an experimental job and is not published until it is stable. - Variants:
prod,dev,full.
Rolling tags move when the release workflow rebuilds them; an existing container does not update itself. Pull the selected tag and recreate your container to use a newer image. Use a frozen release tag, or pin the registry digest, when you need a fixed image. Verify availability before changing versions:
docker buildx imagetools inspect ghcr.io/yii2-extensions/apache:8.5-debian-dev-v2.0.0The release workflow publishes stable versions only. Locally generated Bake tags, particularly PHP 8.6 tags, are not evidence that those images exist in the registry.
Quick start
Section titled “Quick start”First install Docker Engine or Docker Desktop and confirm docker info
succeeds. Docker Compose v2 or newer is needed only for Compose examples; Buildx is needed to build these images.
Start in an existing application root containing composer.json and a Web entry point. The default document root
is web/; the Yii 22.0 basic template on branch 22
uses public/ and needs the setting described in the installation guide.
Match the application’s own framework and PHP version constraints. See installation for the complete setup.
Run the dev variant against that application in the current directory. On Linux, pass your own user so the files the
container creates (vendor/, runtime/, web/assets/) belong to you:
docker run -d --name app --user "$(id -u):$(id -g)" -p 127.0.0.1:8080:80 -p 127.0.0.1:8443:443 -v "$PWD":/var/www/app \ ghcr.io/yii2-extensions/apache:8.5-debian-dev-v2.0.0The application answers on http://localhost:8080 and, with a generated self-signed certificate, on
https://localhost:8443. Composer installs the dependencies at startup when vendor/ is missing, as the container
user, so the project directory must be writable by it. Without --user the stack runs as www-data (UID 33), which
can suit Docker Desktop. A named volume must also have suitable ownership; mounting one does not grant UID 33
write access automatically. On runtimes that keep ports below 1024 privileged (Kubernetes, --network host), set APACHE_HTTP_PORT=8080 and APACHE_HTTPS_PORT=8443 and map -p 8080:8080 -p 8443:8443 instead.
With Docker Compose, save this as compose.yaml in the application root:
services: app: image: ghcr.io/yii2-extensions/apache:8.5-debian-dev-v2.0.0 user: "${APP_UID:?Set APP_UID}:${APP_GID:?Set APP_GID}" ports: - "127.0.0.1:8080:80" - "127.0.0.1:8443:443" volumes: - .:/var/www/app environment: YII_ENV: dev YII_DEBUG: "1" FAIL_ON_COMPOSER_ERROR: "true"APP_UID="$(id -u)" APP_GID="$(id -g)" docker compose up -ddocker compose logs appcurl --fail http://127.0.0.1:8080/healthYII_ENV and YII_DEBUG are available to PHP, but your application entry scripts must read them; setting container
variables does not override constants already defined by the application. The health endpoint checks the stack,
so also request an application route. Usage examples cover CLI commands and cleanup.
For production, build an application image on top of prod so the code and its dependencies are part of the image:
FROM ghcr.io/yii2-extensions/apache:8.5-debian-prod-v2.0.0
COPY --chown=www-data:www-data . /var/www/appRUN composer install --no-dev --optimize-autoloader --no-interaction --no-progressKeep credentials, .env, .git, local vendor/, node_modules/, runtime files, and uploads out of the build
context with an application .dockerignore. Include composer.lock; decide which application Composer scripts and
plugins may run during the build. The image does not configure your database or persist uploaded files.
Variants
Section titled “Variants”| Variant | PHP extensions | Tools |
|---|---|---|
prod | apcu, bcmath, gd, imagick, intl, opcache, pcntl, pdo_mysql, pdo_pgsql, redis, zip | Composer |
dev | prod plus memcached, mongodb, soap, xdebug, yaml | Composer, Node.js 24, npm |
full | dev plus oci8, pdo_oci, pdo_sqlsrv, sqlsrv, tidy | Composer, Node.js 24, npm, Oracle Instant Client, Microsoft ODBC Driver 18 |
prod: OPcache without timestamp validation and with the tracing JIT, session cookies restricted to HTTPS (session.cookie_secure) andSameSite=Strict, no Composer install at startup by default.dev: OPcache revalidates files on every request, JIT disabled, Xdebug loaded.full:devplus the Oracle and SQL Server drivers and assertions enabled, JIT disabled as indev(Xdebug is loaded); intended for test suites that cover every database driver.
Compressed size of the PHP 8.5 images:
| Variant | v1.1.0 | v2.0.0 |
|---|---|---|
prod | 232.9 MiB | 125.1 MiB |
dev | 235.3 MiB | 175.4 MiB |
full | 275.6 MiB | 215.4 MiB |
Configuration
Section titled “Configuration”The most common settings are listed below. See the configuration reference for every variable, its default and the startup sequence.
| Variable | Default | Description |
|---|---|---|
APACHE_DOCUMENT_ROOT | /var/www/app/web | Document root. |
APACHE_HTTP_PORT | 80 | HTTP port inside the container. |
APACHE_HTTPS_PORT | 443 | HTTPS port inside the container. |
APACHE_SSL_ENABLED | true | HTTPS with HTTP/2 on APACHE_HTTPS_PORT. |
APACHE_SSL_REDIRECT | false | Redirect HTTP to HTTPS. |
SSL_AUTO_GENERATE | true | Generate a self-signed certificate when none is mounted. |
SSL_CERT_FILE | /etc/apache2/ssl/cert.pem | Mounted certificate, readable by the container user. |
SSL_KEY_FILE | /etc/apache2/ssl/key.pem | Mounted private key, readable by the container user. |
SKIP_COMPOSER_INSTALL | true for prod, false otherwise | Skip composer install at startup. |
YII_RUN_MIGRATIONS | false | Run yii migrate at startup. |
WAIT_FOR_SERVICES | false | Wait for the DB_*_HOST services before starting. |
ENABLE_HEALTH_ENDPOINT | true | Serve the public health endpoint at HEALTHCHECK_PATH. |
ENABLE_FPM_STATUS | false | Serve the PHP-FPM status and ping pages to loopback only. |
PHP_MEMORY_LIMIT | 256M | PHP memory limit; every PHP_* setting is listed in the docs. |
To use your own certificate, mount it and point the entrypoint at it:
docker run -d -p 80:80 -p 443:443 \ -v /path/to/certs:/run/certs:ro \ -e SSL_AUTO_GENERATE=false \ -e SSL_CERT_FILE=/run/certs/fullchain.pem \ -e SSL_KEY_FILE=/run/certs/privkey.pem \ -e APACHE_SSL_REDIRECT=true \ my-appUsers and privileges
Section titled “Users and privileges”The whole stack (the entrypoint, supervisord, Apache and PHP-FPM) runs as the container user. The default and
arbitrary-UID modes run without root; root mode is an explicit choice:
www-data(default, the image declaresUSER www-data).- Any UID, with
--user <uid>:<gid>or Composeuser:. The UID needs no account in the image, so files created in a bind-mounted project belong to the host user. The entrypoint cannot change ownership in this mode; when the application directory is not writable it says so and names the remedy. - Root, as an explicit opt-in with
--user root: the entrypoint initializes as root (directories,FIX_PERMSbefore a Composer install), then Apache and PHP-FPM drop their workers towww-data, as in v1. Nothing root sources, executes or loads may be written bywww-data, and the generated private key is readable by root only.
Runtime state (pid files, sockets, the Apache runtime environment, generated certificates, PHP sessions and temporary
files) lives under /run/yii2 and is created at every start for the running user. In the two non-root modes no
process can gain root, so the class of privilege escalation that the root mode must guard against does not exist.
Ports 80 and 443 work as a non-root user under docker run, because Docker allows unprivileged processes to bind
every port. Kubernetes, --network host and other runtimes that keep ports below 1024 privileged need
APACHE_HTTP_PORT and APACHE_HTTPS_PORT (for example 8080 and 8443); the entrypoint stops with that remedy when
the configured port cannot be bound. The container side of the port mappings changes with them: -p 8080:80 becomes
-p 8080:8080. See the configuration reference for the read-only root
filesystem flags.
Health checks
Section titled “Health checks”GET /healthreturns a JSON status document produced by PHP-FPM. Change the path withHEALTHCHECK_PATHor disable it withENABLE_HEALTH_ENDPOINT=false.- The Docker
HEALTHCHECKruns thehealthcheckcommand, which requests the reserved, loopback-only/__healthpath through Apache and PHP-FPM. The container becomes unhealthy when either of them stops answering.
Extending the image
Section titled “Extending the image”The images contain neither the compiler toolchain nor the PHP source tarball. The included install-extensions
command compiles extensions in a derived image in one step:
FROM ghcr.io/yii2-extensions/apache:8.5-debian-prod
USER rootRUN install-extensions amqp socketsUSER www-dataThe image runs as www-data, so every step that installs packages or extensions needs USER root first, and the
image should switch back to USER www-data afterwards; install-extensions stops with that hint when it is not root.
It accepts the extension names and version syntax of
install-php-extensions (PECL and bundled extensions).
It downloads the exact PHP source the image was built from and verifies its SHA-256 checksum, installs the
toolchain, builds the extensions, then removes the toolchain, the source and the build-only packages while keeping
the shared libraries the new extensions load. The build fails when a library is left unresolved or PHP reports a
startup warning. The added size depends on the extensions and their runtime libraries.
Ghostscript is not included, so Imagick reads and writes raster formats (JPEG, PNG, WebP, GIF and others) but not PDF, PS or EPS. Add it in a derived image when you need them:
USER rootRUN apt-get update && apt-get install -y --no-install-recommends ghostscript && rm -rf /var/lib/apt/lists/*USER www-dataUpgrading from v1
Section titled “Upgrading from v1”Version 2 contains breaking changes. Review each item before switching tags.
- No toolchain in the image. Images ship without compilers and PHP sources. Derived images that compile
extensions use the included
install-extensionscommand (see Extending the image). - Runs as
www-data. The image declaresUSER www-dataand the whole stack runs as the container user;docker execdefaults towww-data. Use--user "$(id -u):$(id -g)"for bind mounts on Linux (v1 changed the owner of the project towww-datainstead), or--user rootfor the v1 behavior (root initialization,FIX_PERMS, workers aswww-data). Derived images needUSER rootbefore installing packages or extensions andUSER www-dataafter; application files copied into a derived image must be readable by the runtime user, and directories used by Composer or the application must be writable (the quick start usesCOPY --chown=www-data:www-data). - Runtime state moved to
/run/yii2. Pid files, the PHP-FPM socket (/run/yii2/php/php-fpm.sock), the supervisor socket, PHP sessions (PHP_SESSION_PATH=/run/yii2/sessions), PHP temporary files and the generated self-signed certificate (/run/yii2/ssl) are created at every start. Generated certificates are no longer written toSSL_DIRand do not survive a restart; mounted certificates must be readable by the container user, otherwise the container serves HTTP only and logs why./etc/apache2and/etc/apache2/sslbelong to root. - No
sudo,gosu,vim-tinyorbrotliCLI.www-datano longer has passwordlesssudo, and the entrypoint no longer re-executes itself as root. - Node.js is no longer downloaded at startup.
devandfullinclude Node.js 24 and npm;proddoes not. Build front-end assets in your application image or in a separate build stage. prodskipscomposer installby default. Install dependencies in the application image, or setSKIP_COMPOSER_INSTALL=falseto restore the v1 behavior.FAIL_ON_*flags are honored.FAIL_ON_SERVICE_TIMEOUTandFAIL_ON_COMPOSER_ERRORdefault tofalse, so an unreachable service or a failed Composer install is logged and startup continues; v1 aborted the container. Set them totrueto keep failing fast.FAIL_ON_MIGRATION_ERRORdefaults totrue.- Health endpoint served from the image. Nothing is written to
web/any more; remove theweb/health/directory that v1 created in the application./__healthis reserved. The container now turns unhealthy when PHP-FPM is down. - No User-Agent filter. Requests from clients whose User-Agent contains
bot,curl,wget,pythonorscanare no longer rejected with 403. Block unwanted clients at your proxy or firewall if needed. - Single virtual host file.
sites-available/vhost-ssl.confandsites-available/vhost-ssl-full.confare gone;sites-available/vhost.confis driven by Apache defines and the entrypoint no longer rewrites configuration files.APACHE_HTTPS_PORTis not opened whenAPACHE_SSL_ENABLED=false. Images that replaced or patched these files must be updated. - Apache defaults. The ineffective
<LimitExcept>block, the inert global rewrite rules and07-rate-limiting.confare removed. Debian’s default configuration snippets are disabled, so theServerheader isApacheand nothing is logged to files inside the container. - Shorter
PHP_DISABLE_FUNCTIONSdefault. Web requests now block only the shell functions (exec,passthru,shell_exec,system,proc_open,popen);parse_ini_fileandshow_sourceare available again. The list is applied to the PHP-FPM master instead of the pool, so pools you add inherit it and cannot re-enable its functions withphp_admin_value[disable_functions]; set the variable instead. - PHP-FPM status is opt-in. Set
ENABLE_FPM_STATUS=trueto servePHP_FPM_STATUS_PATHandPHP_FPM_PING_PATHto loopback only./fpm-status-fullis replaced by?fullon the status path. - SQL Server drivers.
sqlsrvandpdo_sqlsrv5.13 come from the extension installer instead of a patched 5.12.0 build. - Xdebug configuration. The unused
xdebug.iniis removed; configure Xdebug withXDEBUG_MODEandXDEBUG_CONFIG(see the configuration reference). - No JIT in
full. Xdebug made PHP disable the tracing JIT anyway and warn at every startup;fullnow turns it off likedev.prodkeeps the tracing JIT. - Inert Apache variables removed.
APACHE_RUN_USER,APACHE_RUN_GROUP,APACHE_RUN_DIR,APACHE_PID_FILEandAPACHE_LOCK_DIRare no longer in the image environment./etc/apache2/envvarsalways overrode them, so setting them never had an effect; drop them from your configuration. - Published assets are served. The Yii directory protection is anchored at
/var/www/app, so files underweb/assets/<hash>/widgets/orweb/assets/<hash>/vendor/(jQuery UI, for example) no longer return 403.
APACHE_SSL_REDIRECT, SSL_AUTO_GENERATE, SSL_CERT_FILE, SSL_KEY_FILE, SSL_DIR, SSL_CHAIN_FILE,
APACHE_DISABLE_OCSP_STAPLING, DEBUG_ENTRYPOINT, FORCE_COMPOSER_INSTALL, FIX_PERMS and every APACHE_* and
PHP_* tuning variable keep their names, defaults and behavior.
Development
Section titled “Development”See testing for isolated runtime validation and the distinction between the fixture and a real
application test. No build command below publishes images; never use the digest-* targets for local validation.
docker-bake.hcl is the single source of truth for PHP versions, variants and tags. Adding a PHP version is one
entry in its PHP variable; an entry whose base differs from version (a release candidate such as 8.6-rc) is
experimental, excluded from the default group and never published.
# Build every stable image (PHP 8.3 to 8.5, all variants)docker buildx bake
# Build one image and load it into the local image storedocker buildx bake image-8-5-dev --load
# Build the experimental PHP 8.6 imagedocker buildx bake image-8-6-prod --load
# Print every image target as JSONdocker buildx bake --print imageContinuous integration:
| Workflow | Trigger | Purpose |
|---|---|---|
build.yml | Pull requests, pushes to main | Builds every PHP version on both architectures. |
release.yml | Tags vX.Y.Z, weekly schedule, manual run | Publishes a release; the weekly run rebuilds the latest release and moves the rolling tags. |
quality.yml | Pull requests, pushes | Organization quality checks, Hadolint and ShellCheck. |
security.yml | Pull requests, pushes | Organization security checks. |
Documentation
Section titled “Documentation”Practical guides for selecting images, running Yii applications, and validating containers.
- 📚 Installation Guide: image tags, application mounts, and startup.
- ⚙️ Configuration Guide: environment variables, ports, and permissions.
- 💡 Usage Examples: Compose, CLI commands, and application images.
- 🔄 Upgrading from v1
- 🧪 Testing Guide: isolated image checks and application validation.
AI assistance
Section titled “AI assistance”AI agents: use the repository guides and source for the installed revision.
For a documentation deployment with
llms.txt, read that index first. When Markdown export is enabled, append
index.md to a page URL.
- 🤖 yii2-docker-environment skill: image selection, isolated checks, and cleanup.
The skill source covers HTTP/HTTPS, PHP-FPM, and filesystem behavior.
If the hosted sources are unavailable, use the repository guides and locally available skills.
Our social networks
Section titled “Our social networks”License
Section titled “License”Package
Section titled “Package”- Source code and issues: yii2-extensions/docker-images. Star the repository if the package is useful to you.
- Changelog: CHANGELOG.md.