Migracja
Ten przewodnik przenosi istniejącą aplikację PHP na OxPHP. Zacznij od sekcji dla tego, czego używasz dziś — nginx + PHP-FPM albo FrankenPHP i RoadRunnera — a zanim zdecydujesz się na przejście, przeczytaj Czego nie da się przenieść.
Z nginx + PHP-FPM
Większość aplikacji przechodzi bez zmian w kodzie. Tryb domyślny wykonuje każde żądanie od czystego stanu PHP — to ten sam cykl życia, który daje PHP-FPM — więc praca sprowadza się do przeniesienia konfiguracji. Przykładowe wdrożenia to kompletne przepisy dla Laravela, Symfony, WordPressa, Drupala, Magento i innych.
1. Wybierz tryb routingu pasujący do Twojego 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 z kilkoma punktami wejścia PHP (WordPress, OpenCart) |
ENTRY_FILE nieustawione (Tradycyjny) |
try_files $uri /index.html dla aplikacji jednostronicowej |
ENTRY_FILE=index.html (SPA) |
2. Zbuduj obraz
Zacznij od dwuwierszowego pliku Dockerfile z Szybkiego startu. Rozszerzenia muszą być zbudowane dla wielowątkowego (thread-safe) PHP, w etapie php:*-zts-alpine z tą samą wersją minor PHP co obraz OxPHP; zobacz Instalowanie rozszerzeń PHP na produkcji.
Sprawdź, czy każde używane przez Ciebie rozszerzenie PECL obsługuje ZTS. OxPHP uruchamia wyłącznie wielowątkowe PHP, więc rozszerzenia bez obsługi ZTS nie da się załadować.
3. Przenieś konfigurację
Obraz nie ładuje żadnego php.ini. Trzymaj swoje ustawienia PHP (memory_limit, upload_max_filesize, OPcache, …) we własnym pliku w dowolnym miejscu projektu, na przykład docker/php.ini, i skopiuj go do katalogu konfiguracji PHP w obrazie. Ten katalog to ścieżka wewnątrz kontenera, a nie w Twoim projekcie:
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 odczytuje każdy plik .ini z tego katalogu w kolejności alfabetycznej, a wygrywa ostatnia wartość, więc prefiks zz- sprawia, że Twój plik zostanie zastosowany po własnych plikach obrazu. Zamontowanie pliku jako wolumenu też działa; zobacz Konfiguracja PHP.
Reszta mapuje się na zmienne środowiskowe:
| nginx / PHP-FPM | OxPHP |
|---|---|
listen 443 ssl, ssl_certificate |
TLS_CERT, TLS_KEY, TLS_MIN_VERSION; zobacz TLS |
pm = static / pm = dynamic, pm.max_children |
PHP_WORKERS=N / PHP_WORKERS=MIN:MAX |
php_admin_value[...], php.ini |
własny plik .ini skopiowany do /usr/local/etc/php/conf.d/ w obrazie (zobacz wyżej) |
gzip on, brotli on |
włączone domyślnie, konfigurowane przez COMPRESSION_ENCODINGS; zobacz Kompresja |
expires 30d dla plików statycznych |
STATIC_MAX_AGE (domyślnie 30d) |
limit_req |
RATE_LIMIT, RATE_WINDOW_SECONDS (stałe okno na adres IP); zobacz Ograniczanie liczby żądań |
set_real_ip_from, real_ip_header |
TRUSTED_PROXIES; zobacz Zaufane proxy |
error_page 404 /404.html |
ERROR_PAGES_DIR z plikami {status}.html; zobacz Niestandardowe strony błędów |
access_log |
ACCESS_LOG=all lub error (linie JSON); zobacz Rejestrowanie dostępu |
location ~ ^/uploads/.*\.php$ { deny all; } |
PHP_DENY_PATHS=/uploads/**; zobacz Lista blokowania wykonywania PHP |
pm.status_path, ping.path |
INTERNAL_ADDR z /health i /metrics; zobacz Kontrole stanu |
fastcgi_finish_request() |
oxphp_finish_request(); zobacz Wczesna odpowiedź |
4. Sprawdź różnice w zachowaniu
max_execution_timeliczy czas zegarowy. Pod PHP-FPM czas oczekiwania na bazę danych lub wywołanie HTTP nie jest wliczany; w wielowątkowym PHP jest. Powolny endpoint, który wcześniej nigdy nie dobił do limitu, może zacząć zwracać504. Zobacz Limity czasu.php_sapi_name()zwracacli-server. Kod, który rozgałęzia się na podstawiefpm-fcgi, potrzebuje innego sprawdzenia:function_exists('oxphp_request_id').- Kilka kluczy
$_SERVERsię różni.SERVER_ADDR,PATH_TRANSLATEDiREDIRECT_STATUSnie są ustawiane, aPHP_AUTH_USER/PHP_AUTH_PWnie są wyodrębniane; zamiast nich odczytujHTTP_AUTHORIZATION. Zobacz Różnice względem PHP-FPM. - Osadzanie w ramkach jest domyślnie ograniczone. Odpowiedzi niosą
X-Frame-Options: SAMEORIGINi dopasowaną politykęframe-ancestors. UstawFRAME_OPTIONS=off, jeśli zarządzasz osadzaniem gdzie indziej lub osadzasz aplikację w innym pochodzeniu; zobacz Ochrona przed clickjackingiem.
5. Wdrażaj obok starego stosu
Uruchom OxPHP obok nginx + PHP-FPM, skieruj na niego część ruchu przez istniejący load balancer, używaj /health/readiness do sond i porównaj odsetek błędów oraz opóźnienia w /metrics, zanim przeniesiesz resztę.
6. Tryb worker włącz na końcu
Najpierw przeprowadź migrację w trybie domyślnym. Potem ustaw WORKER_MODE_ENABLED=true, a ENTRY_FILE skieruj na skrypt workera. Stan przechowywany we właściwościach statycznych i długo żyjące połączenia przetrwają teraz między żądaniami, więc przed włączeniem tego trybu przeczytaj Co jest resetowane, a co zachowywane.
Z FrankenPHP lub RoadRunnera
Skrypty workerów zachowują swój kształt: jednorazowa inicjalizacja, a potem obsługa żądań. Zastąp pętlę frankenphp_handle_request() pojedynczym wywołaniem oxphp_worker($handler). OxPHP sam prowadzi pętlę i wywołuje handler dla każdego żądania; wewnątrz niego odczytuj żądanie z superglobalnych lub z oxphp_http_request(). Pętla PSR-7 waitRequest() / respond() z RoadRunnera nie ma odpowiednika: przenieś handler aplikacji do tego samego callbacku. Zobacz oxphp_worker() i Tryb worker.
Porzuć licznik MAX_REQUESTS
Nie ma odpowiednika i nie jest Ci potrzebny: worker nie powinien być restartowany co N żądań, a takie restarty jedynie ukrywają wyciek. Jeśli podejrzewasz wyciek, śledź go:
- Rysuj wykres
oxphp_worker_memory_bytesdla każdego workera i obserwuj, czy wartość stale rośnie. - Ustaw
WORKER_MAX_MEMORY_MIBjako zabezpieczenie. Worker, który przekroczy limit, jest wymieniany, zanim w kontenerze skończy się pamięć, a każdy taki recykling jest liczony woxphp_worker_recycles_by_reason_total{reason="max_memory"}. - Ten limit mierzy tylko własną stertę PHP. Przy stosach intensywnie korzystających z rozszerzeń porównuj
Worker::current()->rss()z własnym progiem i wywołujWorker::scheduleExit().
Czego nie da się przenieść
- OxPHP nie obsługuje odwrotnego proxy ani upstreamów: nie ma
proxy_passani serwera WebSocket. Jeśli nginx obsługuje też inne usługi, zostaw dla tych tras proxy przed OxPHP. - Instancja ma jeden port i jeden protokół. Obsługuje zwykły HTTP albo HTTPS, nie oba naraz, więc przekierowanie z portu 80 na HTTPS wymaga proxy lub drugiej instancji. Certyfikat jest wczytywany przy starcie, więc jego odnowienie wymaga restartu; zobacz TLS.
- HTTP/3 i
103 Early Hintsnie są jeszcze dostępne; zobacz plan rozwoju. - OxPHP działa wyłącznie na Linuksie i jest dystrybuowany jako obraz Docker. Nie ma pakietów apt ani brew. Obsługiwane są PHP 8.4 i 8.5.
Prompty dla Twojego agenta
Te prompty zakładają agenta z podłączonym serwerem MCP dokumentacji OxPHP — sam przeczyta strony, których potrzebuje.
Przenieś tę aplikację z nginx i PHP-FPM na OxPHP. Przeczytaj stronę `getting-started/migration` przez serwer MCP dokumentacji OxPHP.
Przełóż bloki server nginx, ustawienia puli PHP-FPM i nadpisania php.ini z tego repozytorium na plik Dockerfile i zmienne środowiskowe OxPHP, wybierz tryb routingu na podstawie reguł `try_files` i wypisz każdą różnicę w zachowaniu oraz każdą nieobsługiwaną funkcję, która dotyczy tego kodu, razem z plikiem, na który wpływa.Przenieś workera FrankenPHP lub RoadRunnera z tego repozytorium na OxPHP. Przeczytaj stronę `getting-started/migration` przez serwer MCP dokumentacji OxPHP.
Przepisz skrypt workera wokół pojedynczego wywołania `oxphp_worker()`, usuń każdy licznik, który restartuje workera co N żądań, i powiedz mi, jaką metrykę i jaki limit pamięci ustawić w jego miejsce.Co dalej
- Routing — tryby routingu Tradycyjny, Framework, SPA i Worker w szczegółach
- Przewodnik po Dockerze — deweloperskie i produkcyjne pliki Dockerfile, konfiguracja Compose, montowanie plików ini PHP
- Konfiguracja — pełna dokumentacja zmiennych środowiskowych
- Tryb worker — trwałe workery PHP, które inicjalizują się raz i obsługują wiele żądań
- Przykładowe wdrożenia — kompletne przepisy dla Laravela, Symfony, WordPressa, Drupala, Magento i innych