If Not True Then False

Nginx and PHP-FPM Configuration and Optimizing Tips and Tricks - Comment Page: 1

I wrote before a guide Howto install Nginx/PHP-FPM on Fedora 20/19, CentOS/RHEL 6.5/5.10, but this guide is just installation guide and many cases Nginx and PHP-FPM basic configuration is good enough, but if you want to squeeze all the juice out of your VPS or web server / servers and do your maintenance work little bit easier, then this guide might be useful. These tips are based entirely on my...
Categories:

152 Comments

Leave a Comment

Your email address will not be published. Required fields are marked *

Input your comment.
help

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Input your name.

Chris Cortese

I found my way here googling to get to your VirtualBox post (also well done). I’ve been using php-fpm and nginx for some years now and I do some of these things but some are new.

Very nicely done and well-presented. I just wanted to say thanks.

reply Reply
JR

Thanks Chris!

I have also used Nginx and PHP-FPM (earlier FastCGI) setup long time on my testing environments, now I’m gradually transferring all production web servers to use Nginx and PHP-FPM instead Apache and PHP. Nowadays Nginx and PHP-FPM is excellent choice for everyone who wants handle even massive traffic with good and cheap Virtual Private Servers (VPS). Some cases configuration is even easier than Apache configuration.

Very nice to hear that you found even something new on this guide and later I will add more tips, when I have some good ideas. ;)

reply Reply
Nader

Do I need separate linux users (useradd …) for this part:
user = site
group = site
?

Great tutorial, thanks! I have already setup a couple of things according to your post.

reply Reply
JR

Hi Nader and thanks!

This is just example to show how powerful PHP-FPM Pools are, so you could of course use existing users and groups, example nginx user and nginx group or apache user and apache group.

This example use totally separate Linux users and groups, because i.e. those pools users / groups access could be limited just their own directories. This is much more secure way if you have multiple totally separated sites. One site security issue does not affect whole system and other sites, because all sites are running by different users with very limited permissions.

reply Reply
Thomas

But any user/group defined in a PHP-FPM Pool must exist as a user account in Linux?

reply Reply
JR

Hi Thomas,

Yes, user and group must exist on Linux system.

reply Reply
Thomas

Which files must then be owned by this specific user defined in the pool?
Only the pool-configuration-file?
Or all files of the relevant service in /var/www (or /usr/share/nginx/www), e.g. ownclowd?
In other words: which files will be accessed by the user account defined in the pool-configuration?

THX

reply Reply
JR

Hi Thomas,

All files of the service (like /var/www/example1) must be owned by specific user. Configuration files are accessed/used only by PHP-FPM process.

reply Reply
Saif Bechan

Hi, great tutorial, I really love the setup here. I have one question tho, and it is also regarding users and security.

On this setup you have different users: site, forum, blog. These will be users with limited capabilities, with an eye on security.

Now my question is, how can you manage this in a real system. How would you go about on editing the files for the different users. If you have a user that you use to login, let’s says www-user, how can that user edit the files that are owned by users: site, forum, blog.

If you use a remote program that can not sudo such as winscp on windows then you are pretty much stuck I guess. Or is there a way around this?

I assume here that the users site, forum, blog do not have login permission.

reply Reply
JR

Hi Saif Bechan nice to see you here :)

Here, these users can be, for example two types. Users who have access only to the own directories without login permission or users who have the login permission only to the “chrooted system”, like virtual hosting setups.

If you want modify all those sites with www user then you something like following setup (this, is just theory / example):

1. Create users blog, site, forums with nologin

2. Create www user with login permission

3. Add www to blog, site and forums groups

4. Directory structure could look following:


drwxrwxr-x.  2 blog   www  4096 Dec 26 12:40 blog
drwxrwxr-x.  2 forums www  4096 Dec 26 12:40 forums
drwxrwxr-x.  2 site   www  4096 Dec 26 12:40 site

If I run multiple pools with different users, then I normally use root user to modify files. This is theoretical example, which I did on /tmp directory and permissions should work nicely… :)

reply Reply
Sam Barnes

I’ve been using a similar separate user per site setup for each of my python based sites and found your article whilst looking for a similar way to do this with php, thanks.

One nice trick is to use setgid on your site directories. If you use setgid on a directory all files and subdirectories inherit its group. So, my site specific directories are all owned by the www user with which I log in (meaning I can edit files without sudo) but setgid ensures all files have a group which is site specific.

mkdir site

