Instalacja

OxPHP jest dystrybuowany jako obraz Docker — to najszybszy i zalecany sposób, aby zacząć obsługiwać aplikacje PHP. Obraz zawiera binarkę serwera, PHP 8.4 lub 8.5 ZTS, rozszerzenie OxPHP oraz wszystkie zależności czasu wykonania na Alpine Linux. Domyślne tagi :0.13.0 i :latest dostarczają PHP 8.5; PHP 8.4 pobierzesz tagiem :0.13.0-php8.4, :php8.4 lub dowolnym wariantem *-php8.4*.

Docker (zalecane)

Pobierz oficjalny obraz z GitHub Container Registry:

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

Obraz zawiera:

  • Binarkę serwera OxPHP — asynchroniczny serwer HTTP
  • Środowisko uruchomieniowe PHP ZTS — 8.4 lub 8.5, w zależności od pobranego tagu; wielowątkowo bezpieczne PHP do wykonywania w wielu workerach
  • Rozszerzenie PHP OxPHP (oxphp_sapi.so) — udostępnia oxphp_request_id(), oxphp_server_info(), oxphp_worker() oraz inne wbudowane funkcje
  • Bibliotekę pomostową (liboxphp_bridge.so) — łączy serwer napisany w Rust ze środowiskiem uruchomieniowym PHP
  • Bazę Alpine Linux — minimalny narzut czasu wykonania (kompilacja na Debianie jest publikowana co noc, zobacz Obraz Debian (glibc))
  • Brak dyrektywy USER — obraz startuje jako root (tak samo jak nginx:alpine / php-fpm:alpine / frankenphp:alpine), aby móc bindować uprzywilejowane porty, ale oxphp serve/run następnie zrzuca uprawnienia do www-data domyślnie przed rozpoczęciem obsługi, więc ruch nie jest domyślnie obsługiwany jako root. Użytkownik www-data (UID 82, GID 82; 33 w obrazie Debian) jest wstępnie utworzony, a katalog /var/www/html jest przypisywany do niego (chown) na etapie budowania. Ustaw tożsamość czasu wykonania jawnie na poziomie orkiestratora dla konkretnego uid lub dla dodatkowej obrony w głąb:
    • docker run --user www-data ghcr.io/oxphp/oxphp:0.13.0
    • Compose: services.app.user: www-data
    • Kubernetes: securityContext.runAsUser: 82

Obraz Debian (glibc)

Nocny pipeline publikuje także ten sam serwer zbudowany na Debianie trixie zamiast na Alpine: ghcr.io/oxphp/oxphp:nightly-trixie (PHP 8.4), :php8.4-nightly-trixie i :php8.5-nightly-trixie, dla linux/amd64 i linux/arm64.

Tylko wydania nocne

Otagowane wydania są wyłącznie na Alpine. Tagi nocne są budowane z main w te noce, w które gałąź zmieniła się od ostatniego w pełni udanego przebiegu, i nie dają żadnej gwarancji stabilności. Noc, w której budowanie na Debianie się nie powiedzie, pozostawia :nightly-trixie i :php<minor>-nightly-trixie na ostatniej udanej kompilacji, więc mogą one pozostawać w tyle za :nightly.

Obraz Debian zużywa mniej CPU na żądanie, z dwóch powodów:

  • Pamięć lokalna wątku (TLS). Wielowątkowo bezpieczne PHP sięga do stanu silnika przypisanego do wątku przez wskaźnik lokalny dla wątku. Przy budowaniu z musl PHP pozostawia ten wskaźnik w modelu TLS global-dynamic, więc kod w libphp.so sięga do niego przez wywołanie środowiska uruchomieniowego TLS; z glibc używa modelu initial-exec, czyli odczytu względem wskaźnika wątku.
  • Alokator. Alokator musl, z którego obok własnego menedżera pamięci PHP korzystają rozszerzenia i biblioteki takie jak libpq, mapuje świeżą pamięć na wyniki zapytań libpq i zwalnia jej mapowanie, gdy wyniki są zwalniane. Na x86-64 kosztuje to TLB shootdowns we wszystkich wątkach serwera.

Czas CPU kontenera OxPHP na odpowiedź, obraz Debian względem obrazu Alpine, przy tej samej rewizji OxPHP i tej samej wersji poprawkowej PHP 8.5: aplikacja Yii3 pod wrk -c64, mediana z sześciu naprzemiennych przebiegów. Każdy wiersz zmierzono na jednym hoście: x86-64 na maszynie wirtualnej w chmurze z 16 vCPU (AMD EPYC 9575F), arm64 w Docker Desktop na Apple silicon. Własne zużycie CPU przez Postgresa nie jest wliczone.

