Example Deployments

These guides show how to run nine popular PHP applications on OxPHP, each as a self-contained Docker Compose project. Every recipe was built and verified end-to-end. Its Verify section lists the requests that were checked and the status each one returns.

Each page is a complete, copy-pasteable recipe: a Dockerfile, a docker-compose.yml, the install commands, and the OxPHP-specific details that the application's stock documentation (written for nginx + PHP-FPM) does not cover.

The applications

Application Type Routing mode PHP Extra services Install method
Laravel Framework Framework 8.5 MySQL composer create-project
Symfony Framework Framework 8.5 — composer create-project
Yii3 Framework Framework 8.5 — composer create-project
WordPress CMS Traditional 8.5 MySQL WP-CLI
Drupal CMS Framework 8.4 MySQL drush site:install
Craft CMS CMS Framework 8.5 MySQL craft install
October CMS CMS Framework + mirror 8.4 MySQL october:migrate + mirror
Magento E-commerce Framework 8.4 MySQL + OpenSearch bin/magento setup:install
OpenCart E-commerce Traditional 8.4 MySQL CLI installer

What every recipe has in common

Build on the published OxPHP image

OxPHP ships a ready PHP runtime as ghcr.io/oxphp/oxphp (PHP 8.5 by default; a PHP 8.4 variant is published as ghcr.io/oxphp/oxphp:<ver>-php8.4-alpine<X>). The published image already contains the oxphp binary, libphp.so, the OxPHP SAPI extension, the PHP CLI, and Composer-friendly tooling. The recipes extend it in one of two shapes:

  1. Copy OxPHP into a php:*-zts-alpine base. Laravel, Symfony, Yii3, Craft, Magento, OpenCart, Drupal and October are built this way. A multi-stage build assembles a dev image from four stages:

    Dockerfile
    FROM php:8.4-zts-alpine3.23 AS php-base # your app's PHP extensions FROM composer:2 AS composer # the Composer binary FROM ghcr.io/oxphp/oxphp:0.13.0-php8.4-alpine3.23 AS oxphp # OxPHP artifacts FROM php-base AS dev # final image # ... copy the oxphp binary, bridge library, and SAPI extension across: COPY --from=oxphp /usr/local/bin/oxphp /usr/local/bin/oxphp COPY --from=oxphp /usr/local/lib/liboxphp_bridge.so /usr/local/lib/ COPY --from=oxphp /usr/local/lib/php/extensions/ /tmp/oxphp-ext/ RUN cp /tmp/oxphp-ext/*/oxphp_sapi.so "$(php -r 'echo ini_get("extension_dir");')/" \ && echo "extension=oxphp_sapi.so" > /usr/local/etc/php/conf.d/oxphp-ext.ini
  2. Extend the OxPHP runtime directly, as the WordPress recipe does. A builder stage compiles the extensions against a matching php:*-zts-alpine and drops the .so files into the OxPHP image.

Note

Either way, the PHP ABI must match. The OxPHP image's libphp.so and oxphp_sapi.so are compiled for one PHP version (e.g. 8.4 → no-debug-zts-20240924); the php-base/builder stage must use the same php:<X.Y>-zts-alpine<Z> so the extensions you compile are ABI-compatible. Mixing versions makes oxphp_sapi.so refuse to load or corrupts musl TLS at startup.

See the Docker Guide for the canonical multi-stage template, and examples/dockerfile/ in the repository for a ready-to-copy version.

Pick the PHP version deliberately

The default ghcr.io/oxphp/oxphp:<ver> image is PHP 8.5. That is fine for modern frameworks (Laravel, Symfony, Yii3, Craft). Older or more conservative codebases (Magento, OpenCart, Drupal, October CMS) pin PHP 8.4 via the …-php8.4-alpine… tag, because their component stacks predate 8.5 and emit deprecations on it. Each recipe states which it uses and why.

Choose the routing mode from the app's shape

OxPHP's routing mode maps directly onto how the application is laid out:

  • Framework mode (ENTRY_FILE=index.php) fits an app with one front controller under a public/ (or web/, pub/) directory. Existing static files are served from disk and everything else is dispatched to index.php. Use it for Laravel, Symfony, Yii3, Craft, Magento, Drupal, October.
  • Traditional mode (no ENTRY_FILE) serves multiple physical PHP entry points (e.g. index.php plus an admin/ directory) as real files. Use it for WordPress and OpenCart.

Install through the same container

The dev image carries the PHP CLI and Composer (and drush, bin/magento, php yii, php craft, php artisan as appropriate), so install and maintenance commands run inside the running container, without a separate toolchain. WordPress is the exception: its image extends the OxPHP runtime, which ships no wp binary, so WP-CLI runs in the wpcli sidecar container instead. For the other recipes:

bash
docker compose exec app php artisan migrate # Laravel docker compose exec app vendor/bin/drush cr # Drupal docker compose run --rm app composer install # any

Security defaults that apply everywhere

OxPHP gives you, for free, several protections that nginx + PHP-FPM require explicit config for:

  • Dot-path blocking makes .env, .git/, .htaccess and any other dot-segment path return 404 without configuration. This is why running an app from a directory that also contains .env does not leak it.
  • The traditional-mode recipes use the PHP execution deny-list (PHP_DENY_PATHS). OpenCart blocks system/ and install/ scripts, and WordPress blocks .php execution under wp-content/uploads/. It is a no-op in framework mode, where arbitrary .php is never executed directly.
  • October CMS uses symlink allow-paths (SYMLINK_ALLOW_PATHS) so that OxPHP follows the asset symlinks produced by october:mirror public. Symlink escapes stay blocked everywhere else.

The recipes

The pages are grouped by application type, mirroring the directory layout:

text
examples/ ├── framework/ # Laravel, Symfony, Yii3 ├── cms/ # WordPress, Drupal, Craft, October └── ecommerce/ # Magento, OpenCart

Framework — framework/

  • Laravel is the canonical framework-mode app.
  • Symfony is a minimal skeleton with no database.
  • Yii3 is the leanest of all, with core extensions only.

CMS — cms/

  • WordPress runs in traditional mode, with a runtime-extension build and a WP-CLI sidecar.
  • Drupal runs in framework mode, with PDO + drush.
  • Craft CMS runs in framework mode and installs from the console.
  • October CMS runs in framework mode with a public/ mirror and SYMLINK_ALLOW_PATHS.

E-commerce — ecommerce/

  • Magento is the heaviest, with OpenSearch, PHP 8.4, and a static-asset version symlink.
  • OpenCart runs in traditional mode with two front controllers and PHP_DENY_PATHS.
Found a mistake? Report it →