- start-container: generous startretries + startsecs and graceful SIGTERM
stopwaitsecs for queue/scheduler/horizon, so a transient boot failure (e.g.
DB not ready) no longer marks a worker FATAL forever and silently drops jobs,
and an in-flight job finishes before SIGKILL on deploy/restart.
- container-health: new HEALTHCHECK that reports UNHEALTHY when php-fpm/nginx or
any enabled queue/scheduler/horizon worker is not RUNNING, so a dead worker
surfaces in docker ps / orchestration instead of letting jobs pile up.
Two recurring foot-guns in production stacks rolled into one image-level fix:
1. storage/ + bootstrap/cache/ ownership drift. ENABLE_LARAVEL_PERMS was
opt-in (default 0) and only chmod'd the top-level dir — so any subdir
created later by a different UID (root, nobody, …) stayed un-writable
for www-data. Symptom: workkit:db:backup pumping a multi-GB mysqldump
into a doomed bash redirect that fails with "Permission denied" only
after the pipeline starts. Now default-on (=1), recursive chown +
chmod ug+rwX, SGID on dirs so future files inherit the group, and we
pre-create the subdirs that ship empty (incl. storage/backups/) so
artisan never creates one as the wrong user.
2. mysql client TLS verification against self-signed in-cluster certs.
`php artisan db` failed with "TLS/SSL error: self-signed certificate
in certificate chain" because modern mysql/mariadb clients auto-enable
ssl-verify-server-cert when a password is on argv. Drops a
/etc/mysql/conf.d/00-laravel-client.cnf with ssl-verify-server-cert=OFF
so the connection still negotiates TLS but skips the chain check —
the right tradeoff for a private docker network. Override per-host
with MYSQL_CLIENT_VERIFY=ON or by mounting a stricter .cnf.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>