If you’re managing a WordPress site primarily through the browser, there’s a good chance you don’t ever have to think about permissions once your initial setup is in place. Your server has write permissions to your wp-content
directory and that’s that. If you need to make changes, you do so using the Web interface, so no conflict arises.
Even then, though, you may occasionally see an error like “Directory /var/www/yoursite/somedir is not writable.” Usually, this is generated by a plugin which wants to dabble in some custom location. If you’re really lucky, the plugin will go on to suggest something dastardly like “Please make the directory world writable: chmod 0777 /var/www/yoursite/somedir“. Do not be tempted. Making directories or files world-writable is highly risky.
Things go wrong more often if you are managing your WordPress site on the command line. This is because your Web server runs as one user (often apache) and you run as another. Without configuration, you are likely to hit conflict. If you have generated wp-content
via a git clone, then the Web server may not be able to write to the uploads
directory. If you then change the ownership of the directories and files to accommodate the server, you may find that you no longer have the privileges to add a plugin or a file. Generally, then you use sudo (that, is run the command as root) which leaves you with a confusing hybrid environment – writable by root, but only partly writable by the server.
What we need to do then, is organise ownership such that both you AND the server can read, write and execute. I can do this by creating a Unix group that both my user and the Web server can share.
I start by adding a group called webshare
$ sudo groupadd webshare
Next I associate both my user – mattz
and the server’s user apache
with the webshare
user.
$ sudo usermod -a -G webshare mattz
$ sudo usermod -a -G webshare apache
Time for a quick confirmation that something happened.
$ cat /etc/group
...
webshare:x:507:mattz,apache
Yep, that confirms both that webshare
exists and that users mattz
and apache
are members of the group.
We are not done yet though. Three more issues to solve. First of all just sharing a group is not enough – we need to make sure that all files and directories in wp-content
are associated with that group.
$ sudo chgrp -R webshare site/wp-content/
Secondly just belonging to a group is not enough, directories and files must be confirgured so that they can be written by anyone beloning to the webshare
. Most of the time you will find files and directories are writable at the user level rather than the group level. We can use chmod
to change that:
sudo chmod -R g+rwx site/wp-content/
We can see whether this works by listing site/wp-content
from the commandline:
$ ls -al site/wp-content/
total 20
drwxrwxr-x 5 mattz webshare 4096 Dec 10 05:07 .
drwxrwxr-x 4 mattz mattz 4096 Dec 6 18:51 ..
drwxrwxr-x 4 mattz webshare 4096 Dec 10 06:22 plugins
drwxrwxr-x 6 mattz webshare 4096 Dec 10 04:07 themes
drwxrwxr-x 3 apache webshare 4096 Dec 8 19:27 uploads
That’s what I hoped to see. drwxrwxr-x
tells me that:
drwxrwxr-x These are directories
drwxrwxr-x That can be read/written/executed by mattz
in some cases, and apache
in one case.
drwxrwxr-x They can be read/write/executed by anyone in group webshare
.
drwxrwxr-x They can only be read and executed by anyone not already covered (the world)
Since I run as mattz, and the server runs as user apache – this would seem to cover it.
Not quite so fast, though. I changed every file and directory to be group writable with my recursive command. But what about additions?
Here is an edited version of current state of my uploads directory:
$ ls -al site/wp-content/uploads/2016/12/
total 5384
drwxrwxr-x 2 apache webshare 4096 Dec 8 19:27 .
drwxrwxr-x 3 apache webshare 4096 Dec 8 19:27 ..
-rw-rwxr-- 1 apache webshare 23405 Dec 8 19:27 lizard-100x100.png
It’s the new fuzzy shared world. These files are owned by the apache
user, but they also belong to the webshare
group. That means I can work with them on the command line if I need to. Let’s do a quick upload and see what the directory looks like.
So, I have uploaded the file ten.jpg
. Now here is another edited version of the upload directory listing.
$ ls -al site/wp-content/uploads/2016/12/
total 5628
drwxrwxr-x 2 apache webshare 4096 Dec 11 15:54 .
drwxrwxr-x 3 apache webshare 4096 Dec 8 19:27 ..
-rw-rwxr-- 1 apache webshare 23405 Dec 8 19:27 lizard-100x100.png
-rw-rw-r-- 1 apache apache 180671 Dec 11 15:54 ten.jpg
The new file uploaded OK. But look at that group. The file belongs to the apache
. Since I don’t belong to that group, I am at least partially locked out from working with it:
$ rm site/wp-content/uploads/2016/12/ten.jpg
rm: remove write-protected regular file `site/wp-content/uploads/2016/12/ten.jpg'?
I should be able to get round this by recursively setting the group sticky bit for groups on all directories in wp-content
and that’s where this article was serenely heading. Annoyingly there is an issue with the way that PHP and WordPress handle file uploads with regard to the sticky bit so I’ll need to return to this issue after some further research! Onward.