Установка

OxPHP распространяется в виде Docker-образа — это самый быстрый и рекомендуемый способ начать обслуживать PHP-приложения. Образ включает бинарный файл сервера, PHP 8.4 или 8.5 ZTS, расширение OxPHP и все зависимости времени выполнения на Alpine Linux. Теги по умолчанию :0.13.0 и :latest поставляются с PHP 8.5; для PHP 8.4 используйте теги :0.13.0-php8.4, :php8.4 или любой вариант *-php8.4*.

Docker (рекомендуется)

Скачайте официальный образ из GitHub Container Registry:

bash
docker pull ghcr.io/oxphp/oxphp:0.13.0

Образ включает:

  • Бинарный файл сервера OxPHP — асинхронный HTTP-сервер
  • Среда выполнения PHP ZTS — 8.4 или 8.5, в зависимости от скачанного тега; потокобезопасный PHP для выполнения с несколькими воркерами
  • PHP-расширение OxPHP (oxphp_sapi.so) — предоставляет oxphp_request_id(), oxphp_server_info(), oxphp_worker() и другие встроенные функции
  • Библиотека-мост (liboxphp_bridge.so) — соединяет сервер на Rust со средой выполнения PHP
  • Базовый образ Alpine Linux — минимальный размер среды выполнения (сборка на Debian публикуется по ночам, см. Образ на Debian (glibc))
  • Без директивы USER — образ запускается от имени root (как nginx:alpine / php-fpm:alpine / frankenphp:alpine), чтобы иметь возможность привязываться к привилегированным портам, но затем oxphp serve/run по умолчанию понижают привилегии до www-data перед началом обслуживания, поэтому трафик из коробки не обрабатывается от имени root. Пользователь www-data (UID 82, GID 82; 33 в образе на Debian) создаётся заранее, а каталог /var/www/html передаётся ему во владение на этапе сборки. Явно закрепите идентичность процесса на уровне оркестратора — для конкретного uid или дополнительной эшелонированной защиты:
    • docker run --user www-data ghcr.io/oxphp/oxphp:0.13.0
    • Compose: services.app.user: www-data
    • Kubernetes: securityContext.runAsUser: 82

Образ на Debian (glibc)

Ночной конвейер также публикует тот же сервер, собранный на Debian trixie вместо Alpine: ghcr.io/oxphp/oxphp:nightly-trixie (PHP 8.4), :php8.4-nightly-trixie и :php8.5-nightly-trixie, для linux/amd64 и linux/arm64.

Только ночные сборки

Релизы с тегами версий выходят только на Alpine. Ночные теги собираются из main в те ночи, когда он изменился с момента последнего полностью успешного прогона, и не дают никаких гарантий стабильности. Если в какую-то ночь сборка на Debian завершается неудачей, :nightly-trixie и :php<minor>-nightly-trixie остаются на последней успешной сборке, поэтому могут отставать от :nightly.

Образ на Debian тратит меньше процессорного времени на запрос, и тому есть две причины:

  • Локальное хранилище потока. Потокобезопасный PHP обращается к состоянию движка, принадлежащему отдельному потоку, через thread-local-указатель. При сборке с musl PHP оставляет этот указатель на модели TLS global-dynamic, поэтому код в libphp.so получает его через вызов в среду выполнения TLS; с glibc используется initial-exec — загрузка относительно указателя потока.
  • Аллокатор. Аллокатор musl, которым расширения и библиотеки вроде libpq пользуются наряду с собственным менеджером памяти PHP, отображает свежую память под результаты запросов libpq и снимает это отображение, когда они освобождаются. На x86-64 это оборачивается TLB shootdown между потоками сервера.

