Миграция
Это руководство описывает перенос существующего PHP-приложения на OxPHP. Начните с раздела о том, на чём вы работаете сейчас, — nginx + PHP-FPM или FrankenPHP и RoadRunner, — и прочитайте раздел Что не переносится, прежде чем окончательно решиться на переезд.
С nginx + PHP-FPM
Большинство приложений переезжает без изменений в коде. Режим по умолчанию выполняет каждый запрос с чистого состояния PHP — это тот же жизненный цикл, что даёт PHP-FPM, — поэтому вся работа сводится к переводу конфигурации. Примеры развёртываний — это готовые рецепты для Laravel, Symfony, WordPress, Drupal, Magento и других.
1. Выберите режим маршрутизации, соответствующий вашему try_files
| nginx | OxPHP |
|---|---|
try_files $uri /index.php?$query_string (Laravel, Symfony, Yii) |
ENTRY_FILE=index.php (Framework) |
try_files $uri $uri/ /index.php с несколькими точками входа PHP (WordPress, OpenCart) |
ENTRY_FILE не задан (Traditional) |
try_files $uri /index.html для одностраничного приложения |
ENTRY_FILE=index.html (SPA) |
2. Соберите образ
Начните с Dockerfile из двух строк в разделе Быстрый старт. Расширения нужно собирать для потокобезопасного PHP — на этапе php:*-zts-alpine с той же минорной версией PHP, что и в образе OxPHP; см. Установка PHP-расширений в продакшене.
Убедитесь, что каждое используемое вами PECL-расширение поддерживает ZTS. OxPHP работает только с потокобезопасным PHP, поэтому расширение без поддержки ZTS загрузить не получится.
3. Переведите конфигурацию
Образ не загружает php.ini. Храните свои настройки PHP (memory_limit, upload_max_filesize, OPcache, …) в собственном файле в любом месте проекта, например docker/php.ini, и копируйте его в каталог конфигурации PHP внутри образа. Этот каталог — путь внутри контейнера, а не в вашем проекте:
FROM ghcr.io/oxphp/oxphp:0.13.0
COPY docker/php.ini /usr/local/etc/php/conf.d/zz-app.ini
COPY --chown=www-data:www-data . /var/www/html/publicPHP читает все файлы .ini в этом каталоге в алфавитном порядке, и действует последнее значение, поэтому префикс zz- гарантирует, что ваш файл применится после собственных файлов образа. Смонтировать файл как том тоже можно; см. Конфигурация PHP.
Остальное отображается на переменные окружения:
| nginx / PHP-FPM | OxPHP |
|---|---|
listen 443 ssl, ssl_certificate |
TLS_CERT, TLS_KEY, TLS_MIN_VERSION; см. TLS |
pm = static / pm = dynamic, pm.max_children |
PHP_WORKERS=N / PHP_WORKERS=MIN:MAX |
php_admin_value[...], php.ini |
собственный файл .ini, скопированный в образ в /usr/local/etc/php/conf.d/ (см. выше) |
gzip on, brotli on |
включено по умолчанию, настраивается через COMPRESSION_ENCODINGS; см. Сжатие |
expires 30d для статических файлов |
STATIC_MAX_AGE (по умолчанию 30d) |
limit_req |
RATE_LIMIT, RATE_WINDOW_SECONDS (фиксированное окно на IP); см. Ограничение частоты запросов |
set_real_ip_from, real_ip_header |
TRUSTED_PROXIES; см. Доверенные прокси |
error_page 404 /404.html |
ERROR_PAGES_DIR с файлами {status}.html; см. Страницы ошибок |
access_log |
ACCESS_LOG=all или error (JSON-строки); см. Логирование доступа |
location ~ ^/uploads/.*\.php$ { deny all; } |
PHP_DENY_PATHS=/uploads/**; см. Дени-лист выполнения PHP |
pm.status_path, ping.path |
INTERNAL_ADDR с /health и /metrics; см. Проверки работоспособности |
fastcgi_finish_request() |
oxphp_finish_request(); см. Ранний ответ |
4. Проверьте различия в поведении
max_execution_timeучитывает реальное время. В PHP-FPM время ожидания базы данных или HTTP-вызова не засчитывается, а в потокобезопасном PHP — засчитывается. Медленный эндпоинт, который раньше ни разу не упирался в лимит, может начать возвращать504. См. Таймауты.php_sapi_name()возвращаетcli-server. Коду, который ветвится поfpm-fcgi, нужна другая проверка:function_exists('oxphp_request_id').- Некоторые ключи
$_SERVERотличаются.SERVER_ADDR,PATH_TRANSLATEDиREDIRECT_STATUSне устанавливаются, аPHP_AUTH_USER/PHP_AUTH_PWне извлекаются; читайте вместо нихHTTP_AUTHORIZATION. См. Отличия от PHP-FPM. - Встраивание во фреймы по умолчанию ограничено. Ответы содержат
X-Frame-Options: SAMEORIGINи соответствующую политикуframe-ancestors. ЗадайтеFRAME_OPTIONS=off, если управляете встраиванием в другом месте или встраиваете приложение в страницы другого источника; см. Защита от кликджекинга.
5. Разворачивайте рядом со старым стеком
Запустите OxPHP рядом с nginx + PHP-FPM, направьте на него часть трафика через существующий балансировщик нагрузки, используйте /health/readiness для проб и сравните частоту ошибок и задержки по /metrics, прежде чем переводить остальное.
6. Включайте режим воркеров последним
Сначала выполните миграцию в режиме по умолчанию. Затем задайте WORKER_MODE_ENABLED=true и укажите в ENTRY_FILE скрипт воркера. Состояние в статических свойствах и долгоживущие соединения теперь сохраняются между запросами, поэтому перед включением прочитайте Что сбрасывается, а что сохраняется.
С FrankenPHP или RoadRunner
Скрипты воркеров сохраняют свою форму: инициализация один раз, затем обслуживание запросов. Замените цикл frankenphp_handle_request() одним вызовом oxphp_worker($handler). Цикл выполняет OxPHP и вызывает обработчик для каждого запроса; внутри обработчика читайте запрос из суперглобальных переменных или через oxphp_http_request(). У PSR-7-цикла RoadRunner waitRequest() / respond() аналога нет: перенесите обработчик приложения в тот же колбэк. См. oxphp_worker() и Режим воркеров.
Откажитесь от счётчика MAX_REQUESTS
Эквивалента нет, и он вам не нужен: воркер не предназначен для перезапуска каждые N запросов, а такой перезапуск лишь маскирует утечку. Если вы её подозреваете, отслеживайте её:
- Постройте график
oxphp_worker_memory_bytesпо каждому воркеру и следите за устойчивым ростом. - Задайте
WORKER_MAX_MEMORY_MIBкак страховку. Воркер, превысивший лимит, заменяется до того, как контейнеру перестанет хватать памяти, и каждый такой перезапуск учитывается вoxphp_worker_recycles_by_reason_total{reason="max_memory"}. - Этот лимит измеряет только собственную кучу PHP. В стеках с большим количеством расширений сравнивайте
Worker::current()->rss()со своим порогом и вызывайтеWorker::scheduleExit().
Что не переносится
- В OxPHP нет обратного прокси и поддержки upstream: нет
proxy_passи нет WebSocket-сервера. Если nginx обслуживает и другие сервисы, оставьте прокси перед OxPHP для этих маршрутов. - У экземпляра один порт и один протокол. Он обслуживает либо обычный HTTP, либо HTTPS, но не оба сразу, поэтому для редиректа с порта 80 на HTTPS нужен прокси или второй экземпляр. Сертификат читается при запуске, поэтому для его обновления нужен перезапуск; см. TLS.
- HTTP/3 и
103 Early Hintsпока недоступны; см. дорожную карту. - OxPHP работает только в Linux и распространяется как Docker-образ. Пакетов apt или brew нет. Поддерживаются PHP 8.4 и 8.5.
Промпты для вашего агента
Эти промпты рассчитаны на агента с подключённым MCP-сервером документации OxPHP — нужные страницы он прочитает сам.
Перенеси это приложение с nginx и PHP-FPM на OxPHP. Прочитай страницу `getting-started/migration` через MCP-сервер документации OxPHP.
Переведи серверные блоки nginx, настройки пулов PHP-FPM и переопределения php.ini из этого репозитория в Dockerfile для OxPHP и переменные окружения, выбери режим маршрутизации по правилам `try_files` и перечисли все различия в поведении и неподдерживаемые возможности, которые касаются этого кода, с указанием затронутого файла.Перенеси воркер FrankenPHP или RoadRunner из этого репозитория на OxPHP. Прочитай страницу `getting-started/migration` через MCP-сервер документации OxPHP.
Перепиши скрипт воркера вокруг единственного вызова `oxphp_worker()`, убери любой счётчик, который перезапускает воркер каждые N запросов, и скажи, какую метрику и какой лимит памяти настроить вместо него.Что дальше
- Маршрутизация — режимы маршрутизации Traditional, Framework, SPA и Worker в подробностях
- Руководство по Docker — Dockerfile для разработки и продакшена, настройка Compose, монтирование PHP ini
- Конфигурация — полный справочник по переменным окружения
- Режим воркеров — постоянные PHP-воркеры, которые инициализируются один раз и обрабатывают несколько запросов
- Примеры развёртываний — готовые рецепты для Laravel, Symfony, WordPress, Drupal, Magento и других