# set owner to www & group to site
sudo chown www:site site

# make sure the group can write to the directory
sudo chmod g+w site

# setgid on the site directory
sudo chmod g+s site

It also helps to set your umask to 002 in your ~/.profile so that files you create group writable by default.

I’d be interested to hear your thoughts on this setup.

reply Reply
Ashraf Amayreh

Great post! Don’t forget to enable APC and memcache if you really want to get top speeds. You can also set a reverse proxy in nginx for PHP requests (which means nginx caching PHP requests if possible):

Inside location:

fastcgi_cache nginxcache;
fastcgi_cache_valid any 5m;

Inside http

fastcgi_cache_path /tmp/nginx_cache levels=1:2 keys_zone=nginxcache:50m inactive=1d max_size=400m;
fastcgi_cache_key “$scheme$request_method$host$request_uri”;

And by the way, maybe you should look into honeypot technique for preventing spam submissions :)

reply Reply
JR

Hi Ashraf,

Thanks for nice Nginx reverse proxy tip :) If you have time, you can write more detailed guide, with some full config on If !1 0 forums. I add link with description to your guide of course. :)

I am thinking of writing own instructions about APC, because it works of course also with other HTTP servers example with Apache. It’s not just Nginx and PHP-FPM related stuff. And I already have Memcache guide… :)

I actually have honeypot on forums section, but current technique is just totally zero spam technique, but yes I know, it might be irritating…maybe I should change it… :D

reply Reply
Dedi Lesmana

Hello,

I’m trying to run with nginxcp, how to create single account don’t want to use nginx

thanks

reply Reply
JR

Hi Dedi,

My apologies, but I do not quite understand your question? Could you try to explain more specific what you are trying to do and what is the problem?

reply Reply
DeltaHF

Great article, thanks for putting all these tips together!

One thing that’s not clear to me is how to direct a PHP application to actually use the PHP-FPM pools you’ve provided for it?

reply Reply
JR

Hi DeltaHF,

If I understood your question correctly…

When you create PHP-FPM pools, let’s say you have 3 pools pool1, pool2, pool3 which listens 127.0.0.1:9000, 127.0.0.1:9001, 127.0.0.1:9002:
1. Create virtual host where you pass PHP requests to pool1 (127.0.0.1:9000)
2. Create virtual host where you pass PHP requests to pool2 (127.0.0.1:9001)
3. Create virtual host where you pass PHP requests to pool3 (127.0.0.1:9002)
4. Create virtual host where you pass PHP requests again to pool2 (127.0.0.1:9001)
5. …

Did this answer your question? :)

reply Reply
DeltaHF

Thanks, JR! Yes, I was overlooking the address:port number defined by fastcgi_pass in the Nginx configuration file and I think that disconnect was confusing me.

I have a blog at / and a message board at /forum on my site. So, if I want the forum to run in its own PHP-FPM pool, would I define a unique fastcgi_pass in a location block like so (assuming the pool is already properly defined, of course)?


location /forum {
fastcgi_pass 127.0.0.1:9001;
..
}

Would this correctly override the “default” port defined in my general “location ~ \.php$ {…}” block as I would expect?

reply Reply
JR

You are welcome! :)

Yes, you could use this almost that, but you can’t override any default ports, so you have use little bit different setup…example something like following.

Separated php-fastcgi.conf file:


fastcgi_index   index.php;
include         fastcgi_params;
fastcgi_param   SCRIPT_FILENAME    $document_root$fastcgi_script_name;
fastcgi_param   SCRIPT_NAME        $fastcgi_script_name;

location /forum {
fastcgi_pass 127.0.0.1:9001;
include php-fastcgi.conf;
}

This is just idea how it could works (not working example)…normally I use different PHP-FPM pools only with different virtual hosts.

Please let me know if you need more help, or did you get idea? :)

reply Reply
Elaidon

Hi JR,

I try to use fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
but when I uncomment it in the browser I get 502 Bad Gateway.

What should I do?

Thank you!
Elaidon

reply Reply
JR

Hi Elaidon,

How is your PHP-FPM pool configured what you try to use?

reply Reply
Gray

Hi, Thanks for your blog post it is very informative.

I just want to ask one question. How can I set a timeout for the php processes? sometimes one of the php-fpm child is using too much cpu which makes my server unresponsive. Right now I am restarting php-fpm every hour using cronjobs. But is there a setting in nginx or php-fpm that can solve my problem?

reply Reply
JR

Hi Gray,

