Best Apache and PHP-FPM Configuration for a PHP Website on Ubuntu
Best Apache and PHP-FPM Configuration for a PHP Website on Ubuntu
This tutorial provides a practical per-subdomain Apache and PHP-FPM configuration for a PHP website on Ubuntu. A separate PHP-FPM pool and Unix socket are used for the site, which helps isolate its PHP settings and worker limits from other websites on the same server.
Suggested categories: Linux, Apache, PHP, Performance, DevOps
1. Example Environment
Replace the example values with your actual domain, document root and email address.
Domain: subdomain.example.com
Document Root: /var/www/vhost/subdomain.example.com
PHP Version: 8.3
PHP-FPM Socket: /var/run/php/subdomain.example.com.sock2. Create the Apache Virtual Host
Create a dedicated Apache virtual-host file:
sudo vim /etc/apache2/sites-available/subdomain.example.com.conf<VirtualHost *:80>
ServerAdmin hosting@example.com
ServerName subdomain.example.com
DocumentRoot /var/www/vhost/subdomain.example.com
<Directory /var/www/vhost/subdomain.example.com/>
Options +FollowSymlinks
AllowOverride All
Require all granted
</Directory>
# Send PHP requests to the dedicated PHP-FPM socket
<FilesMatch \.php$>
SetHandler "proxy:unix:/var/run/php/subdomain.example.com.sock|fcgi://localhost/"
</FilesMatch>
ErrorLog ${APACHE_LOG_DIR}/subdomain.example.com-error.log
CustomLog ${APACHE_LOG_DIR}/subdomain.example.com-access.log combined
</VirtualHost>3. Enable the Required Apache Modules
sudo a2enmod proxy
sudo a2enmod proxy_fcgi
sudo a2enmod setenvif
sudo a2enmod rewrite4. Create a Dedicated PHP-FPM Pool
Create a separate PHP-FPM pool for the website:
sudo vim /etc/php/8.3/fpm/pool.d/subdomain.example.com.conf[subdomain.example.com]
user = www-data
group = www-data
listen = /var/run/php/subdomain.example.com.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
; ---------------------------------------------------------
; PHP application settings
; ---------------------------------------------------------
php_admin_value[disable_functions] = passthru,shell_exec,system
php_admin_flag[allow_url_fopen] = on
php_admin_value[short_open_tag] = on
php_admin_value[max_execution_time] = 360
php_admin_value[max_file_uploads] = 200
php_admin_value[max_input_time] = 600
php_admin_value[max_input_vars] = 100000
php_admin_value[memory_limit] = 256M
php_admin_value[session.gc_maxlifetime] = 7200
php_admin_value[upload_max_filesize] = 128M
php_admin_value[post_max_size] = 128M
php_admin_value[date.timezone] = Asia/Kolkata
; ---------------------------------------------------------
; PHP-FPM slow request logging
; ---------------------------------------------------------
request_slowlog_timeout = 10s
slowlog = /var/log/php8.3-fpm-slow.log
request_terminate_timeout = 300s
catch_workers_output = yes
; ---------------------------------------------------------
; PHP-FPM process manager
; ---------------------------------------------------------
pm = dynamic
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.max_requests = 300
chdir = /5. Why Use a Separate PHP-FPM Pool?
- Dedicated PHP-FPM workers and Unix socket
- Site-specific PHP limits
- Independent slow-request logging
- Worker recycling using
pm.max_requests - Better isolation between multiple PHP applications
6. Enable the Virtual Host
sudo a2ensite subdomain.example.com.conf7. Validate PHP-FPM
sudo php-fpm8.3 -tYou should see a successful configuration test.
8. Validate Apache
sudo apache2ctl configtestExpected result:
Syntax OK9. Restart or Reload the Services
sudo systemctl restart php8.3-fpm
sudo systemctl reload apache210. Verify the PHP-FPM Socket
ls -l /var/run/php/subdomain.example.com.sockThe socket should normally be owned by www-data and use mode 0660.
11. Verify the Apache Virtual Host
sudo apache2ctl -SConfirm that the hostname is mapped to the expected virtual host.
12. Test PHP
For a temporary test, create:
sudo tee /var/www/vhost/subdomain.example.com/info.php > /dev/null <<'PHP'
<?php
phpinfo();
PHPOpen:
http://subdomain.example.com/info.phpConfirm that PHP 8.3 is running through the expected PHP-FPM configuration.
Remove the test file immediately after testing:
sudo rm -f /var/www/vhost/subdomain.example.com/info.php13. Check PHP-FPM Processes
ps aux | grep '[p]hp-fpm'
sudo systemctl status php8.3-fpm --no-pager14. Check Slow PHP Requests
The configuration records requests that take 10 seconds or longer in the PHP-FPM slow log.
sudo tail -f /var/log/php8.3-fpm-slow.log15. Important PHP-FPM Sizing Note
Do not copy pm.max_children = 50 blindly to every server. The correct value depends on available RAM, application memory usage and other services running on the server.
Also, memory_limit = 1024M is a maximum PHP memory limit per request. It does not mean that every worker continuously consumes 1 GB of RAM. Measure actual PHP-FPM worker memory usage before deciding the final worker count.
16. Example Baseline Configuration
pm = dynamic
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.max_requests = 300Monitor memory usage, response time and PHP-FPM queueing, then adjust the values for the workload.
17. Useful Monitoring Commands
# PHP-FPM
sudo systemctl status php8.3-fpm --no-pager
# Apache
sudo systemctl status apache2 --no-pager
# PHP-FPM log
sudo tail -f /var/log/php8.3-fpm.log
# PHP-FPM slow log
sudo tail -f /var/log/php8.3-fpm-slow.log
# Apache error log
sudo tail -f /var/log/apache2/subdomain.example.com-error.log
# Apache access log
sudo tail -f /var/log/apache2/subdomain.example.com-access.log
# PHP-FPM processes
ps aux | grep '[p]hp-fpm'
# Memory
free -h
# Load
uptime18. Quick Deployment Checklist
[✓] Apache virtual host created
[✓] Dedicated document root configured
[✓] Dedicated PHP-FPM pool created
[✓] Dedicated Unix socket configured
[✓] proxy and proxy_fcgi enabled
[✓] Slow request logging enabled
[✓] Request timeout configured
[✓] Worker recycling configured
[✓] PHP-FPM configuration tested
[✓] Apache configuration tested
[✓] Services restarted/reloaded
[✓] PHP-FPM socket verified
[✓] Test info.php removed19. Quick Copy-Paste Commands
sudo a2enmod proxy
sudo a2enmod proxy_fcgi
sudo a2enmod setenvif
sudo a2enmod rewrite
sudo a2ensite subdomain.example.com.conf
sudo php-fpm8.3 -t
sudo apache2ctl configtest
sudo systemctl restart php8.3-fpm
sudo systemctl reload apache2
ls -l /var/run/php/subdomain.example.com.sockImportant
Before using this configuration in production, replace:
subdomain.example.com
hosting@example.com
/var/www/vhost/subdomain.example.comNote: the original command had sudo vim vim .... The correct command is sudo vim ....
Discussion (0)