fix(magento): make nginx and php-fpm actually serve

The role could not deliver anything. The markoshust nginx image ships a
default vhost built for a different topology: fastcgi points at
unix:/sock/phpfpm.sock, port 8000 only returns 301 to https, the real
server sits on 8443 with a self-signed cert, and it references an upstream
host 'phpfpm' that does not exist here - so nginx aborted at config load
with 'host not found in upstream' and the container never started.
php-fpm listened on that same unix socket, because its
/usr/local/etc/php-fpm.conf carries no include line and php-fpm.d/*.conf
is therefore dead config.

Both are now replaced through type: config mounts. The role never had any
- that absence is why every template it previously rendered was inert.

The vhost stays minimal and includes Magento's own nginx.conf, copied from
nginx.conf.sample by the bootstrap. Its location blocks carry the .php
whitelist, the /static/version rewrites and the /media to get.php fallback
that a hand-written vhost has to reimplement - the previous attempt did
not, and would have executed every .php under pub/.

PHP moves from 8.5 to 8.4: Magento 2.4.8 requires ~8.2.0||~8.3.0||~8.4.0
and the bootstrap passes no platform-requirement override, so
composer create-project failed before nginx ever mattered.

nginx waits for the php socket before starting, for the reason given in
the erpnext frontend commit: the wildcard search domain turns a DNS miss
into a routable wrong answer, and nginx pins upstreams at config load.

Also: the oauth2 origin port named 8080, where nothing listens, and the
healthcheck proved only that some listener existed - it stayed green on a
redirect loop and on 502.

Measured in a rebuild of the role topology against Magento's real
nginx.conf.sample: HTTP 200 on / and /index.php, healthy healthcheck, and
the counter-test - without the gate and with php down, nginx exits 1.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
kevinveenbirkenbachandClaude Opus 5 committed 2026-08-06 10:47:39 +02:00
1 parent e62e695876
commit dc08bc6212
8 files changed
+86 -6

No files matched your search

+2 -2
View File
@@ -14,7 +14,7 @@ sso:
oauth2:
origin:
host: nginx
port: "8080"
port: "{{ lookup('config', 'web-app-magento', 'services.magento.ports.internal.http') }}"
dashboard:
bond: 1
enabled: "{{ 'web-app-dashboard' in group_names }}"
@@ -29,7 +29,7 @@ email:
shared: "{{ 'web-app-mailu' in group_names }}"
php:
image: markoshust/magento-php
version: 8.5-fpm
version: 8.4-fpm
name: magento-php
ports:
internal:
+16
View File
@@ -7,3 +7,19 @@ data:
target: /var/www/html
- service: php
target: /var/www/html
nginx_conf:
type: config
source: "{{ [ lookup('container', 'web-app-magento', 'directories.volumes'), 'nginx-default.conf' ] | path_join }}"
mode: "0444"
mounts:
- service: nginx
target: /etc/nginx/conf.d/default.conf
php_fpm_conf:
type: config
source: "{{ [ lookup('container', 'web-app-magento', 'directories.volumes'), 'php-fpm.conf' ] | path_join }}"
mode: "0444"
mounts:
- service: php
target: /usr/local/etc/php-fpm.conf
+12
View File
@@ -1,4 +1,16 @@
---
- name: "📄 Render the container config overrides for {{ application_id }}"
ansible.builtin.include_tasks:
file: "{{ lookup('path_absolute', 'roles/sys-svc-compose/tasks/utils/render_replicated_templates.yml') }}"
vars:
role_templates:
- src: "nginx-default.conf.j2"
dest: "{{ MAGENTO_NGINX_CONF_PATH }}"
mode: "0444"
- src: "php-fpm.conf.j2"
dest: "{{ MAGENTO_PHP_FPM_CONF_PATH }}"
mode: "0444"
- name: "🧩 load docker, db/redis/proxy for {{ application_id }}"
include_role:
name: sys-stk-full
+16
View File
@@ -17,6 +17,7 @@
mkdir -p /tmp/composer/cache
cd /var/www/html
composer create-project --no-interaction --no-progress --repository-url=https://repo.magento.com/ magento/project-community-edition=2.4.8 .
cp nginx.conf.sample nginx.conf
mkdir -p var pub/static pub/media app/etc
chmod -R 775 var pub/static pub/media app/etc
'
@@ -58,3 +59,18 @@
(magento_install.stdout is defined and
('Magento installation complete' in magento_install.stdout
or 'successfully installed' in magento_install.stdout))
- name: "🔄 Restart nginx so it picks up Magento's vhost (compose)"
ansible.builtin.command: "container restart {{ MAGENTO_NGINX_CONTAINER | quote }}"
register: magento_nginx_restart_compose
changed_when: magento_nginx_restart_compose.rc == 0
when: DEPLOYMENT_MODE == 'compose'
- name: "🔄 Restart nginx so it picks up Magento's vhost (swarm)"
ansible.builtin.command: >-
container service update --force
{{ lookup('container_service', application_id, 'nginx') | quote }}
register: magento_nginx_restart_swarm
changed_when: magento_nginx_restart_swarm.rc == 0
timeout: "{{ lookup('timeout', 600) | int }}"
when: DEPLOYMENT_MODE == 'swarm'
@@ -1,17 +1,16 @@
{% include 'roles/sys-svc-compose/templates/base.yml.j2' %}
{% set MAGENTO_PHP_READY_GATE = "until nc -z " ~ MAGENTO_PHP_HOST ~ " " ~ MAGENTO_PHP_PORT ~ " 2>/dev/null; do sleep 2; done;" %}
{% set service_name = 'nginx' %}
{{ service_name }}:
{% include 'roles/sys-svc-container/templates/deploy.yml.j2' %}
{{ lookup('container_image', application_id, 'nginx') }}
{{ lookup('compose_only', 'container_name', MAGENTO_NGINX_CONTAINER) }}
environment:
PHP_HOST: "php"
PHP_PORT: "9000"
command: ["sh", "-c", "{{ MAGENTO_PHP_READY_GATE }} exec nginx -g 'daemon off;'"]
{{ lookup('depends_on', ['php', 'search']) }}
{{ lookup('container_volumes', application_id, 'nginx') | indent(4) }}
{{ lookup('container_ports', ['magento', 'http', DOCKER_BIND_HOST]) | indent(4) }}
healthcheck:
test: ["CMD-SHELL", "nginx -t >/dev/null 2>&1 && { grep -q ':1F40' /proc/net/tcp || grep -q ':1F40' /proc/net/tcp6; }"]
test: ["CMD-SHELL", "nginx -t >/dev/null 2>&1 && nc -z {{ MAGENTO_PHP_HOST }} {{ MAGENTO_PHP_PORT }}"]
interval: 10s
timeout: 5s
retries: 5
@@ -0,0 +1,13 @@
upstream fastcgi_backend {
server {{ MAGENTO_PHP_HOST }}:{{ MAGENTO_PHP_PORT }};
}
server {
listen {{ MAGENTO_NGINX_PORT }};
set $MAGE_ROOT /var/www/html;
{# Exception: glob, not a typo — a hard include emergs on first boot,
before the bootstrap has copied nginx.conf into the volume. #}
include /var/www/html/nginx[.]conf;
}
@@ -0,0 +1,17 @@
{# Exception: this file has no include= line, so php-fpm.d/*.conf is never
read — an override dropped there is silently inert. #}
[global]
error_log = /proc/self/fd/2
daemonize = no
[www]
access.log = /proc/self/fd/2
listen = 0.0.0.0:{{ MAGENTO_PHP_PORT }}
pm = dynamic
pm.max_children = 10
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6
clear_env = no
catch_workers_output = yes
process.dumpable = yes
+7
View File
@@ -7,6 +7,13 @@ MAGENTO_USER: "app"
MAGENTO_DOMAIN: "{{ lookup('domain',application_id) }}"
MAGENTO_URL: "{{ lookup('tls', application_id, 'url.base') }}"
MAGENTO_PHP_HOST: "php"
MAGENTO_PHP_PORT: "{{ lookup('config', application_id, 'services.php.ports.internal.fpm') }}"
MAGENTO_NGINX_PORT: "{{ lookup('config', application_id, 'services.magento.ports.internal.http') }}"
MAGENTO_NGINX_CONF_PATH: "{{ [ lookup('container', application_id, 'directories.volumes'), 'nginx-default.conf' ] | path_join }}"
MAGENTO_PHP_FPM_CONF_PATH: "{{ [ lookup('container', application_id, 'directories.volumes'), 'php-fpm.conf' ] | path_join }}"
MAGENTO_SEARCH_CONTAINER: "{{ lookup('config', application_id, 'services.search.name') }}"
MAGENTO_PHP_CONTAINER: "{{ lookup('config', application_id, 'services.php.name') }}"