You can use PHP-FPM pool option pm.max_requests to limit max request per process.

Default value is 0 (unlimited), but if you setup it example some value between 50-500 then process stops when it’s handled example 200 requests.

reply Reply
N

I was having some problems with my WHMCS on a Fedora NGINX/PHP-FPM installation (based off your instructions). Turns out the PHP sessions directory /var/lib/php/session was owned by “apache” group (assuming an apache install). I had to chgrp apache /var/lib/php/session to get stuff working properly.

Might be worth mentioning somewhere that the php-fpm package-related perms have to be updated.

Other than that, great articles and tips. Can’t wait for them to be updated for Fedora 17! ;)

reply Reply
JR

Hi N,

Thanks for this info! :)

Yes I start test and updating all guides for Fedora 17 when Beta/Final is released… ;)

reply Reply
Android VPN

Thanks for your tutorial. Again its very useful especially nginx tip #5 and php-fpm tip #2

All my websites are using nginx + php-fpm + mysql so I can apply your tips on my servers.

:)

reply Reply
woody

Hi, Thanks for your guidelines. It is helpful.

Can you explain about the PHP-FPM Pools in more details..
PHP-FPM Tip 3. – PHP-FPM Pools Configuration

I followed your guidelines to create my second virtual host.
I name my 2nd host as forums & using different PHP-FPM pools, name forums

my conf files should be look like this?
Create the files from the /etc/nginx/sites-available/forums and under the server { } I put in,

location ~ \.php$ {
include /etc/nginx/fastcgi_params;
fastcgi_pass 127.0.0.1:9002;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/forums/public_html$fastcgi_script_name;
}

AM i right? is this configuration able to use the 2nd PHP-FPM pools?

reply Reply
JR

Hi woody,

Your configuration looks perfect! :D

Your PHP-FPM pool listen localhost port 9002 and then you pass requests to that port…yes you are right and it should use the 2nd PHP-FPM pools. :)

reply Reply
Ahmet

Thank you man. Successfully installed nginx. But php_cgi :) Does the difference?

reply Reply
woody

Hi JR, Thanks :)
I need your help to clarify the code below, kinda confuse about the code below,


location / {
index index.html index.htm index.php;
}


location ~ \.php$ {
include /etc/nginx/fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /srv/www/testsite.local/public_html$fastcgi_script_name;
}

The location / and location ~ \.php$
What is that actually means?
Besides that, how do we know, the php-fpm is running on every request from php?
Is there any tools to test?

Need your advice. :) really appreciate it ~

reply Reply
Karan

Hi JR ,

Thanks for the tips , i am going to try and implement these settings now on our server .

With the above mentioned settings and below mentioned hardware configs : what kind of load can the server take : approximately how many visitors a minute or per day :

CentOS 5.7
NGINX
8 Gb RAM ( my full ram keeps running out of memory with just 1000 visitors)

We went live for an hour this morning and we kept crashing with the following error:

Too many connections to php-fpm. Server is reaching pm.max_children value.

Then our server admins did a hard reboot on the server , and our drive started getting mounted on read-only mode.

And then we were forced to run a FSCK ! We are down 8 hours and counting right now.

Wish we could hire you as consultant to setup our system and let our admins maintain it time to time. If you are up for it , please hit us up on the email mentioned above.

reply Reply
JR

Hi Karan,

Do you run just Nginx and PHP-FPM on that server?

I think that 8 Gb RAM with good network connection and processor(s) should be enough to handle very huge amount of traffic.

Could you post output of following commands from your server (example to pastebin.com):


cat /proc/cpuinfo

cat /etc/nginx/nginx.conf

cat /etc/php-fpm.conf