Процессорное время контейнера OxPHP на один ответ, образ на Debian против образа на Alpine, при одной и той же ревизии OxPHP и одном и том же патч-релизе PHP 8.5: приложение Yii3 под wrk -c64, медиана шести чередующихся прогонов. Каждая строка измерена на одном хосте: x86-64 — на облачной ВМ с 16 vCPU (AMD EPYC 9575F), arm64 — под Docker Desktop на Apple silicon. Собственное процессорное время Postgres не учитывается.

Страница Yii3 Страница с чтением из Postgres
x86-64, традиционный режим −18.9% −14.1%
x86-64, режим воркеров −18.1% −18.6%
arm64, традиционный режим −8.5% −9.0%

Что меняется для Dockerfile, построенного на этом образе:

  • Пакеты ставятся через apt-get update && apt-get install -y --no-install-recommends, а не через apk, и под именами Debian: например, libicu-dev и libpq-dev для сборки intl и pdo_pgsql, libicu76 и libpq5 во время выполнения.
  • Собирайте расширения в стадии php:<minor>-zts-trixie. Файл .so, собранный с musl в стадии -zts-alpine, несовместим с этим образом, как и наоборот.
  • У www-data UID/GID 33, а не 82: securityContext.runAsUser: 33, и всё, что передаётся во владение по числовому идентификатору, должно использовать 33.
  • wget нет, но есть curl. Проверка работоспособности, написанная для образа на Alpine как wget --spider http://localhost:9090/health, превращается в curl -fsS -o /dev/null http://localhost:9090/health.
  • Образ больше: база PHP занимает около 170–180 MiB в сжатом виде против примерно 45–50 MiB у Alpine.

Структура образа

Расположение файлов в образе среды выполнения:

text
/usr/local/ ├── bin/ │ └── oxphp # server binary ├── lib/ │ ├── libphp.so # PHP ZTS runtime (8.4 or 8.5, matches the image tag) │ ├── liboxphp_bridge.so # C bridge library │ └── php/extensions/no-debug-zts-<ABI>/ │ ├── oxphp_sapi.so # OxPHP PHP extension │ └── sodium.so, ... # from the PHP base image; the set depends on the tag └── etc/php/ └── conf.d/ ├── docker-php-ext-*.ini # from the PHP base image; the set depends on the tag └── extension.ini # extension=oxphp_sapi.so
Note

Значение <ABI> зависит от минорной версии PHP. PHP 8.4 использует 20240924, PHP 8.5 использует 20250925. В примерах ниже жёстко указан 20250925, потому что их строка FROM нацелена на php:8.5-zts-alpine3.23 (это PHP тега по умолчанию :0.13.0) — при смене FROM нужно сменить и дату. Чтобы вывести значение переносимо прямо во время сборки:

bash
php -r 'echo ini_get("extension_dir");' # /usr/local/lib/php/extensions/no-debug-zts-20250925

Используйте $(php -r 'echo ini_get("extension_dir");') в командах оболочки, чтобы не задавать значение вручную.

В образе нет собственного php.ini (помимо conf.d/, в /usr/local/etc/php/ лежат только исходные образцы php.ini-development и php.ini-production из upstream, и PHP не загружает ни один из них), а также нет никаких настроек приложения. Передайте свои в виде .ini-файла в conf.d — смонтированного или скопированного в образ; см. руководство по Docker.

Note

Имя файла определяет, будет ли .ini прочитан и когда. PHP разбирает все файлы .ini в conf.d в алфавитном порядке и молча пропускает файлы с любым другим именем. Для обычной настройки побеждает последнее прочитанное значение, поэтому файл, который её переопределяет, должен идти в сортировке после файла, который её задаёт. Директивы extension= и zend_extension=, напротив, собираются из всех файлов и загружаются все, так что более поздняя extension= никогда не заменяет более раннюю.

Три компонента OxPHP и их назначение; размеры измерены в образе 0.11.0. Размеры различаются для linux/amd64 и linux/arm64 и меняются от релиза к релизу:

