We set up the blog, did the first round of optimization and secured it last time. Today we optimize how Apache and PHP run.
Let’s start with PHP.
PHP
PHP, as configured out of the box, runs inside the same process as Apache. This isn’t optimal because it can take up a bunch of memory in all of the web server processes. Not only that but the cache of PHP’s code doesn’t seem to be as shared as it could be.
An analogy is thinking of Apache as a small sports car. PHP requires some other stuff to be bolted onto that car. When you’re done the original sports car is like an SUV. PHP-FPM is a way of running the PHP code in another process. Apache stays mean and lean and PHP does only what it needs to. Both scale well. Not only that but we can configure Apache to run multi-threaded and quicker and even lower memory! But that’s the second part of this post.
Let’s start!
First off, let’s configure PHP-FPM.
$ sudo nano /etc/php-fpm.d/www.conf
What you want to do is set things up like this:
listen = /var/run/php-fpm/php-fpm.sock
listen.owner = apache
listen.group = apache
listen.mode = 0664
user = apache
group = apache
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
(I’m leaving out the comments that start with “;” in this case)
What this sets up is a process that’s listening to a UNIX socket on /var/run/php-fpm/php-fpm.sock. This is like listening to an internet socket but a bit quicker.
We’re also setting this to run as the same user as Apache.
Last we’re making this max out at 20 PHP processors. If we’re running this on a bigger machine, you can scale this up.
Next, let’s start this up!
$ sudo chkconfig php-fpm on
$ sudo service php-fpm start
Starting php-fpm: [ OK ]
Now we have to get Apache to use this instead of the default way of running PHP.
$ sudo yum install httpd-devel apr-devel apr
$ cd /tmp
$ wget http://www.fastcgi.com/dist/mod_fastcgi-current.tar.gz
$ tar xfvz mod_fastcgi-current.tar.gz
$ cd mod_fastcgi-2.4.6/
$ cp Makefile.AP2 Makefile
$ make top_dir=/usr/lib/httpd/
$ sudo make install top_dir=/usr/lib/httpd
I’ll walk through what’s going on here.
- sudo yum … – Gets a few more packages
- cd – Change Directory
- wget – Download the latest fast CGI module
- tar – Extract the source code
- cd – Change directory into what just got extracted (you might need to change the version number depending on what’s latest at the time)
- cp – Copy the makefile so we’re using the right one
- make – Compile the module
- sudo make install – Install the module into Apache!
Next, we have to set up a directory for Apache to use.
$ sudo mkdir /var/www/fcgi-bin
$ sudo cp $(which php-cgi) /var/www/fcgi-bin/
$ sudo chown -R apache: /var/www/fcgi-bin
$ sudo chmod -R 755 /var/www/fcgi-bin
- mkdir – Make directory
- cp – Copy
- chown – Change ownership to Apache
- chmod – Change mode so only Apache can write to it.
Apache
Finally, we need to add an Apache config:
$ sudo nano /etc/httpd/conf.d/php-fpm.conf
Since this is a new file, just paste this in:
LoadModule fastcgi_module modules/mod_fastcgi.so <IfModule mod_fastcgi.c> ScriptAlias /fcgi-bin/ "/var/www/fcgi-bin/" FastCGIExternalServer /var/www/fcgi-bin/php-cgi -socket /var/run/php-fpm/php-fpm.sock -pass-header Authorization AddHandler php-fastcgi .php Action php-fastcgi /fcgi-bin/php-cgi DirectoryIndex index.php </IfModule>
This will load the module we just installed and point it at the socket that the fpm module is listening on.
Lastly, we need to unconfigure the old way of running PHP and restart Apache.
$ sudo mv /etc/httpd/conf.d/php.conf /etc/httpd/conf.d/php.conf-old
$ sudo service httpd restart
At this point you should go back to your browser and make sure things work. Things should. :-)
At this point we just need to configure Apache to use the multi-threaded way of running things.
$ sudo nano /etc/sysconfig/httpd
Just find the line that looks like
#HTTPD=/usr/sbin/httpd.worker
…and remove the “#” that comments it out.
Restart the service one last time and you should be good to go!
$ sudo service httpd restart
Next time, we’ll run some benchmarks against this! (I’ll also go into some of the details about what we just did with before and after benchmarks)
(Updated 2014-03-30 – Some of the configs for the PHP-FPM were jibbered)
Hi, thanks for the awesome step-by-step. It’s the best I’ve found online and I *really* appreciate it.
I did run into a snag w/this:
$ make top_dir=/usr/lib/httpd/
$ sudo make install top_dir=/usr/lib/httpd
I should say that I am dealing with a brand new EC2 instance (amazon linux) so some things may have changed but after TONS of digging I found that I have to issue the 64 bit specific command and what you’ve got may be related only to 32 bit. FYI here are the URLs I used in my research (taking into account I know NOTHING about unix/linux … just trying hit and miss things until stuff fell into place based on attempting to connect certain dots):
http://www.cyberciti.biz/tips/rhel-centos-fedora-apache2-fastcgi-php-configuration.html
http://www.fastcgi.com/archives/fastcgi-developers/2010-March/000487.html
So, basically, it seems as though your instructions need to be updated to reflect the following:
# yum install libtool httpd-devel apr-devel apr
then:
# sudo make top_dir=/usr/lib64/httpd
# sudo make install top_dir=/usr/lib64/httpd
Firstly, in your instructions the “_” from the first top_dir line is missing for those who may be typing it manually (even though it shows up when you copy/paste it, FYI). When I attempted “make top_dir=/usr/lib64/httpd” I received some “errors” in the output…..so I had to run it again as “sudo make top_dir=/usr/lib64/httpd” and got no errors….not sure why (again, I know nothing about unix/linux…..just that your instructions as posted didn’t work for me, giving me errors telling me I couldn’t build in that directory so I had to dig until I discovered the 64 bit issue which you refer to here [but it seems the instructions aren’t really updated?] http://blog.vec.com/2014/07/08/amazon-aws-upgrade/).
Sorry for the long post but this is complicated stuff and since I couldn’t get it to work I figured I might raise this w/you in case you can take a look and either update your instructions for future visitors or explain why the way I ended up doing it is wrong so that I can learn and/or update what I must….for what it’s worth, when I restarted httpd after doing it the way I ended up doing it, I got [ OK ] messages so I assume I am working properly but, really, who knows? :)
Yep, you are absolutely correct! When I was writing all this up I was playing with a 32-bit t1.micro instance that was then current entry-level instance. (A 64-bit t1.micro was around, but it was worse at most things)
This tutorial is probable due for a re-vamp with the newer t2.micro instance that AWS is pimping that are 64-bit only. Too bad I don’t get paid for this (Amazon pays me to do other things instead)! ;-) One of these weekends I’ll likely re-run the setup to see where things break.
Thanks, I’ll keep an eye on your blog and hope to see an update when you get a chance. As for rewards for your labor, I thought it was a labor of love and what more could you hope for than <3 ? Seriously though, I bet if you turned these into a series of YouTube videos you'd go far….views, ad revenue (and some fun trolling by those YouTuber kiddie coders) may be the type of reward you should consider. ;)
A few additional issues you may wish to hit on if/when you revise:
1. User/Group rights was a HUGE pain for me. I never got it to fully work. Following AWS (and your) instructions, I ended up w/apache as the user and www as the group, but once that was set up, anytime apache installed new WordPress files (such as a new theme or plugin) the ownership was auto set to apache / apache (ignoring the www group) such that I had to manually go in and SSH chmod the permissions in order to manipulate any files myself. I created a ticket/question here if you are interested: https://forums.aws.amazon.com/thread.jspa?threadID=174311&tstart=0
2. WP Super Cache broke my site (white screen of death, although if I hit refresh the page would load but after a few loads, white screen again) and I tried all setting types (HTACCESS / PHP / legacy) and no dice each time. Not sure exactly what the issue may have been and I didn't want to spend too much time investigating since I am not a programmer and it takes me SO LONG to solve such issues w/my traditional "surf the internet until you figure it out" method. Not sure if it worked fine w/32 bit and there is a specific issue w/64 bit that breaks things….something for you to check out!
3. During my investigation into this service, I played with the t2.micro instance (1 CPU/1GB RAM) and the t2.medium (2 CPU/4GB RAM) and found them both equally responsive and, if anything, the t2.micro being slightly more responsive (in terms of www access speed and overall performance loading pages against a mySQL DB)! Not sure why, but I guess that unless you have a tremendously busy server, you probably don't need anything larger than a t2.micro!
Items 1 & 2 above made this 3 day investigation on my part turn out convincing me that AWS EC2 is not yet ready for "prime time" meaning general enthusiast use (someone like me, not a hard core developer but an enthusiast who likes tinkering……..forget about the average person!). At the end of the day, if I have to stress about basic file permission rights not sticking and if basic [but important] plugins don't work w/o much stress, w/o an active community to assist in figuring stuff out, it's just not worth it unless you are hard core. :/ Hopefully that can change.