March 3, 2015
FastCGI PHP_VALUE settings leaking to other sites on NGINX with PHP-FPM
The information in this post is based on NGINX 1.4.6 and PHP-FPM 5.5.9 running on Ubuntu Server 14.04 x64. It may or may not be valid for other versions.
I was recently setting up a new website on a server that had a couple of other sites on it already. The server and all of the sites on it are owned and controlled by me, so even though it has multiple virtual hosts, I don’t really consider it a “shared hosting environment” as such.
More or less by chance, I suddenly noticed that the new site had some PHP settings that were certainly not default. On one of the other sites, I have a virtual host defined as an admin area where I’m allowed to bulk upload large files, so the PHP settings regarding file uploads and max POST size had been increased for the relevant location in that virtual host using the fastcgi_param PHP_VALUE directive – or so I thought, because it was now apparent that these settings were leaking and polluting other sites. I assume the same leak occurs if using fastcgi_param PHP_ADMIN_VALUE instead, but I haven’t actually tested it.
Specifically, the following PHP settings were increased for this location: post_max_size, upload_max_filesize, max_file_uploads, and max_input_time. Also, NGINX’s own client_max_body_size was increased to the same as PHP’s post_max_size.
While having way too high max POST size and upload size for publicly available areas is certainly not optimal, it’s not a huge security issue either (attackers could potentially attempt to exploit it to deplete resources on the server by posting massive requests) – but other settings I might have set could have been, so I’m glad I found out about this on something fairly innocent.
It seems that the issue stems from the passed options getting applied to the PHP-FPM child process that happens to process the request and then remain there while that process lives, which can be for quite some time as one of the major performance improvements in PHP-FPM over traditional PHP execution is that each process handles multiple requests, so the entire engine doesn’t have to be started for every request.
After doing some research it is still unclear to me whether this is a bug, normal behaviour, or just an error in my setup. I have seen people claiming all three. The problem was completely reproducible to me, though – restarting PHP-FPM would return the settings to default, but as soon as I’d visited the virtual host with the special settings, those settings would start appearing on other sites on the same server. Regardless, the important part is how to fix it.
After some further research and experimenting, it appeared to me that the only reliable way of fixing it was to divide the virtual hosts into separate PHP-FPM pools so that they would not share child processes. Many people will tell you that you should be doing that anyway for security reasons; while I can see both pros and cons here, I’m inclined to think they’re right based on my experiences with this problem.
I have decided to split the description of how configure separate PHP-FPM pools into a separate post, which you can read here.