Компонент Размер Назначение
oxphp ~12–15 МБ HTTP-сервер, маршрутизация, плагины, метрики
liboxphp_bridge.so ~150–170 КБ Разделяемая библиотека-мост, связывающая сервер со средой выполнения PHP
oxphp_sapi.so ~700 КБ PHP-функции (oxphp_request_id(), OxPHP\Http\Request и т. д.)

Цепочка зависимостей:

graph LR
  oxphp["oxphp"] --> libphp["libphp.so"]
  libphp --> deps["libxml2, libcurl, libsqlite3, libonig, ..."]
  oxphp --> bridge["liboxphp_bridge.so"]
  sapi["oxphp_sapi.so"] --> bridge

Бинарный файл oxphp линкуется с libphp.so и liboxphp_bridge.so. PHP-расширение oxphp_sapi.so также линкуется с библиотекой-мостом, чтобы состояние отдельного запроса было доступно вашему PHP-коду.

Минимальный Dockerfile

Базовый образ php:8.5-zts-alpine3.23 (или php:8.4-zts-alpine3.23) уже содержит libphp.so и все его зависимости. Минорную версию PHP в вашем FROM согласуйте с тегом OxPHP, из которого вы копируете, и библиотеку C тоже: артефакты из тега -trixie ставятся на php:<minor>-zts-trixie, а не на базу Alpine. Достаточно скопировать три артефакта OxPHP и добавить libgcc: с ней линкуется собранный на Rust бинарный файл oxphp, а в PHP-образе на Alpine её нет:

Dockerfile
FROM php:8.5-zts-alpine3.23 RUN apk add --no-cache libgcc COPY --from=ghcr.io/oxphp/oxphp:0.13.0 /usr/local/bin/oxphp /usr/local/bin/oxphp COPY --from=ghcr.io/oxphp/oxphp:0.13.0 /usr/local/lib/liboxphp_bridge.so /usr/local/lib/ COPY --from=ghcr.io/oxphp/oxphp:0.13.0 /usr/local/lib/php/extensions/no-debug-zts-20250925/oxphp_sapi.so /usr/local/lib/php/extensions/no-debug-zts-20250925/ RUN echo "extension=oxphp_sapi.so" > /usr/local/etc/php/conf.d/oxphp.ini COPY --chown=www-data:www-data . /var/www/html/public EXPOSE 80 443 CMD ["oxphp"]

Этот подход удобен для разработки: доступны PHP CLI, docker-php-ext-install и pecl. Composer и Xdebug в базовый образ PHP не входят. Добавьте их сами с помощью COPY --from=composer:2 /usr/bin/composer /usr/local/bin/composer и pecl install xdebug, как это делает таргет dev в руководстве по Docker.

Продакшен-Dockerfile

Официальный образ OxPHP сохраняет PHP CLI и инструменты для расширений (php, phpize, pecl, docker-php-ext-install) образа php:<minor>-zts-alpine3.23, на котором он построен, поэтому расширения можно устанавливать прямо в нём; см. Установка PHP-расширений в продакшене. Если же собирать их в отдельной стадии, пакеты, нужные только для сборки, такие как icu-dev, не попадут в итоговый образ. Выбор между двумя вариантами сборки ниже зависит от того, нужны ли вам дополнительные PHP-расширения.

Если вашему приложению нужны дополнительные расширения (pdo_mysql, intl и т. д.), соберите их в отдельной стадии и скопируйте в итоговый образ:

Dockerfile
# Extension build stage FROM php:8.5-zts-alpine3.23 AS extensions RUN apk add --no-cache icu-dev postgresql-dev \ && docker-php-ext-install pdo pdo_mysql pdo_pgsql intl # Production FROM ghcr.io/oxphp/oxphp:0.13.0 # Runtime dependencies for extensions USER root RUN apk add --no-cache icu-libs libpq # Copy compiled extensions COPY --from=extensions /usr/local/lib/php/extensions/no-debug-zts-20250925/*.so /usr/local/lib/php/extensions/no-debug-zts-20250925/ # Enable extensions RUN { \ echo "extension=pdo.so"; \ echo "extension=pdo_mysql.so"; \ echo "extension=pdo_pgsql.so"; \ echo "extension=intl.so"; \ } > /usr/local/etc/php/conf.d/app-extensions.ini USER www-data COPY --chown=www-data:www-data . /var/www/html/public

