Magento sur OxPHP
Magento est la recette la plus lourde de cette section. Il impose un moteur de recherche (OpenSearch), une longue liste d'extensions et une étape de déploiement du contenu statique. Il s'exécute dans le mode de routage framework d'OxPHP avec pub/ comme racine du document, mais ses URL de fichiers statiques versionnées nécessitent une étape supplémentaire, décrite ci-dessous.
La stack en un coup d'œil
- Image OxPHP :
ghcr.io/oxphp/oxphp:0.13.0-php8.4-alpine3.23(PHP 8.4) - Mode de routage : Framework (
ENTRY_FILE=index.php;DOCUMENT_ROOT=/var/www/html/pubremplace la valeur par défaut…/public) - Extensions ajoutées :
bcmath,gd,intl,pdo_mysql,soap,xsl,zip,mbstring,ftp,pcntl,sockets - Services : OxPHP + MySQL 8.0 + OpenSearch 2.x
- URL :
http://localhost:8093· admin/admin· internehttp://localhost:9094/health
Magento 2.4.8 déclare "php": "~8.2 || ~8.3 || ~8.4" et rejette PHP 8.5, il faut donc épingler l'image PHP 8.4. ext-sockets est une dépendance transitive (php-amqplib) et nécessite linux-headers pour compiler.
Organisation du projet
Magento Open Source depuis le canal de distribution officiel nécessite des clés d'authentification Adobe Marketplace. Pour l'installer sans clés, clonez le dépôt open source (ses modules sont fournis dans l'arborescence via replace, donc composer install ne récupère que les dépendances Packagist) :
mkdir -p magento-oxphp
git clone --branch 2.4.8 --depth 1 https://github.com/magento/magento2.git magento-oxphp/src
# composer install runs later, inside the PHP 8.4 container (composer:2 is PHP 8.5
# and Magento rejects it):
docker compose run --rm --no-deps -e COMPOSER_MEMORY_LIMIT=-1 app \
composer install --no-interaction --prefer-distDockerfile et fichier compose
src/Dockerfile.oxphp est nommé ainsi pour éviter d'entrer en conflit avec les propres assets docker de Magento.
ARG OXPHP_VERSION=0.13.0
ARG PHP_VERSION=8.4
ARG ALPINE_VERSION=3.23
# ── PHP base: Magento runtime extensions ──────────────────────
FROM php:${PHP_VERSION}-zts-alpine${ALPINE_VERSION} AS php-base
RUN apk add --no-cache \
icu-libs libpng libjpeg-turbo freetype oniguruma libzip libxslt \
&& apk add --no-cache --virtual .build-deps \
icu-dev libpng-dev libjpeg-turbo-dev freetype-dev oniguruma-dev \
libzip-dev libxslt-dev libxml2-dev linux-headers \
&& docker-php-ext-configure gd --with-jpeg --with-freetype \
&& docker-php-ext-install -j"$(nproc)" \
bcmath gd intl pdo_mysql soap xsl zip mbstring ftp pcntl sockets \
&& apk del .build-deps
# ── Composer ──────────────────────────────────────────────────
FROM composer:2 AS composer
# ── OxPHP artifacts (PHP 8.4 image) ───────────────────────────
FROM ghcr.io/oxphp/oxphp:${OXPHP_VERSION}-php${PHP_VERSION}-alpine${ALPINE_VERSION} AS oxphp
# ── dev: OxPHP server + PHP CLI + Composer + Magento extensions ─
FROM php-base AS dev
RUN apk add --no-cache libgcc git patch
COPY --from=composer /usr/bin/composer /usr/local/bin/composer
COPY --from=oxphp /usr/local/bin/oxphp /usr/local/bin/oxphp
COPY --from=oxphp /usr/local/lib/liboxphp_bridge.so /usr/local/lib/
COPY --from=oxphp /usr/local/lib/php/extensions/ /tmp/oxphp-ext/
RUN cp /tmp/oxphp-ext/*/oxphp_sapi.so "$(php -r 'echo ini_get("extension_dir");')/" \
&& rm -rf /tmp/oxphp-ext \
&& echo "extension=oxphp_sapi.so" > /usr/local/etc/php/conf.d/oxphp-ext.ini
RUN { \
echo "[opcache]"; echo "opcache.enable=1"; echo "opcache.enable_cli=1"; \
echo "opcache.validate_timestamps=1"; echo "opcache.revalidate_freq=0"; \
} > /usr/local/etc/php/conf.d/opcache-dev.ini
RUN { \
echo "memory_limit=4G"; echo "max_execution_time=1800"; \
echo "realpath_cache_size=10M"; echo "realpath_cache_ttl=86400"; \
echo "upload_max_filesize=64M"; echo "post_max_size=64M"; \
} > /usr/local/etc/php/conf.d/magento.ini
RUN getent passwd www-data >/dev/null \
|| adduser -D -H -u 82 -G www-data -s /sbin/nologin www-data
RUN mkdir -p /var/www/html/pub && chown -R www-data:www-data /var/www/html
ENV LD_LIBRARY_PATH=/usr/local/lib
WORKDIR /var/www/html
EXPOSE 80 9090
CMD ["oxphp"]services:
app:
build:
context: ./src
dockerfile: Dockerfile.oxphp
target: dev
image: magento-oxphp/app:dev
container_name: magento-oxphp
ports:
- "8093:80"
- "9094:9090"
volumes:
- ./src:/var/www/html
environment:
# LISTEN_ADDR defaults to 0.0.0.0:80, so it is omitted.
DOCUMENT_ROOT: /var/www/html/pub # overrides the default /var/www/html/public
ENTRY_FILE: index.php # framework mode
INTERNAL_ADDR: 0.0.0.0:9090
ACCESS_LOG: all
depends_on:
db:
condition: service_healthy
opensearch:
condition: service_healthy
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://0.0.0.0:9090/health"]
interval: 10s
timeout: 3s
retries: 5
start_period: 5s
db:
image: mysql:8.0
container_name: magento-oxphp-db
ports:
- "3310:3306"
command:
- --max_allowed_packet=64M
- --innodb-buffer-pool-size=1G
- --log_bin_trust_function_creators=1 # Magento creates triggers/functions
environment:
MYSQL_DATABASE: magento
MYSQL_USER: magento
MYSQL_PASSWORD: magento
MYSQL_ROOT_PASSWORD: root
volumes:
- db_data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-uroot", "-proot"]
interval: 5s
timeout: 5s
retries: 30
start_period: 20s
restart: unless-stopped
opensearch:
image: opensearchproject/opensearch:2.19.1
container_name: magento-oxphp-opensearch
environment:
- discovery.type=single-node
- DISABLE_SECURITY_PLUGIN=true
- DISABLE_INSTALL_DEMO_CONFIG=true
- bootstrap.memory_lock=true
- "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g"
ulimits:
memlock: { soft: -1, hard: -1 }
nofile: { soft: 65536, hard: 65536 }
ports:
- "9201:9200"
volumes:
- opensearch_data:/usr/share/opensearch/data
healthcheck:
test: ["CMD-SHELL", "curl -sf http://localhost:9200/_cluster/health || exit 1"]
interval: 10s
timeout: 5s
retries: 30
start_period: 20s
restart: unless-stopped
volumes:
db_data:
opensearch_data:Installation et premier démarrage
docker compose up -d db opensearch
# composer install (see Project layout), then:
docker compose run --rm app php bin/magento setup:install \
--base-url=http://localhost:8093/ \
--db-host=db --db-name=magento --db-user=magento --db-password=magento \
--admin-firstname=Admin --admin-lastname=User \
--admin-email=admin@example.com --admin-user=admin --admin-password='Admin123!' \
--language=en_US --currency=USD --timezone=America/New_York \
--search-engine=opensearch --opensearch-host=opensearch --opensearch-port=9200 \
--opensearch-index-prefix=magento --opensearch-enable-auth=0
# production mode compiles DI and deploys static content
docker compose run --rm app php bin/magento deploy:mode:set production
# CRITICAL for OxPHP: make versioned static URLs resolve (see notes below)
docker compose run --rm app sh -c \
'ln -sfn . "pub/static/version$(cat pub/static/deployed_version.txt)"'
docker compose up -d appNotes OxPHP
-
Les URL statiques versionnées nécessitent un lien symbolique. Magento émet des URL d'assets comme
/static/version<timestamp>/frontend/…, alors que les fichiers se trouvent danspub/static/frontend/…. nginx supprime le segmentversion<N>/grâce à une règle de réécriture ; le mode framework d'OxPHP n'a pas de réécriture de ce type, donc chaque asset versionné renverrait404et la vitrine s'afficherait sans styles. La solution est un lien symbolique auto-référentiel qui fait pointer le chemin versionné vers les fichiers réels :ln -sfn . "pub/static/version$(cat pub/static/deployed_version.txt)"Comme le lien symbolique reste à l'intérieur de
DOCUMENT_ROOT(pub/), aucune entréeSYMLINK_ALLOW_PATHSn'est requise. -
Exécutez le mode production. Le pool de workers d'OxPHP est multithread (PHP ZTS). Le mode développeur de Magento génère les classes DI et les fichiers statiques à la volée (via
pub/static.php, que le mode framework ne route pas), ce qui risque de provoquer des conditions de concurrence entre les threads de workers.deploy:mode:set productionprécompile la DI et déploie le contenu statique en amont, de sorte que les workers ne génèrent jamais de code au moment de la requête. -
MySQL :
--log_bin_trust_function_creators=1. Magento crée des triggers et des fonctions stockées pendant l'installation ; avec la journalisation binaire activée (valeur par défaut de MySQL 8.0), l'utilisateurmagentonon-SUPERdéclenche sinon l'erreur 1419. -
composer installs'exécute dans le conteneur PHP 8.4. L'imagecomposer:2standard est en PHP 8.5, que Magento rejette ; exécutez-la plutôt via l'imageappconstruite.
Vérification
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8093/ # 200 storefront
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8093/admin # 200 admin login
curl -s http://localhost:8093/ | grep -oE '/static/version[0-9]+/[^"]+\.css' | head -1 | \
xargs -I{} curl -s -o /dev/null -w "%{http_code}\n" "http://localhost:8093{}" # 200
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:9094/health # 200Prompts 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.
Fais tourner ma boutique Magento 2 sur OxPHP en local. Lis la page `examples/ecommerce/magento` via le serveur MCP de la documentation OxPHP.
Écris le Dockerfile et le fichier Compose pour ce dépôt avec MySQL et OpenSearch, et donne-moi la séquence d'installation dans l'ordre, en terminant par le lien symbolique de version des fichiers statiques dont ma version déployée a besoin.Ma vitrine Magento sur OxPHP s'affiche sans styles et ses URL `/static/version…` renvoient 404. Lis la page `examples/ecommerce/magento` via le serveur MCP de la documentation OxPHP.
Vérifie ce que contient réellement mon `pub/static/` et dans quel mode se trouve cette installation, puis donne-moi la commande de lien symbolique pour ma version déployée, plus le changement de mode si je suis encore en mode développeur.Voir aussi
- Routage · Guide Docker · Référence de configuration
- OpenCart — l'autre recette e-commerce