Strona Yii3 Strona odczytująca z Postgresa
x86-64, tryb klasyczny −18,9% −14,1%
x86-64, tryb worker −18,1% −18,6%
arm64, tryb klasyczny −8,5% −9,0%

Co zmienia się w Dockerfile zbudowanym na tym obrazie:

  • Pakiety pochodzą z apt-get update && apt-get install -y --no-install-recommends, a nie z apk, i mają nazwy debianowe: na przykład libicu-dev i libpq-dev do zbudowania intl i pdo_pgsql, a libicu76 i libpq5 w czasie wykonania.
  • Buduj rozszerzenia w etapie php:<minor>-zts-trixie. Plik .so zbudowany z musl w etapie -zts-alpine nie jest zgodny z tym obrazem i na odwrót.
  • www-data ma UID/GID 33, a nie 82: securityContext.runAsUser: 33, a wszystko, co jest przypisywane (chown) po numerze, musi używać 33.
  • Nie ma wget, ale jest curl. Kontrola stanu napisana dla obrazu Alpine jako wget --spider http://localhost:9090/health zmienia się w curl -fsS -o /dev/null http://localhost:9090/health.
  • Obraz jest większy: bazowy obraz PHP ma po kompresji około 170–180 MiB, wobec około 45–50 MiB dla Alpine.

Struktura obrazu

Układ plików w obrazie czasu wykonania:

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

Wartość <ABI> zależy od wersji minor PHP. PHP 8.4 używa 20240924, PHP 8.5 używa 20250925. Poniższe przykłady przypinają 20250925, ponieważ ich linia FROM celuje w php:8.5-zts-alpine3.23, czyli PHP domyślnego tagu :0.13.0 — jeśli zmienisz FROM, musisz zmienić także datę. Aby wyliczyć ją przenośnie wewnątrz budowania:

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

Użyj $(php -r 'echo ini_get("extension_dir");') w poleceniach powłoki, aby uniknąć wpisywania wartości na sztywno.

Obraz nie zawiera własnego php.ini (obok conf.d/ katalog /usr/local/etc/php/ zawiera jedynie przykładowe pliki php.ini-development i php.ini-production z obrazu bazowego, a PHP nie wczytuje żadnego z nich) ani żadnych ustawień aplikacji. Swoje ustawienia dostarcz jako plik .ini w conf.d, zamontowany lub skopiowany do obrazu; zobacz Przewodnik po Dockerze.

Note

To nazwa pliku decyduje, czy i kiedy plik .ini zostanie wczytany. PHP parsuje każdy plik .ini w conf.d w kolejności alfabetycznej i po cichu pomija pliki o innych nazwach. W przypadku zwykłego ustawienia wygrywa ostatnia wczytana wartość, więc plik, który ją nadpisuje, musi być posortowany za plikiem, który ją ustawia. Dyrektywy extension= i zend_extension= są natomiast zbierane ze wszystkich plików i wszystkie ładowane, więc późniejsze extension= nigdy nie zastępuje wcześniejszego.

Trzy komponenty OxPHP i ich przeznaczenie, z rozmiarami zmierzonymi w obrazie 0.11.0. Rozmiary różnią się między linux/amd64 a linux/arm64 i zmieniają się z wydania na wydanie:

Komponent Rozmiar Przeznaczenie
oxphp ~12 do 15 MB Serwer HTTP, routing, wtyczki, metryki
liboxphp_bridge.so ~150 do 170 KB Współdzielona biblioteka pomostowa łącząca serwer ze środowiskiem uruchomieniowym PHP
oxphp_sapi.so ~700 KB Funkcje PHP (oxphp_request_id(), OxPHP\Http\Request itp.)

Łańcuch zależności:

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

Binarka oxphp linkuje się z libphp.so i liboxphp_bridge.so. Rozszerzenie PHP oxphp_sapi.so również linkuje się z biblioteką pomostową, aby stan per-żądanie był dostępny dla Twojego kodu PHP.

Minimalny Dockerfile

Bazowy obraz php:8.5-zts-alpine3.23 (lub php:8.4-zts-alpine3.23) zawiera już libphp.so i wszystkie jego zależności. Dopasuj wersję minor PHP w FROM do tagu OxPHP, z którego kopiujesz, a także bibliotekę C: artefakty z tagu -trixie trafiają na php:<minor>-zts-trixie, a nie na bazę Alpine. Wystarczy skopiować trzy artefakty OxPHP i dodać libgcc, z którą linkuje się zbudowana w Rust binarka oxphp, a której obraz PHP na Alpine nie zawiera:

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"]

