Installation

OxPHP est distribué sous forme d'image Docker, la manière la plus rapide et recommandée pour commencer à servir des applications PHP. L'image regroupe le binaire du serveur, PHP 8.4 ou 8.5 ZTS, l'extension OxPHP et toutes les dépendances d'exécution sur Alpine Linux. Les tags par défaut :0.13.0 et :latest embarquent PHP 8.5 ; récupérez PHP 8.4 avec les tags :0.13.0-php8.4, :php8.4 ou n'importe quelle variante de tag *-php8.4*.

Docker (recommandé)

Récupérez l'image officielle depuis le GitHub Container Registry :

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

L'image inclut :

  • Binaire du serveur OxPHP — le serveur HTTP asynchrone
  • Runtime PHP ZTS — 8.4 ou 8.5, selon le tag récupéré ; PHP thread-safe pour l'exécution multi-worker
  • Extension PHP OxPHP (oxphp_sapi.so) — fournit oxphp_request_id(), oxphp_server_info(), oxphp_worker() et d'autres fonctions intégrées
  • Bibliothèque passerelle (liboxphp_bridge.so) — connecte le serveur Rust au runtime PHP
  • Base Alpine Linux — empreinte d'exécution minimale (une version Debian est publiée chaque nuit, voir Image Debian (glibc))
  • Aucune directive USER — l'image démarre en tant que root (comme nginx:alpine / php-fpm:alpine / frankenphp:alpine) afin de pouvoir se lier aux ports privilégiés, mais oxphp serve/run abandonne ensuite ces privilèges pour www-data par défaut avant de servir, de sorte que le trafic n'est pas traité en tant que root d'entrée de jeu. L'utilisateur www-data (UID 82, GID 82 ; 33 dans l'image Debian) est pré-créé et /var/www/html lui est attribué (chown) au moment de la construction. Fixez explicitement l'identité d'exécution au niveau de l'orchestrateur pour un uid spécifique ou une défense en profondeur supplémentaire :
    • docker run --user www-data ghcr.io/oxphp/oxphp:0.13.0
    • Compose : services.app.user: www-data
    • Kubernetes : securityContext.runAsUser: 82

Image Debian (glibc)

Le pipeline nocturne publie aussi le même serveur construit sur Debian trixie au lieu d'Alpine : ghcr.io/oxphp/oxphp:nightly-trixie (PHP 8.4), :php8.4-nightly-trixie et :php8.5-nightly-trixie, pour linux/amd64 et linux/arm64.

Nightly uniquement

Les versions taguées sont exclusivement Alpine. Les tags nightly sont construits depuis main les nuits où la branche a évolué depuis la dernière exécution entièrement réussie, et n'offrent aucune garantie de stabilité. Une nuit où la construction Debian échoue laisse :nightly-trixie et :php<minor>-nightly-trixie sur la dernière construction réussie, si bien qu'ils peuvent être en retard sur :nightly.

L'image Debian consomme moins de CPU par requête, pour deux raisons :

  • Stockage local au thread. PHP thread-safe accède à l'état propre à chaque thread du moteur via un pointeur local au thread. Compilé avec musl, PHP laisse ce pointeur sur le modèle TLS global-dynamic, si bien que le code de libphp.so l'atteint par un appel au runtime TLS ; avec glibc, il utilise initial-exec, un simple chargement relatif au pointeur de thread.
  • Allocateur. L'allocateur de musl, qu'utilisent les extensions et les bibliothèques comme libpq à côté du gestionnaire de mémoire propre à PHP, mappe de la mémoire neuve pour les résultats de requêtes de libpq et la démappe lorsqu'ils sont libérés. Sur x86-64, cela coûte des invalidations de TLB (TLB shootdowns) sur l'ensemble des threads du serveur.

Temps CPU du conteneur OxPHP par réponse, image Debian contre image Alpine, avec la même révision d'OxPHP et le même correctif de PHP 8.5 : une application Yii3 sous wrk -c64, médiane de six exécutions alternées. Chaque ligne a été mesurée sur un seul hôte : x86-64 sur une VM cloud à 16 vCPU (AMD EPYC 9575F), arm64 sous Docker Desktop sur Apple silicon. Le CPU consommé par Postgres lui-même n'est pas inclus.

Page Yii3 Page lisant Postgres
x86-64, mode classique −18,9 % −14,1 %
x86-64, mode worker −18,1 % −18,6 %
arm64, mode classique −8,5 % −9,0 %

Ce qui change pour un Dockerfile construit sur cette image :

  • Les paquets s'installent avec apt-get update && apt-get install -y --no-install-recommends, et non apk, et sous leurs noms Debian : par exemple libicu-dev et libpq-dev pour compiler intl et pdo_pgsql, libicu76 et libpq5 à l'exécution.
  • Compilez les extensions dans une étape php:<minor>-zts-trixie. Un .so compilé avec musl dans une étape -zts-alpine n'est pas compatible avec cette image, ni l'inverse.
  • www-data a l'UID/GID 33, et non 82 : securityContext.runAsUser: 33, et tout ce qui est attribué (chown) par numéro doit utiliser 33.
  • Il n'y a pas de wget, mais curl est présent. Un contrôle de santé écrit pour l'image Alpine sous la forme wget --spider http://localhost:9090/health devient curl -fsS -o /dev/null http://localhost:9090/health.
  • L'image est plus volumineuse : la base PHP pèse environ 170 à 180 Mio compressée, contre environ 45 à 50 Mio pour Alpine.

Structure de l'image

Organisation des fichiers de l'image d'exécution :

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

La valeur <ABI> dépend de la version mineure de PHP. PHP 8.4 utilise 20240924, PHP 8.5 utilise 20250925. Les exemples ci-dessous fixent 20250925 parce que leur ligne FROM cible php:8.5-zts-alpine3.23, le PHP du tag par défaut :0.13.0 — changez le FROM et vous devez aussi changer la date. Pour la dériver de façon portable au sein de la construction :

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

Utilisez $(php -r 'echo ini_get("extension_dir");') dans les commandes shell pour éviter de coder la valeur en dur.

L'image n'embarque aucun php.ini propre (à côté de conf.d/, /usr/local/etc/php/ ne contient que les modèles php.ini-development et php.ini-production fournis en amont, et PHP ne charge ni l'un ni l'autre), ni aucun réglage applicatif. Fournissez les vôtres sous forme de fichier .ini dans conf.d, monté ou copié dans l'image ; consultez le Guide Docker.

Note

Le nom du fichier détermine si un .ini est lu, et à quel moment. PHP analyse chaque fichier .ini de conf.d par ordre alphabétique et ignore silencieusement tout autre nom. Pour un réglage ordinaire, c'est la dernière valeur lue qui l'emporte : un fichier qui en redéfinit un doit donc être trié après celui qui le définit. Les directives extension= et zend_extension=, elles, sont collectées dans tous les fichiers et toutes chargées, si bien qu'un extension= ultérieur ne remplace jamais un précédent.

Les trois composants d'OxPHP et leur rôle, avec des tailles mesurées dans l'image 0.11.0. Les tailles diffèrent entre linux/amd64 et linux/arm64 et évoluent d'une version à l'autre :

Composant Taille Rôle
oxphp ~12 à 15 MB Serveur HTTP, routage, plugins, métriques
liboxphp_bridge.so ~150 à 170 KB Bibliothèque passerelle partagée qui relie le serveur au runtime PHP
oxphp_sapi.so ~700 KB Fonctions PHP (oxphp_request_id(), OxPHP\Http\Request, etc.)

Chaîne de dépendances :

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

Le binaire oxphp est lié à libphp.so et liboxphp_bridge.so. L'extension PHP oxphp_sapi.so est elle aussi liée à la bibliothèque passerelle afin que l'état propre à chaque requête soit accessible depuis votre code PHP.

Dockerfile minimal

L'image de base php:8.5-zts-alpine3.23 (ou php:8.4-zts-alpine3.23) contient déjà libphp.so et toutes ses dépendances. Faites correspondre la version mineure de PHP dans votre FROM au tag OxPHP depuis lequel vous copiez, ainsi que la bibliothèque C : les artefacts d'un tag -trixie vont sur php:<minor>-zts-trixie, et non sur une base Alpine. Il vous suffit de copier les trois artefacts OxPHP et d'ajouter libgcc, auquel le binaire oxphp compilé en Rust est lié et que l'image PHP Alpine ne fournit pas :

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

Cette approche est pratique pour le développement : PHP CLI, docker-php-ext-install et pecl sont tous disponibles. Composer et Xdebug ne font pas partie de l'image de base PHP. Ajoutez-les vous-même avec COPY --from=composer:2 /usr/bin/composer /usr/local/bin/composer et pecl install xdebug, comme le fait la cible dev du Guide Docker.

Dockerfile de production

L'image officielle OxPHP conserve le PHP CLI et les outils d'extensions (php, phpize, pecl, docker-php-ext-install) de l'image php:<minor>-zts-alpine3.23 sur laquelle elle est construite : vous pouvez donc y installer des extensions directement ; voir Installer des extensions PHP en production. Les compiler plutôt dans une étape distincte permet de garder hors de l'image finale les paquets nécessaires uniquement à la compilation, comme icu-dev. Le besoin ou non d'extensions PHP supplémentaires détermine laquelle de ces deux constructions choisir.

Si votre application a besoin d'extensions supplémentaires (pdo_mysql, intl, etc.), compilez-les dans une étape distincte et copiez-les dans l'image finale :

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

Construire et exécuter :

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

Le serveur écoute sur le port 80 par défaut. La racine du document est /var/www/html/public, et les extraits ci-dessus y copient le projet directement. Pour Laravel, Symfony ou d'autres frameworks qui embarquent déjà un sous-répertoire public/, utilisez plutôt COPY --chown=www-data:www-data . /var/www/html afin que le public/ propre au framework s'aligne sur la valeur par défaut. Si votre structure diffère davantage, remplacez la racine du document par la variable d'environnement DOCUMENT_ROOT.

Compilation depuis les sources (sans PHP)

Compilez OxPHP depuis les sources avec la fonctionnalité PHP désactivée pour servir uniquement des fichiers statiques :

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

Le binaire se trouve dans target/release/oxphp. Il utilise un exécuteur factice qui renvoie une réponse générique pour les requêtes PHP tout en servant normalement les fichiers statiques. Ce mode est utile pour tester le serveur sans qu'un runtime PHP soit présent.

Compilation depuis les sources (avec PHP)

Compiler OxPHP avec la prise en charge complète de PHP requiert que la bibliothèque passerelle et l'extension PHP soient d'abord compilées et installées.

Prérequis

  • Chaîne d'outils Rust (1.91.1 ou ultérieure)
  • PHP 8.4 ou 8.5 avec ZTS (Zend Thread Safety) activé
  • Compilateur C (gcc ou clang)
  • phpize et les en-têtes de développement de PHP

Étapes de compilation

  1. Compilez et installez la bibliothèque passerelle.

    bash
    cd ext/bridge make && sudo make install
  2. Compilez et installez l'extension PHP.

    bash
    cd ../ phpize && ./configure --enable-oxphp-sapi && make && sudo make install
  3. Compilez OxPHP. Les fonctionnalités par défaut incluent php.

    bash
    cargo build --release

Le binaire a besoin des bibliothèques partagées dans le chemin de recherche des bibliothèques à l'exécution :

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

Lors d'un déploiement sur Alpine Linux, compilez à l'intérieur de la même image php:{8.4,8.5}-zts-alpine que celle utilisée pour le runtime PHP — faites correspondre la version mineure de l'image OxPHP que vous livrez. Mélanger des constructions glibc et musl provoque des erreurs à l'exécution. L'image Docker officielle gère cela correctement.

Vérification de l'installation

Après le démarrage d'OxPHP, une sortie de log JSON structurée confirme que le serveur fonctionne :

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

Testez que le serveur répond :

bash
curl http://localhost/

Si vous avez activé le serveur interne avec INTERNAL_ADDR, vérifiez l'endpoint de contrôle de santé :

bash
curl http://localhost:9090/health

Un serveur en bonne santé renvoie 200 avec un statut JSON. Un serveur dégradé renvoie 503.

Et ensuite

  • Démarrage rapide — créez un projet, exécutez OxPHP avec Docker Compose et effectuez votre première requête
  • Guide Docker — Dockerfiles pour le développement et la production, configuration de Compose et montages de volumes
  • Configuration — référence complète des variables d'environnement
Une erreur ? Signalez-la →