I setup LEMP (Linux, Nginx, MySQL, and PHP) on a Ubuntu 10.04 server from Linode with the following guide: http://library.linode.com/lemp-guides/ubuntu-10.04-lucid
Essentially, I uploaded my PHP scripts to a directory (/srv/www/mysite.com/public_html
) specified in /etc/nginx/sites-available/mysite.com.conf
.
Visiting the site in the browser gives me a 500 Internal Server Error. I assume there's some error with the PHP code, which is fine. However, I'm totally lost in terms of how to debug this, because there are several components: PHP, FastCGI, and Nginx.
My question is, how do I get those errors to display in the browser, or at least in a log so I can figure out what's going on? I'm not sure if I need to tell Nginx to log errors somewhere, or FastCGI, or edit php.ini.
I have full root access to the server to solve this. However, I'm not sure how to restart PHP/FastCGI (although I know how to restart Nginx), since the guide I followed uses some kind of daemon.
Thanks a ton for any help you can give me.
Best Answer
Short answer:
The most likely scenario is that you have a slight misconfiguration in Nginx which results in the incorrect path being sent to PHP-FPM. Ensure that your root directive is outside the location block, turn on
fastcgi_intercept_errors
, increase the verbosity of your error_log (e.g. to notice) and consult those logs for more information.Long Answer - Diagnosing the problem
Firstly, I am not an Ubuntu person (more of a CentOS one) - so you'll forgive me if a few paths/packages are not quite as specific to your operating system as would be ideal.
As you said, you have multiple parts to your setup that must work together.
For this approach to diagnostics, we want to keep things simple - don't test it by trying to load a CMS like Wordpress - we want one single independent file.
Test Files:
Static - let's go with a text file called 'test.txt'.
test.txt:
PHP - let's go with the phpinfo() function.
test.php:
Testing Nginx:
If Nginx can serve a static file, we can confirm that the basic setup and software is functional.
A few points of mention:
Copy 'test.txt' into '/srv/www/mysite.com/public_html', ensure that it is readable by the user 'nginx' (which is the default user nginx runs as), permissions of 644 should be sufficient. Ensure that all directories above public_html have 'execute' permissions for 'other' (i.e. 'other' can traverse the directory structure).
Restart Nginx for the configuration changes to take effect (you could reload instead of restarting, if desired).
Test from the same server you have nginx setup on:
The notable points here:
Ideally, the above command will return 'Hello world' - the text you entered into your text file.
PHP:
It is fairly easy to ensure that PHP works right:
Create the file 'test.php' (as above), in your public_html folder and run:
You should get a long output that contains all of the information you normally see in on a phpInfo() page.
If the above doesn't work:
display_errors
on and increase the verbosity of error_reporting in your php.ini file (firstly, find the right php.ini file, by usingphp -i | grep 'Loaded Configuration'
)Hopefully by now you have confirmed that PHP, and your simple test file, works.
PHP-FPM:
Unfortunately, FastCGI does not 'speak' plain text. We need an interpreter to help us here. You need the
cgi-fcgi
binary. (On CentOS it is available in the package 'fcgi', from EPEL; I believe Ubuntu has a packagelibfcgi
that provides the same).cgi-fcgi
reads environment variables and will pass the correct request to our FastCGI process manager (PHP-FPM).Firstly, let's setup PHP-FPM: The default global options should mostly suffice, however, enable logging - when debugging, we want as much information as we can get our hands on (the default log prefix is /var).
Setup a basic pool, specifying:
(Of course, you can - and probably should, use a socket instead of a TCP listener, but I find this approach is easier to test (i.e. fewer permissions problems) - obviously, ensure that there is nothing else listening on the port you choose). We need to permit only the local machine to access it, setup the basics of the process manager, and give the pool an owner (of course, you will change things to suit your needs later on).
service php-fpm restart
will work (usereload
instead if you ever need to do this in a production environment). (There may be an init script for it in /etc/init.d)Run the following:
Here we are telling PHP-FPM the path to the file, and the filename, as well as the request type (GET), and then instructing cgi-fcgi to connect to the right host and port.
It should return you the same output you got before, but this time, instead of using the php binary directly, it used FastCGI. If this works, you have successfully validated each component of your setup.
If you get errors, check your error log at /var/log/php-fpm.log
Putting it all together: If each part of the setup works, then, you need to ensure that all the parts can work together. Really, there is only one part left here - getting Nginx to communicate via FastCGI.
In its simplest form, we need to only add a single location block to our existing nginx server block:
To support this, the file 'fastcgi_params' is rather essential. The really important lines are:
You can actually include the FastCGI directives you need directly inside the location block - but I find having the external file is far simpler to maintain when you get more complex setups. You'll note here, that the path depends on $document_root - if you don't have that set correctly (the root directive), outside your location block, you will usually run into problems with your setup.
Some setups may also need a line such as:
One helpful directive for debugging FastCGI setup errors is
fastcgi_intercept_errors On
. This will let let errors (such as file not found, etc) be logged by nginx.Finally, try loading your PHP page through nginx:
Hopefully you get your phpinfo() output. If not, you know that the problem is in your nginx setup (because, every other component works on its own) start checking your nginx error logs, you should have more than enough information logged at this point to identify the problem.