cat /etc/php-fpm.d/*.conf

php -i

## when server running normally ##
ps aux |grep -e php -e nginx

free -m

grep -e WARNING -e ERROR /var/log/php-fpm/*.log

Let’s check first if I can help you just with seeing this info… ;)

reply Reply
JR

Thanks Karan,

Your server looks very good. :)

Actually Nginx configuration looks good to me (4 worker processes should be enough, but 8 is also okay with your server) and PHP-FPM need some configuration.

Let’s do some calculation…if you have 8 Gb memory and let’s use now 4 Gb for PHP-FPM. This is a rough estimate, but let’s say that your PHP-FPM processes use 66 Mb RAM (is not so much really I think) and you have 4 Gb RAM to use.
4096 / 66 = 62.06

Based on this theory, it should be safe to set:


pm.max_children = 62
pm.start_servers = 8
pm.min_spare_servers = 8
pm.max_spare_servers = 16
pm.max_requests = 250

And also enable following settings for PHP-FPM:


emergency_restart_threshold 10
emergency_restart_interval 1m
process_control_timeout 10s

I recommend you to backup your config before doing anything, if something goes wrong then you can very easy switch back to your original config… :) After config change remember restart PHP-FPM… :)

You can monitor your php processes with top, htop or even with following command:


watch -n 2 'ps aux |grep php'
reply Reply
Karan

HI JR ,

We noticed that our PHP-FPM processes is burning through at 300Mb+ each : here are the screenshots :
http://grab.by/cUnc
http://grab.by/cUng

as u can see we are running out of 8 GB ram pretty quick…not sure whats causing this issue

please let us know what do here – we are hosting an e-commerce shopping cart based on Magento.

Let us know.

reply Reply
JR

Hi again Karan,

Thank you for this information.

Actually VIRT is not right column to follow in this case. VIRT column represents how much memory the program is able to access at the present moment. All memory usage combined memory it has mapped into itself, files on disk that have been mapped into it and memory shared with other processes.

RES stands for the resident size, which is an accurate representation of how much actual physical memory a process is consuming. (and also %MEM column value is calculated directly from RES).

So RES is right / much better column to follow. Memory usage per process is therefore around 75-90 Mb (~1 percent of 8 Gb). Let’s calculate again:
4096 / 90 = 45.51

Based on this information I recommend to try following values then:


pm.max_children = 46
pm.start_servers = 6
pm.min_spare_servers = 6
pm.max_spare_servers = 12
pm.max_requests = 250

And


emergency_restart_threshold 10
emergency_restart_interval 1m
process_control_timeout 10s

You should definitely adjust these values​​, when you see the real situation.

However, the problem is indeed Magento, rather than the configuration of the server. Magento is just too large and too heavy to any environment. Magento hosting is really tedious and unpleasant task.

Please let me know if these values ​​work, or if you have problems?

reply Reply
Karan

Thanks JR ,

Seems some improvements.

Please see below :

Cpu(s): 11.6%us, 3.6%sy, 0.0%ni, 84.8%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 8163952k total, 3282776k used, 4881176k free, 375324k buffers
Swap: 4192956k total, 0k used, 4192956k free, 1316412k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
27992 apache 16 0 340m 80m 41m R 40.3 1.0 0:07.54 php-fpm
27985 apache 15 0 334m 73m 40m S 16.0 0.9 0:14.53 php-fpm
27984 apache 16 0 338m 77m 40m S 2.7 1.0 0:04.81 php-fpm
5114 mysql 15 0 1534m 708m 5996 S 2.0 8.9 226:07.99 mysqld
27991 root 15 0 12760 1176 828 R 0.3 0.0 0:00.32 top
1 root 15 0 10320 688 580 S 0.0 0.0 0:00.68 init
2 root RT -5 0 0 0 S 0.0 0.0 0:00.00 migration/0

Few days back my total memory went right upto 7.5 GB and there was only a free memory of 500-700 MB

Then i typed this command to clear cache
sudo sync
sudo echo 3 | sudo tee /proc/sys/vm/drop_caches and i had 6 GB free. Do you know how do i limit this cache. It seems to be eating up all the memory on the server, if i dont regularly flush it.

Do you think this heavy caching could be caused by varnish cache / APC cache etc?? is there anyway i can limit this.

reply Reply
JR

You are welcome!

Actually ~3.2 Gb used from 8 Gb looks very low, normally Linux use ~90 % all available memory. So that 7.5 Gb / 8 Gb is much more normal and better situation.

Do you have Varnish running and PHP APC installed on this server?

reply Reply
Karan

Hi JR,

Varnish Cache was running, we disabled it after the server crashed thinking we needed to save some memory or the cache was being put on the memory and thus crashing the server. APC is enabled on this server.

Few mins back we were again not able to access the server. I guess my server guys were running a stress test on the server. They gave me back with these details.
Total transferred: 2976410 bytes
HTML transferred: 240762 bytes
Requests per second: 96.36 [#/sec] (mean)
Time per request: 10377.283 [ms] (mean)
Time per request: 10.377 [ms] (mean, across all concurrent requests)
Transfer rate: 28.01 [Kbytes/sec] received

Kindly suggest what do you advice.

Thanks again for all the help provided.

reply Reply