WordPress upload/upgrade permissions with group ownership

I have to maintain a few WP blogs for clients. It’s not a package I overly enjoy working with. Sure, it does the job pretty well and is hugely popular, But there is something about it that I just find to be a bit…cloying.

One issue I’d not looked into in any great depth before was file ownership. I’ve worked around the issue of permissions before by using a Makefile like this, and just fixing the permissions as required:

HTTPD_GROUP=www-data
### Configure file and directory permissions
fix_permissions:
	sudo chown $(HTTPD_GROUP):$$USER -R ./
	find . -type d -print0 | xargs -0 sudo chmod 770
	find . -type f -print0 | xargs -0 sudo chmod 660

It’s not particularly tidy or exceptionally safe, but it works. Then today I was helping someone out on IRC and I found myself wondering why this is necessary. All WP needs to be able to do is to write to /wp-content. This should do it, but it doesn’t work. Hence the above fix.

cd /var/www
sudo chmod 770 -R wordpress
sudo chown root:www-data -R wordpress

So digging a little deeper, it turns out that when something is done through Dashboard that requires a filesystem write (like downloading a new theme to install), a temporary file is created in the WP root directory to see if it’s writeable. Then the uid for the owner of the new file is compared with the owner of the running script. If they’re the same, the download proceeds. If they’re not, Dashboard redirects to the screen asking for FTP login details. Irrespective of whether wp-content is writeable or not!

The problem here is in wp-admin/includes/file.php which uses getmyuid(). This actually returns the uid of the owner of the currently running script, not the uid for the owner of the process the script is running under. So when WP root is chmod root:www-data, the uid for the script owner is 0 for root, even if the script is running as www-data (Apache2 under Ubuntu here).

#870
		$temp_file_name = $context . 'temp-write-test-' . time();
		$temp_handle = @fopen($temp_file_name, 'w');
		if ( $temp_handle ) {
			if ( getmyuid() == @fileowner($temp_file_name) )
				$method = 'direct';

The better function here would be posix_getuid() which returns the uid of the owner of the process the script is running under, but Windows doesn’t support this and WP is multi-platform.

There’s a long-standing bug in the WP trac for this one with suggested approaches, but no fixed resolution. However there is a work-around, and it does feel like a work-around to me. But it works and it enables the WP directories to be chown root:www-data. Simply add this anywhere to wp-config.php

define('FS_METHOD', 'direct');

Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>