harden(docker): non-root, dedicated healthcheck, opcache split, graceful shutdown

Coolify-doc-driven production hardening of the deploy stack:
- run the whole stack as non-root www-data; nginx on 8080 (non-privileged),
  pid in /tmp, user directive dropped (Coolify routes to any port)
- docker/healthcheck.sh: hit real /health route via PHP (not just port probe)
- split OPcache config into docker/php/opcache.ini
- graceful shutdown: supervisord stopsignal/stopwaitsecs + worker stop_grace_period
- APCu intentionally not added (Symfony cache uses redis)
- DEPLOY.md: 8080 port, non-root, resource-limit guidance

Verified on linux/amd64: non-root uid=82, /health 200, migrations run,
worker process healthcheck OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
hamed
2026-06-28 15:27:34 +03:30
co-authored by Claude Opus 4.8
parent c74b06b3cc
commit 5150365d2c
8 changed files with 84 additions and 23 deletions
+18 -2
View File
@@ -1,14 +1,28 @@
[supervisord]
nodaemon=true
user=root
# Run the whole stack as the non-root www-data user (security hardening).
# nginx listens on 8080 (non-privileged) so root is not needed to bind the port.
user=www-data
logfile=/dev/stdout
logfile_maxbytes=0
pidfile=/run/supervisord.pid
pidfile=/tmp/supervisord.pid
[unix_http_server]
file=/tmp/supervisor.sock
[supervisorctl]
serverurl=unix:///tmp/supervisor.sock
[rpcinterface:supervisor]
supervisor.rpcinterface_factory=supervisor.rpcinterface:make_main_rpcinterface
[program:php-fpm]
command=php-fpm -F
autorestart=true
priority=10
# Forward SIGTERM (graceful) and give workers time to finish in-flight requests.
stopsignal=TERM
stopwaitsecs=15
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
@@ -18,6 +32,8 @@ stderr_logfile_maxbytes=0
command=nginx -g 'daemon off;'
autorestart=true
priority=20
stopsignal=QUIT
stopwaitsecs=15
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr