Figuring out the possibilities for Apache and PHP reminds me of a Dr. Seuss book, “Fox in Sox”. It’s a favorite of mine. I love reading it to the kids. In it, Mr. Fox tries to get Mr. Knox to say all kinds of ridiculous (in meaning and hard to say) tongue twisters. At one point Mr. Knox exclaims:
“I can’t blab such blibber blubber!
My tongue isn’t make of rubber.”
That’s what my brain felt like after trying to figure all of the options for Apache and PHP. To combat my rubber brain, I created this flow-chart to help me keep track of the options, the pros and cons for each, and the path I finally chose.
First off, a list of requirements and goals:
- Chroot each vhost to it’s own directory, and have Apache and PHP run on that vhost’s server account
- Speed, run Apache and PHP at their most effective and efficient levels
- Utilize an opcode cache, APC, to speed up PHP pages
- Use trusted repositories to make installation and upgrading easier
Here’s what I eventually figured out about Apache and PHP:
These sites were helpful for the initial set up of PHP as CGI with mod_fcgi and Apache in chroot (mod_fcgi sends one request to each PHP process regardless if PHP children are available to handle more, and no sharing of APC opcode cache across PHP processes):
- http://www.howtoforge.com/how-to-set-up-apache2-with-mod_fcgid-and-php5-on-centos-5.2
- http://forum.linode.com/viewtopic.php?t=2982
This site was helpful for setting up PHP as CGI with mod_fastcgi and Apache in chroot (mod_fastcgi sends multiple requests to a PHP process, so the process can send them to children processes, and having one PHP process for each site allows for APC opcode cache to be usable.)
These sites helped me learn about php-fpm and how it is not quite ready for what I have in mind:
- http://www.makina-corpus.org/blog/install-drupal-php-fpm-fastcgi-apache-and-chroot-php-fpm
- https://groups.google.com/forum/?fromgroups=#!topic/highload-php-en/Uq2MDrudMQ4
I ended up going with Apache’s mod_fastcgi for using PHP as a CGI, and NOT using PHP-FPM, while running Apache in threaded mode with apache.worker enabled.
To get this set up is pretty easy. I already had Apache and PHP installed and running (with PHP as CGI using mod_fcgi), so here are the steps I used to convert it to run mod_fastcgi and apache.worker. I’m running CentOS 6.3.
Install the RPMForge repo for installing mod_fastcgi.
- Get latest from http://repoforge.org/use/ :
rpm -Uvh http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.2-2.el6.rf.x86_64.rpm
yum --enablerepo=rpmforge install mod_fastcgi
Edit the /etc/httpd/conf/httpd.conf
file
ServerTokens Prod
KeepAlive On
- Edit the worker section. I still need to do some testing to figure out the best configuration
<IfModule worker.c> StartServers 8 MaxClients 300 MinSpareThreads 25 MaxSpareThreads 75 ThreadsPerChild 25 MaxRequestsPerChild 0 </IfModule>
- If there, make sure to comment out, or delete the lines for mod_php:
LoadModule php5_module modules/libphp5.so
- this line also:
AddType application/x-httpd-php .php
- The last line should be:
Include conf/virtual_hosts.conf
Create a /etc/httpd/conf/virtual_hosts.conf
file
Each virtual host needs to have an entry similar to this in the httpd.conf file, or I like to create a separate virtual_host.conf and include that in the main httpd.conf.
# Name-based virtual hosts # # Default NameVirtualHost *:80 # Begin domain-name.com section <VirtualHost *:80> DocumentRoot /var/domain-name/home/html/ ServerName domain-name.com ServerAlias www.domain-name.com # Rewrite domain name to not use the 'www' RewriteEngine On RewriteCond %{HTTP_HOST} !^domain-name\.com$ [NC] RewriteRule ^/(.*) http://domain-name.com/$1 [R=301] # Specify where the error logs go for each domain ErrorLog /var/logs/httpd/current/domain-name.com-error_log CustomLog /var/logs/httpd/current/domain-name.com-access_log combined <IfModule mod_fastcgi.c> SuexecUserGroup domain-name domain-name ScriptAlias /cgi-bin/ "/var/www/cgi-bin/domain-name/" <Directory "/var/domain-name/home/html"> Options -Indexes FollowSymLinks +ExecCGI AddHandler php5-fastcgi .php Action php5-fastcgi /cgi-bin/php-fastcgi Order allow,deny Allow from all </Directory> </IfModule> </VirtualHost> # End domain-name.com section
Things to note:
- The line with
SuexecUserGroup
should have the user/group for the project.
Create the php-fastcgi file
Add a /var/www/cgi-bin/projectname/php-fastcgi
file for each project. This allows php to run as FastCGI, and use suEXEC. The php-fastcgi file needs to be under suexec’s default directory path /var/www/cgi-bin/
.
-
#!/bin/bash # Set PHPRC to the path for the php.ini file. Change this to # /var/projectname/home/ to let projects have their own php.ini file PHPRC=/var/domain-name/home/ export PHPRC export PHP_FCGI_MAX_REQUESTS=5000 export PHP_FCGI_CHILDREN=5 exec /usr/bin/php-cgi
Things to note:
- The directory and file created above must be have user/group of the project (the same as the user/group of the /var/projectname/ directory)
- The directory and file must be executable and writable by the owner ONLY.
- If you get Apache Internal Server errors, check
/var/log/httpd/suexec.log
- For each site, you can specify how much RAM the APC module can use. For large, busy sites, you set this higher. Not setting this defaults to 64MB, which is a bit more than needed for the average WP site. Change the last line in the
/var/www/cgi-bin/projectname/php-fastcgi
file:exec /usr/bin/php-cgi -d apc.shm_size=128M
Change php.conf
Comment out everything in the /etc/httpd/conf.d/php.conf
file so php is not loaded as a module when Apache starts.
Apache multi-threaded
Edit the /etc/sysconfig/httpd
file to allow Apache to use multi-threaded mode (httpd.worker) which handles basic HTML files much nicer (less RAM). Uncomment the line with HTTPD=/usr/sbin/httpd.worker
Config Check
Check the Apache configuration files to see if there are any errors.
service httpd configtest
If all good, restart Apache
service httpd restart
This will stop the running httpd service, and then start it again. Use this command after installing or removing a dynamically loaded module such as PHP. ORservice httpd reload
This will cause the running httpd service to reload the configuration file. Note that any requests being currently processed will be interrupted, which may cause a client browser to display an error message or render a partial page. ORservice httpd graceful
This will cause the running httpd service to reload the configuration file. Note that any requests being currently processed will use the old configuration.
Install APC
pecl install apc
Set up log rotation for Apache
- Add a file
/etc/logrotate.d/httpd.monti
-
/var/logs/httpd/*log { daily rotate 365 compress missingok notifempty copytruncate olddir /var/logs/httpd/archives/ sharedscripts postrotate /bin/kill -HUP `cat /var/run/httpd/httpd.pid 2>/dev/null` 2> /dev/null || true endscript }