Встановлення

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 витрачає менше CPU на запит, і на це є дві причини:

  • Локальне сховище потоку (thread-local storage). Потокобезпечний PHP звертається до стану рушія кожного потоку через локальний для потоку вказівник. У збірці під musl PHP лишає цей вказівник на моделі TLS global-dynamic, тож код у libphp.so дістається до нього через виклик у середовище виконання TLS; під glibc використовується initial-exec — завантаження відносно вказівника потоку.
  • Алокатор. Алокатор musl, яким поряд із власним менеджером пам’яті PHP користуються розширення та бібліотеки на кшталт libpq, відображає свіжу пам’ять під результати запитів libpq і скасовує це відображення, коли їх звільняють. На x86-64 це коштує скидань TLB (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 з апстриму, і 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.

Production 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 для розробки та production, конфігурація Compose і монтування томів
  • Налаштування — повний довідник змінних середовища