Two separate PHP-FPM sites seem to be using the same code?

I have two websites with two codebases, yet when I change one codebase, I see the change in both.

I have two checkouts of the same website. They are set up to use PHP-FPM through Apache2 with FastCGI. The checkouts are in:

/var/www/site1
/var/www/site2

The Apache configs look like this:

<VirtualHost *:80>
    ServerName site1.myserver.com
    DocumentRoot /var/www/site1
    <IfModule mod_fastcgi.c>
        AddHandler php5-fcgi-handler .php
        Action php5-fcgi-handler /php5-fcgi-uri
        Alias /php5-fcgi-uri fcgi-application
        FastCgiExternalServer fcgi-application -socket /var/run/site1-fpm.sock -pass-header Authorization -idle-timeout 30000 -flush
    </IfModule>
</VirtualHost>

<VirtualHost *:80>
    ServerName site2.myserver.com
    DocumentRoot /var/www/site2
    <IfModule mod_fastcgi.c>
        AddHandler php5-fcgi-handler .php
        Action php5-fcgi-handler /php5-fcgi-uri
        Alias /php5-fcgi-uri fcgi-application
        FastCgiExternalServer fcgi-application -socket /var/run/site2-fpm.sock -pass-header Authorization -idle-timeout 30000 -flush
    </IfModule>
</VirtualHost>

The FPM pool configs look like these:

[site1]
user = site1-user
group = site1-group
listen = /var/run/site1-fpm.sock
listen.owner = www-data
listen.group = www-data
chdir = /
pm = ondemand
pm.max_children = 5
pm.max_requests = 500 ;default to unlimited

[site2]
user = site2-user
group = site2-group
listen = /var/run/site2-fpm.sock
listen.owner = www-data
listen.group = www-data
chdir = /
pm = ondemand
pm.max_children = 5
pm.max_requests = 500 ;default to unlimited

I am not using the chroot feature of FPM (as far as I can tell).

When I change the code for site1 and restart PHP-FPM and visit site1 and site2 then I see the change on both sites.

If I restart PHP-FPM and visit site2 first (the unchanged site), followed by site1 then I don't see the change on either site.

What is wrong with my configs? I do see separate PHP-FPM processes running for site1 and site2 under the main FPM master.


When I've seen similar issues in our environments, it appears to have been because of the way that OpCache (by default) shares a single cache across all users on a shared hosting environment. A bug has been submitted (and you can, and should, go and vote to let the maintainers know how important this might be for your use case) though no commitment has been made on delivering a fix.

TL;DR : By default when OpCache is enabled, the cache that is used to store compiled byte-code is shared across all users. In an environment where hosting is shared between multiple sites / users, this can result in a site grabbing the cached output of php scripts from another site or, if specific security settings are enabled even generating errors.

If you plan on using PHP-FPM with PHP 5.5+'s built in opcache, please read the blog post below before you actually do that. Turns out that the opcode cache can be read by any user on the server. This means that if there are say, 10 separate users, with their own vhosts and directories, and you configure one PHP-FPM pool per user, each user can still see what scripts are cached and their locations. Since they have read access to the cache they could potentially view all this data.

This is obviously a massive security concern, and even if no one exploits this, there is still a chance of scripts being read by the wrong user when generating a page, so websites could possibly be displaying the wrong data / info if there are multiple index.php scripts in the cache.

Although no fix has been officially released, if you're using cPanel, this wiki has a documented way of configuring the php-fpm pools to be created and secured on a per-user basis and if you follow the instructions below as well as the IMPORTANT NOTES at the bottom of this answer you should be able to get the functionality you desire without any errors

That post also documents how you might configure this by hand on a per-site/per-user basis (though I'd wager that might become tedious if you're hosting a lot of sites). If you're not using cPanel, you may need to modify the scripts to specify your individual paths and usernames instead of the variables being used by cPanel's config engine.


IMPORTANT NOTES

During testing and additional research I came across this article which provide a few clarifications that may be relevant to your specific situation:

  1. You need to make sure that the opcache.use_cwd parameter is set to true for your application's configuration of OpCache - it's set to false by default and leaving it set to default will probably cause collisions if you're hosting more than one PHP application on your system:

First of all, probably in each typical project you will have to ensure that the opcache.use_cwd option is set to true. Enabling this setting means that the OpCache engine will look at the full file paths to distinguish between files with the same names. Setting it to false will lead to collisions between files with the same base name.

  1. If you're running an application powered by Zend Framework or another similar framework that makes use of annotations, you ALSO need to ensure that the opcache.load_comments and opcache.save_comments directives are set to true. You should double-check this suggestion with your application / framework documentation as most have now updated their docs with specific instructions on enabling the use of OpCache properly for their systems:

There is also a setting that is important in tools and frameworks that make use of annotations. If you use Doctrine, Zend Framework 2 or PHP Unit, remember to set the opcache.load_comments and opcache.save_comments settings to true. In result, the documentation comments from your files will also be included in the precompiled code generated by OpCache. This setting will allow you to work with annotations without any disruptions.

If your project is based on a specific framework or a web application, it’s always a good idea to check the documentation for any guidelines regarding the OpCache configuration

IMPORTANT NOTES


Hopefully this helped - and if you're using cPanel, drop a comment to let us know how you tackled that portion of the configuration!