Nginx and php-fpm – ‘File not found’

Ran into this issue briefly when moving a blog over to a Centos 7.2 cloud box.

File not found.

Nginx was running as user ‘nginx’, and that user had full ownership of all web files. Logically, everything should have run fine with 700 permissions, but it wasn’t.

cat /etc/passwd

showed a user named ‘apache’. Why would that user exist on a system that had never had Apache installed?

Ahhhhh… php-fpm. The default php-fpm user is ‘apache’ – I guess just assuming it will be installed alongside apache is easier than trying to figure out how to have the webserver and php-fpm run in the same group or something.

Edited /etc/php-fpm.d/www.conf to set php-fpm’s user and group to ‘nginx’, then did

chown -R nginx.nginx /var/www/webroot
chmod -R 500 /var/www/webroot
chmod -R 700 /var/www/webroot/wp-content/uploads

Now the blog runs fine and permissions are as tight as possible without breaking things (so far lol).

Disabling PHP on a per-directory basis

Any PHP web application that allows uploads, by necessity, is going to need to vary permissions on a per-directory basis (unless you want to just save a hacker some work and make the directories that contain code files writeable by the webserver). Magento needs to be able to write to ./var, ./media, and also ./app/etc if you want to run the installer.

The ./media/ directory is an exceptionally temping gap in the application’s armor, because files there are also web-accessible out of necessity. That means if an attacker can manage to write a code file there, they can then execute it at will by simply requesting the file in a browser or sending an http request another way.

One of the easiest and most effective countermeasures against this method of attack is to simply block php execution in directories that should not contain php files. While it’s tempting to use an .htaccess file (.htaccess files in themselves kind of suck for both security and performance but that’s a diatribe for another day), there is a high risk of an attacker just overwriting it with a new, looser .htaccess file.

Instead, use the following in your Apache virtual host file (test these first, they’re tweaked snippets I found online but they look about right)

<Directory /media>
    <FilesMatch "(?i)\.(php|phtml)$">
        Order Deny,Allow
        Deny from All

… or your nginx config file

location ~* /media/.*\.(php|phtml)$ {
    return 404;

That should block any files with .php or .phtml file extensions in the directory from being parsed. You might want to do the same for ./var/, depending on the installation – the preferable action is to hide ./var/ from the web completely, but some installs with import/export extensions and other 3rd party code require allowing some access.

Debugging Magento Routing

Magento’s choice of configuration (via XML) over convention is part of what makes the system so awesomely flexible and extensible. The downside is that it also has a tendency to lead to those ‘WTF’ moments when you know you’ve done *something* wrong, but you have no idea *what*.

Having some background on Magento’s routing system is super helpful in the situation where you’ve created a controller and a route, but for some reason your controller is not being used and you’re getting an unhelpful 404 page instead of whatever functionality you’re expecting. The meat of the code that handles request routing in Magento can be found at ./app/code/core/Mage/Core/Controller/Varien/Router/


In the case above, it can be useful to refer to the standard router in Standard.php, specifically the match() method. This contains the bulk of the logic that tries to match a URL to a module, controller, and action. You can dump or inspect the contents of $this->_modules, or just the local $modules, to view the modules Magento has registered, and $p to see how Magento has broken the URL parts up.


It can also be helpful to dump and do a search on the global config object – I wrote a super simple free extension to do just that.