To podejście jest wygodne przy programowaniu: PHP CLI, docker-php-ext-install i pecl są wszystkie dostępne. Composer i Xdebug nie wchodzą w skład bazowego obrazu PHP. Dodaj je samodzielnie przez COPY --from=composer:2 /usr/bin/composer /usr/local/bin/composer i pecl install xdebug, tak jak robi to cel dev w Przewodniku po Dockerze.

Produkcyjny Dockerfile

Oficjalny obraz OxPHP zachowuje PHP CLI i narzędzia do rozszerzeń (php, phpize, pecl, docker-php-ext-install) z obrazu php:<minor>-zts-alpine3.23, na którym jest zbudowany, więc możesz instalować w nim rozszerzenia bezpośrednio; zobacz Instalowanie rozszerzeń PHP na produkcji. Budowanie ich w osobnym etapie pozwala natomiast trzymać pakiety potrzebne tylko do budowania, takie jak icu-dev, poza końcowym obrazem. To, czy potrzebujesz dodatkowych rozszerzeń PHP, decyduje, po który z tych dwóch wariantów budowania sięgniesz.

Jeśli Twoja aplikacja potrzebuje dodatkowych rozszerzeń (pdo_mysql, intl itp.), zbuduj je w osobnym etapie i skopiuj do końcowego obrazu:

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

Zbuduj i uruchom:

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

Serwer domyślnie nasłuchuje na porcie 80. Katalog główny dokumentów to /var/www/html/public, a powyższe fragmenty kopiują projekt bezpośrednio do niego. Dla Laravela, Symfony lub innych frameworków, które już dostarczają podkatalog public/, użyj COPY --chown=www-data:www-data . /var/www/html, aby własny katalog public/ frameworka pokrył się z domyślnym. Jeśli Twoja struktura różni się jeszcze bardziej, nadpisz katalog główny dokumentów zmienną środowiskową DOCUMENT_ROOT.

Budowanie ze źródeł (bez PHP)

Zbuduj OxPHP ze źródeł z wyłączoną funkcją PHP, aby obsługiwać wyłącznie pliki statyczne:

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

Binarka znajduje się w target/release/oxphp. Używa zaślepki executora, która zwraca odpowiedź zastępczą dla żądań PHP, obsługując przy tym normalnie pliki statyczne. Ten tryb przydaje się do testowania serwera bez obecnego środowiska uruchomieniowego PHP.

Budowanie ze źródeł (z PHP)

Zbudowanie OxPHP z pełną obsługą PHP wymaga wcześniejszego skompilowania i zainstalowania biblioteki pomostowej oraz rozszerzenia PHP.

Wymagania wstępne

  • Toolchain Rust (1.91.1 lub nowszy)
  • PHP 8.4 lub 8.5 z włączonym ZTS (Zend Thread Safety)
  • Kompilator C (gcc lub clang)
  • phpize i nagłówki deweloperskie PHP

Kroki budowania

  1. Zbuduj i zainstaluj bibliotekę pomostową.

    bash
    cd ext/bridge make && sudo make install
  2. Zbuduj i zainstaluj rozszerzenie PHP.

    bash
    cd ../ phpize && ./configure --enable-oxphp-sapi && make && sudo make install
  3. Zbuduj OxPHP. Domyślne funkcje obejmują php.

    bash
    cargo build --release

Binarka wymaga bibliotek współdzielonych w ścieżce wyszukiwania bibliotek w czasie wykonania:

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

Przy wdrażaniu na Alpine Linux buduj wewnątrz tego samego obrazu php:{8.4,8.5}-zts-alpine, którego używasz jako środowiska uruchomieniowego PHP — dopasuj wersję minor do obrazu OxPHP, który dostarczasz. Mieszanie buildów glibc i musl powoduje błędy czasu wykonania. Oficjalny obraz Docker obsługuje to poprawnie.

Weryfikacja instalacji

Po uruchomieniu OxPHP ustrukturyzowany wynik logów w formacie JSON potwierdza, że serwer działa:

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"}

Sprawdź, czy serwer odpowiada:

bash
curl http://localhost/

Jeśli włączyłeś serwer wewnętrzny za pomocą INTERNAL_ADDR, zweryfikuj endpoint kontroli stanu:

bash
curl http://localhost:9090/health

Sprawny serwer zwraca 200 ze statusem w formacie JSON. Serwer w stanie degradacji zwraca 503.

Co dalej

  • Szybki start — utwórz projekt, uruchom OxPHP z Docker Compose i wykonaj pierwsze żądanie
  • Przewodnik po Dockerze — pliki Dockerfile do programowania i produkcji, konfiguracja Compose oraz montowanie wolumenów
  • Konfiguracja — pełne odniesienie do zmiennych środowiskowych
Znalazłeś błąd? Zgłoś go →