Migration
Ce guide fait passer une application PHP existante sur OxPHP. Commencez par la section qui correspond à ce que vous exécutez aujourd'hui, nginx + PHP-FPM ou bien FrankenPHP et RoadRunner, et lisez Ce qui ne se transpose pas avant de vous engager dans la migration.
Depuis nginx + PHP-FPM
La plupart des applications migrent sans modification de code. Le mode par défaut exécute chaque requête à partir d'un état PHP vierge, le même cycle de vie que celui de PHP-FPM, si bien que le travail consiste à traduire la configuration. Les exemples de déploiement sont des recettes complètes pour Laravel, Symfony, WordPress, Drupal, Magento et d'autres.
1. Choisissez le mode de routage qui correspond à votre 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 avec plusieurs points d'entrée PHP (WordPress, OpenCart) |
ENTRY_FILE non défini (Traditional) |
try_files $uri /index.html pour une application monopage |
ENTRY_FILE=index.html (SPA) |
2. Construisez l'image
Partez du Dockerfile de deux lignes du Démarrage rapide. Les extensions doivent être compilées pour PHP thread-safe, dans une étape php:*-zts-alpine avec la même version mineure de PHP que l'image OxPHP ; voir Installer des extensions PHP en production.
Vérifiez que chaque extension PECL que vous utilisez prend en charge ZTS. OxPHP n'exécute que du PHP thread-safe, si bien qu'une extension sans prise en charge de ZTS ne peut pas être chargée.
3. Traduisez la configuration
L'image ne charge aucun php.ini. Conservez vos réglages PHP (memory_limit, upload_max_filesize, OPcache, …) dans un fichier à vous, placé n'importe où dans le projet, par exemple docker/php.ini, et copiez-le dans le répertoire de configuration PHP de l'image. Ce répertoire est un chemin à l'intérieur du conteneur, pas dans votre projet :
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 lit chaque fichier .ini de ce répertoire dans l'ordre alphabétique et la dernière valeur l'emporte : le préfixe zz- fait donc s'appliquer le vôtre après les fichiers propres à l'image. Monter le fichier en tant que volume fonctionne aussi ; voir Configuration PHP.
Le reste se traduit en variables d'environnement :
| nginx / PHP-FPM | OxPHP |
|---|---|
listen 443 ssl, ssl_certificate |
TLS_CERT, TLS_KEY, TLS_MIN_VERSION ; voir TLS |
pm = static / pm = dynamic, pm.max_children |
PHP_WORKERS=N / PHP_WORKERS=MIN:MAX |
php_admin_value[...], php.ini |
votre propre fichier .ini copié dans /usr/local/etc/php/conf.d/ dans l'image (voir plus haut) |
gzip on, brotli on |
compression activée par défaut, configurée avec COMPRESSION_ENCODINGS ; voir Compression |
expires 30d pour les fichiers statiques |
STATIC_MAX_AGE (par défaut 30d) |
limit_req |
RATE_LIMIT, RATE_WINDOW_SECONDS (fenêtre fixe par IP) ; voir Limitation de débit |
set_real_ip_from, real_ip_header |
TRUSTED_PROXIES ; voir Proxys de confiance |
error_page 404 /404.html |
ERROR_PAGES_DIR avec {status}.html ; voir Pages d'erreur |
access_log |
ACCESS_LOG=all ou error (lignes JSON) ; voir Journalisation des accès |
location ~ ^/uploads/.*\.php$ { deny all; } |
PHP_DENY_PATHS=/uploads/** ; voir Liste de refus d'exécution PHP |
pm.status_path, ping.path |
INTERNAL_ADDR avec /health et /metrics ; voir Contrôles de santé |
fastcgi_finish_request() |
oxphp_finish_request() ; voir Réponse anticipée |
4. Vérifiez les différences de comportement
max_execution_timecompte le temps réel écoulé. Sous PHP-FPM, le temps passé à attendre une base de données ou un appel HTTP n'est pas décompté ; sous PHP thread-safe, il l'est. Un endpoint lent qui n'atteignait jamais la limite auparavant peut se mettre à renvoyer504. Voir Délais d'expiration.php_sapi_name()renvoiecli-server. Le code qui bifurque selonfpm-fcgia besoin d'une autre vérification :function_exists('oxphp_request_id').- Quelques clés de
$_SERVERdiffèrent.SERVER_ADDR,PATH_TRANSLATEDetREDIRECT_STATUSne sont pas définies, etPHP_AUTH_USER/PHP_AUTH_PWne sont pas extraites ; lisez plutôtHTTP_AUTHORIZATION. Voir Différences avec PHP-FPM. - Le framing est restreint par défaut. Les réponses portent
X-Frame-Options: SAMEORIGINet une politiqueframe-ancestorsassortie. DéfinissezFRAME_OPTIONS=offsi vous gérez le framing ailleurs ou si vous intégrez l'application dans une autre origine ; voir Protection contre le clickjacking.
5. Déployez à côté de l'ancienne pile
Faites tourner OxPHP à côté de nginx + PHP-FPM, dirigez une part du trafic vers lui via votre load balancer existant, utilisez /health/readiness pour les sondes, et comparez les taux d'erreur et la latence sur /metrics avant de basculer le reste.
6. Activez le mode worker en dernier
Migrez d'abord dans le mode par défaut. Définissez ensuite WORKER_MODE_ENABLED=true et faites pointer ENTRY_FILE vers un script de worker. L'état qui vit dans des propriétés statiques et les connexions de longue durée survivent désormais d'une requête à l'autre : lisez donc Ce qui est réinitialisé et ce qui persiste avant de l'activer.
Depuis FrankenPHP ou RoadRunner
Les scripts de worker gardent leur forme : un amorçage unique, puis le traitement des requêtes. Remplacez la boucle frankenphp_handle_request() par un unique appel à oxphp_worker($handler). OxPHP exécute la boucle et appelle le gestionnaire pour chaque requête ; à l'intérieur, lisez la requête depuis les superglobales ou oxphp_http_request(). La boucle PSR-7 waitRequest() / respond() de RoadRunner n'a pas d'équivalent : déplacez le gestionnaire de l'application dans ce même callback. Voir oxphp_worker() et Mode worker.
Supprimez le compteur MAX_REQUESTS
Il n'existe pas d'équivalent, et vous n'en avez pas besoin : un worker n'est pas censé être redémarré toutes les N requêtes, et le faire ne sert qu'à masquer une fuite. Si vous en soupçonnez une, suivez-la plutôt :
- Tracez
oxphp_worker_memory_bytespar worker et surveillez une hausse régulière. - Définissez
WORKER_MAX_MEMORY_MIBcomme filet de sécurité. Un worker qui dépasse la limite est remplacé avant que le conteneur ne manque de mémoire, et chacun de ces recyclages est compté dansoxphp_worker_recycles_by_reason_total{reason="max_memory"}. - Cette limite ne mesure que le tas propre de PHP. Si votre pile logicielle s'appuie largement sur des extensions, comparez
Worker::current()->rss()à votre propre seuil et appelezWorker::scheduleExit().
Ce qui ne se transpose pas
- OxPHP ne prend en charge ni reverse proxy ni upstream : il n'y a pas de
proxy_passni de serveur WebSocket. Si nginx sert aussi de frontal à d'autres services, gardez un proxy devant OxPHP pour ces routes. - Une instance a un seul port et un seul protocole. Elle sert du HTTP en clair ou du HTTPS, pas les deux, si bien que la redirection du port 80 vers HTTPS nécessite un proxy ou une seconde instance. Le certificat est lu au démarrage, donc un renouvellement nécessite un redémarrage ; voir TLS.
- HTTP/3 et
103 Early Hintsne sont pas encore disponibles ; voir la feuille de route. - OxPHP ne fonctionne que sous Linux et est distribué sous forme d'image Docker. Il n'existe pas de paquets apt ni brew. PHP 8.4 et 8.5 sont pris en charge.
Prompts pour votre agent
Ces prompts supposent un agent connecté au serveur MCP de la documentation OxPHP — il lira lui-même les pages dont il a besoin.
Migre cette application de nginx et PHP-FPM vers OxPHP. Lis la page `getting-started/migration` via le serveur MCP de la documentation OxPHP.
Traduis les blocs server de nginx, les réglages de pool de PHP-FPM et les surcharges de php.ini de ce dépôt en un Dockerfile OxPHP et en variables d'environnement, choisis le mode de routage d'après les règles `try_files`, et liste chaque différence de comportement et chaque fonctionnalité non prise en charge qui s'applique à ce code, avec le fichier concerné.Porte vers OxPHP le worker FrankenPHP ou RoadRunner de ce dépôt. Lis la page `getting-started/migration` via le serveur MCP de la documentation OxPHP.
Réécris le script de worker autour d'un unique appel à `oxphp_worker()`, supprime tout compteur qui redémarre le worker toutes les N requêtes, et dis-moi quelle métrique et quelle limite mémoire mettre en place à sa place.Et ensuite
- Routage — les modes de routage Traditional, Framework, SPA et Worker en détail
- Guide Docker — Dockerfiles de développement et de production, configuration de Compose, montages d'ini PHP
- Configuration — référence complète des variables d'environnement
- Mode worker — workers PHP persistants qui s'initialisent une fois et traitent plusieurs requêtes
- Exemples de déploiement — recettes complètes pour Laravel, Symfony, WordPress, Drupal, Magento et d'autres