Optimising the WordPress permissions

May 2017

WordPress, like all web based platforms, is subject to the virtues of its environment. In the usual cases, something like Apache or Nginx on a Unix-like server. As such, file and folder permissions form one of the foundations of its security.

Working in the web industry for over 18 years, I’ve seen more than my fair share of issues that have arisen from incorrect or insufficient permissions. The commonest of them being:

  • Not being able to write to a folder from within a CMS – This is probably one of the most common, as more often than not, a CMS is either uploaded or installed by a different user to the web server
  • Files being replaced by way of an exploit because the folder was completely writable, and worse yet…
  • Files being replaced by executable files (such as PHP) which then proceeded to wreak havoc on the web server (and sometimes on other sites in a shared hosting environment).

Generally you can help to avoid all three issues by ensuring that the permissions of files and folders are set optimally.

The advice from Automattic gives a short introduction on what permissions are, how they work, how to set them, and then continues by noting the optimal permission sets.

As you can see from the advice though, it’s not exactly black and white. There’s a good reason — web servers can be quite a minefield when it comes to generalised advice, and it’s hard to make a blanket statement when you know that your software runs on millions of different environments.

What makes matters more complex, is that WordPress can also update itself as well as edit its own themes through a UI. File & folder permissions in this case need to be especially permissive. Personally I don’t use either of these features, which means while I need to update manually, the site is that little bit more secure.

One part of the advice regarding writable access doesn’t sit well with me though — wp-content should be writable? What about the themes and plugins folders? Some of them too, but it’s generally up to the theme and/or plugin to tell you what. Generally though, cache and uploads should be writable.

Some developers took it upon themselves to create scripts which took care of this for them. One such script was written by Michael Conigliaro over 5 years ago. It would run through a WordPress installation and automatically revert permissions to a consistent state. It worked well enough, but I wasn’t entirely happy with how it treated wp-content: Everything was blanket writable by the web user.

I’ve created my own version with a few amendments. It does a couple of things slightly differently to the original script.

Firstly, after performing blanket standardising, it makes wp-content root writable by giving group to the web server:

chgrp ${WS_GROUP} ${WP_ROOT}/wp-content

Then, it allows the web server to manage the contents of wp-content, except for themes and plugins:

find ${WP_ROOT}/wp-content \( -path ${WP_ROOT}/wp-content/themes -o -path ${WP_ROOT}/wp-content/plugins \) -prune -o -exec chgrp ${WS_GROUP} {} \;
find ${WP_ROOT}/wp-content \( -path ${WP_ROOT}/wp-content/themes -o -path ${WP_ROOT}/wp-content/plugins \) -prune -o -type d  -exec chmod 775 {} \;
find ${WP_ROOT}/wp-content \( -path ${WP_ROOT}/wp-content/themes -o -path ${WP_ROOT}/wp-content/plugins \) -prune -o -type f -exec chmod 775 {} \;

If you want to try it yourself, feel free to grab the full gist and give it a go.

You’ll want to edit the WS_GROUP variable on line 23 if your web server runs under a different user, and if your FTP/SSH user is in a specific group (like staff, for instance), edit line 21 to that effect.

To run the script, simply make it executable with the following:

chmod +x wordpress-permissions.sh

And then it can be run like so:

./wordpress-permissions.sh [ftp-user] [/path/to/wordpress/root]

Where the path to your WordPress root would be the folder which contains the root index.php and wp-content.

For example, if you log into the server with the user wordpress-steve And your site’s public root is at /var/www/wordpress-steve/public_html then the command would be:

./wordpress-permissions.sh wordpress-steve /var/www/wordpress-steve/public_html

A word of warning: This script will (of course) overwrite existing permissions — if you have a very special setup with hundreds of carefully curated permissions, firstly, my condolences, and secondly, you may want to think twice before running the script.

Got any tips on making this even more secure or working better with existing plugins? Let me know below or in the gist comments.

Leave a Reply

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