WordPress plugins like WordFence use $_SERVER['DOCUMENT_ROOT'] to locate
config/log files. With ProxyPassMatch, Apache sends its own mount path
(/mnt/users/...) as DOCUMENT_ROOT, which doesn't exist in the FPM
container.
ProxyFCGISetEnvIf can't override DOCUMENT_ROOT when using ProxyPassMatch
(Apache sets it after the directive evaluates). Instead, set it via the
FPM pool config's env[] directive which takes precedence.
create-php-config.sh now adds env[DOCUMENT_ROOT] = /home/$user/public_html
when in TCP listen mode (shared httpd), giving PHP the correct path.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Separate Apache and PHP-FPM into distinct container roles to reduce
per-customer memory overhead on shared servers. Adds three new images:
- Dockerfile.fpm: PHP-FPM only (no Apache), listens on TCP port 9000
- Dockerfile.shared-httpd: Apache only (no PHP), with SSL and proxy_fcgi
- Existing Dockerfile unchanged for standalone mode
Key changes:
- detect-memory.sh: CONTAINER_ROLE env var (combined/fpm_only/httpd_only)
controls the memory budget split
- create-php-config.sh: FPM_LISTEN env var for TCP port vs Unix socket,
added /fpm-ping and /fpm-status health endpoints
- New entrypoints for each container role
- tune-mpm.sh for hot-adjusting Apache MPM settings
- shared-vhost-template.tpl with proxy_fcgi and SSL on port 443
- CI/CD builds all three image types in parallel
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Switch PHP-FPM from pm=dynamic to pm=ondemand (zero idle workers),
auto-detect container memory via cgroups to calculate appropriate
limits, and generate Apache MPM config at runtime. All tuning values
are now overridable via environment variables.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Created user-specific crontab file at /home/$user/crontab
- Crontab now persists through container restarts/refreshes
- Users can manage their own cron jobs by editing their crontab file
- Automatically loads user crontab on container start
- Updated DEV environment to use user crontab for MySQL backups
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
The php-ioncube-loader package is incompatible with PHP 8.1 and was causing
a segmentation fault (exit code 139) when the Composer installer tried to
run PHP. This aligns PHP 8.1 with other PHP versions that already had
ioncube-loader removed.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
PHP error logs were incorrectly being written to /etc/httpd/logs/error_log
instead of the expected /home/$user/logs/php-fpm/ directory. Updated the
php_admin_value[error_log] setting to point to the proper location.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Added postgresql-devel package to Dockerfile for client libraries
- Added php-pgsql extension to all PHP versions (7.4, 8.0, 8.1, 8.2, 8.3, 8.4)
- Enables PHP applications to connect to PostgreSQL databases
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Apache mpm_event: Reduced StartServers from 10 to 2, adjusted spare threads
and worker limits for container environments
- PHP-FPM: Switched from static to dynamic process management with lower
process counts (5 max children instead of 10)
- Removed php-ioncube-loader from PHP 8.0 installation
- Expected memory reduction: 60-70% in idle state while maintaining responsiveness
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>