PHP hardening reduces the attack surface of web applications by restricting what PHP scripts can do at the interpreter level. A default PHP installation exposes powerful functions that can be abused by attackers who exploit code injection vulnerabilities: system(), exec(), and passthru() allow execution of arbitrary OS commands; file_get_contents() with allow_url_fopen can fetch remote files; and unrestricted file system access allows path traversal attacks. The four most impactful PHP hardening settings are: disable_functions (block dangerous built-in functions), open_basedir (restrict filesystem access to the web root), OPcache configuration (secure the bytecode cache), and hiding the PHP version from HTTP headers. This guide covers all of these plus additional php.ini security settings for RHEL 9 production servers.
Prerequisites
- PHP 8.x installed on RHEL 9
Step 1 — Disable Dangerous Functions
# /etc/php.ini — disable functions commonly exploited in webshells
disable_functions = exec, passthru, shell_exec, system, proc_open, popen,
curl_exec, curl_multi_exec, parse_ini_file, show_source, phpinfo,
pcntl_exec, dl, posix_kill, posix_setuid, posix_setgid
; Note: Only disable functions not needed by your application
; Laravel/Symfony require most of these to be available — review your specific needs
Step 2 — Restrict Filesystem Access with open_basedir
# Restrict PHP to only access files within the web root and tmp
; /etc/php.ini
open_basedir = /var/www/html:/tmp:/var/lib/php/session
; Per-virtual-host open_basedir in PHP-FPM pool (/etc/php-fpm.d/www.conf):
php_admin_value[open_basedir] = /var/www/myapp:/tmp:/var/lib/php/session
Step 3 — Hide PHP Version Information
# /etc/php.ini
expose_php = Off ; Remove X-Powered-By: PHP/8.3.x header
display_errors = Off ; Never display errors in production
display_startup_errors = Off
log_errors = On
error_log = /var/log/php_errors.log
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
Step 4 — Harden Session Configuration
# /etc/php.ini — session security settings
session.cookie_httponly = 1 ; Prevent JavaScript from reading session cookies
session.cookie_secure = 1 ; Session cookies only over HTTPS
session.cookie_samesite = Strict ; CSRF protection
session.use_strict_mode = 1 ; Reject unrecognised session IDs
session.use_only_cookies = 1 ; No session IDs in URLs
session.gc_maxlifetime = 1800 ; 30-minute session timeout
Step 5 — Secure File Upload Settings
# /etc/php.ini
file_uploads = On
upload_max_filesize = 10M ; Restrict to application needs
max_file_uploads = 5 ; Limit simultaneous uploads
upload_tmp_dir = /var/lib/php/tmp ; Dedicated temp directory (not /tmp)
allow_url_fopen = Off ; Prevent remote file inclusion
allow_url_include = Off ; Prevent remote code inclusion
Step 6 — Harden OPcache
# /etc/php.d/10-opcache.ini
opcache.enable=1
opcache.enable_cli=0 ; Disable OPcache for CLI
opcache.validate_timestamps=0 ; Disable file mtime check (production)
opcache.revalidate_freq=0
opcache.memory_consumption=256
opcache.max_accelerated_files=10000
; Prevent opcache bypass via forged timestamps
opcache.file_cache_only=0
systemctl restart php-fpm
php -r "echo ini_get('expose_php');" # Should output empty string (Off)
Conclusion
PHP hardening on RHEL 9 is a layered process — no single setting provides complete protection, but together these measures significantly reduce the impact of code injection vulnerabilities. The most critical settings for shared hosting environments are open_basedir (prevents path traversal across virtual hosts) and disable_functions (blocks command execution even if an attacker can inject PHP code). Always test that your application still functions correctly after applying these restrictions, as some frameworks may use functions in the disable_functions list for development tooling or CLI commands.
Next steps: How to Install PHP 8.3 on RHEL 9, How to Configure PHP-FPM with Nginx on RHEL 9, and How to Configure SELinux for Web Applications on RHEL 9.