Featured image for Why your web server can't write to its files

Why your web server can't write to its files

Explainer

More often than not, when a site won't save something, it isn't the code. You set it up, everything looks right, and then the media library won't upload a file, or an update won't install, or something can't write to its cache folder. The error just says permission denied. And what's usually behind it is file permissions: who owns the files, and what the web server is actually allowed to do with them.

It's one of those things that took me a fair bit of research and hair-pulling to get straight years back, so here's the plain version.

Who is www-data?

Your web server doesn't run as you. It runs as its own user on the system, and on most Linux setups that user is called www-data. So every time someone visits your site, it's www-data doing the work: reading the page templates, saving an uploaded image, writing to a cache file. All of it happens as www-data, not as the account you log in with.

And that's the whole source of the confusion. If www-data isn't allowed to touch a file, then your site can't touch it, no matter how right the code is.

Who owns the files?

Every file and folder on the server has an owner and a group. For a website, you generally want both set to www-data for the parts of the site the server needs to write to.

# hand the site directory over to the web server user
sudo chown -R www-data:www-data /var/www/your-site

The -R just means "and everything inside it too". Once www-data owns the files, it can read them, and where the permissions allow, write to them. That's what lets the media library save an upload, or a plugin write its cache.

What do 755 and 644 mean?

This is where people tend to glaze over, so let's keep it simple. Permissions come as three digits, like 755. Each digit is for a different audience: the owner, then the group, then everyone else, in that order. And the digit itself is just read, write and execute added together, where read is worth 4, write is worth 2, and execute is worth 1. So a 7 is all three (4+2+1), a 5 is read and execute (4+1), and a 4 is read only.

For a website, the pair you want is 755 for folders and 644 for files:

# folders: owner can do the lot, everyone else can look but not change
sudo find /var/www/your-site -type d -exec chmod 755 {} \;

# files: owner can read and write, everyone else read only
sudo find /var/www/your-site -type f -exec chmod 644 {} \;

One thing worth knowing: folders need that execute bit (the 5, not a 4), even though you're not running anything. On a folder, "execute" just means allowed to go into it and look inside. Take it away and the server can't get into the folder at all.

So why can't the server write?

Here's where the head-scratching usually kicks in. Under 755 and 644, only the owner gets to write. The group and everyone else are read only.

So if your files are owned by root, or by your own login, while the server is running as www-data, then www-data falls into the "everyone else" bucket, which is read only. The upload fails, the update fails, and the error says permission denied, even though the numbers look perfectly sensible.

More often than not, the fix is ownership, not the numbers. Hand the folders it needs to write to over to www-data, and 755/644 does exactly what you wanted all along. It's tempting to just set everything to 777 (everyone can do everything) to make the error disappear, and it will disappear, but now anyone who gets onto that box can rewrite your site's files. Best not.

Hiding the config files

One more worth doing while you're in there. Config files, the ones holding your database name and password, shouldn't be readable by everyone on the server. On WordPress that's wp-config.php.

# owner and group can read it, nobody else gets a look
sudo chmod 640 /var/www/your-site/wp-config.php

640 means the owner can read and write, the group can read, and everyone else gets nothing. Since www-data is both the owner and the group, your site reads the file fine, but some randomer who's wandered onto the server can't open it up and help themselves to your database password.

That's really all it is. The web server is just another user on the machine, and it can only get at what it owns or what it's been let at. So if something won't save, don't go straight to the code; check who owns the files first. That's usually where the answer is.

file permissions · www-data · chmod · chown · permission denied · Linux · Apache · WordPress · LAMP