Соберите и запустите:

bash
docker build -t my-app . docker run -p 80:80 my-app

По умолчанию сервер слушает порт 80. Корневой каталог документов — /var/www/html/public, и приведённые выше сниппеты копируют проект прямо в него. Для Laravel, Symfony и других фреймворков, которые уже поставляются с подкаталогом public/, используйте вместо этого COPY --chown=www-data:www-data . /var/www/html, чтобы собственный каталог public/ фреймворка совпал со значением по умолчанию. Если ваша структура отличается ещё сильнее, переопределите корневой каталог документов переменной окружения DOCUMENT_ROOT.

Сборка из исходников (без PHP)

Соберите OxPHP из исходников с отключённой поддержкой PHP, чтобы обслуживать только статические файлы:

bash
cargo build --release --no-default-features

Бинарный файл находится в target/release/oxphp. Он использует исполнитель-заглушку, который возвращает ответ-заглушку на PHP-запросы, при этом статические файлы обслуживаются как обычно. Этот режим полезен для тестирования сервера без установленной среды выполнения PHP.

Сборка из исходников (с PHP)

Для сборки OxPHP с полной поддержкой PHP сначала нужно скомпилировать и установить библиотеку-мост и PHP-расширение.

Предварительные требования

  • Инструментарий Rust (1.91.1 или новее)
  • PHP 8.4 или 8.5 с включённым ZTS (Zend Thread Safety)
  • Компилятор C (gcc или clang)
  • phpize и заголовочные файлы для разработки PHP

Шаги сборки

  1. Соберите и установите библиотеку-мост.

    bash
    cd ext/bridge make && sudo make install
  2. Соберите и установите PHP-расширение.

    bash
    cd ../ phpize && ./configure --enable-oxphp-sapi && make && sudo make install
  3. Соберите OxPHP. Набор возможностей по умолчанию включает php.

    bash
    cargo build --release

Во время выполнения бинарному файлу нужны разделяемые библиотеки в пути поиска библиотек:

bash
export LD_LIBRARY_PATH=/usr/local/lib ./target/release/oxphp
Note

При развёртывании на Alpine Linux выполняйте сборку внутри того же образа php:{8.4,8.5}-zts-alpine, который используется в качестве среды выполнения PHP, — согласуйте минорную версию с образом OxPHP, который вы поставляете. Смешивание сборок под glibc и musl приводит к ошибкам во время выполнения. Официальный Docker-образ обрабатывает это корректно.

Проверка установки

После запуска OxPHP структурированный вывод логов в формате JSON подтверждает, что сервер работает:

text
{"timestamp":"...","level":"INFO","message":"OxPHP HTTP server starting","listen_addr":"0.0.0.0:80",...} {"timestamp":"...","level":"INFO","message":"Server listening","addr":"0.0.0.0:80"}

Проверьте, что сервер отвечает:

bash
curl http://localhost/

Если вы включили внутренний сервер через INTERNAL_ADDR, проверьте эндпоинт проверки работоспособности:

bash
curl http://localhost:9090/health

Исправный сервер возвращает 200 со статусом в формате JSON. Сервер с деградацией возвращает 503.

Что дальше

  • Быстрый старт — создайте проект, запустите OxPHP с помощью Docker Compose и выполните первый запрос
  • Руководство по Docker — Dockerfile для разработки и продакшена, настройка Compose и монтирование томов
  • Конфигурация — полный справочник по переменным окружения
Нашли ошибку? Сообщите →