Getting Mail from WordPress on Linux

I’ve mentioned previously that I’m running WordPress on my own web server on top of Linux, and that it took me some digging to get it to play nicely with SELinux. Turns out I don’t learn from old mistakes.

WordPress has this nice feature where it sends notifications about new comments, and comments held for moderation, to the admin account’s email address. Well, that never worked for me. That’s a problem: while it’s easy to regularly check the queue of held comments to approve those that are legit, new comments from readers who previously had a comment approved are not held, and can get lost quite easily. I’ve recently found a bunch that I should have answered months ago, but I never saw them.

And as before, the solution is easy once you know what you’re looking for: it’s SELinux again. In my sendmail log file, I found a bunch of these error messages:

NOQUEUE: SYSERR(apache): /etc/mail/sendmail.cf: line 0:
cannot open: Permission denied

Upon checking that file and finding it had proper permissions (read/write for user, read for group and other), I figured there would be some secret SELinux context that needed to be applied, and wondered why it wasn’t configured right by default. Turns out it’s different. SELinux also maintains a set of global flags, and there is one special flag that allows an HTTP server access to sendmail. Seems rather specific, that.

Anyway, to check whether apache (or any other web server) is allowed to send mail via sendmail, run

$ getsebool httpd_can_sendmail

which will reply either “on” or “off” (mine was “off,” big surprise). Then, to enable mail, run

$ setsebool httpd_can_sendmail 1

and voila. Now I’m getting email about comments, and about new users registering for my blog. Yay. As it turns out, there are a lot of new users registering for my blog. After deleting several thousand bogus ones, I’ve disabled user registration for now. Turns out there wasn’t a single registered user that looked legit. Oh well.

This probably means readers who tried to sign up for email notifications about new posts or comment replies didn’t get any either, but nobody ever complained, so I’m not sure. Anyway, it should work now.

Running WordPress on Linux

When I got talked into starting a blog, I decided I’d at least have some fun with it and install the blog software myself — after all, I’m already running a web server; why not use that? Should be easy, right?

Well, turns out it was easy, except one “little snag.” I could see the blog template, change settings, post and comment — but I couldn’t upload media. Some digging turned up that WordPress stuffs everything besides media into its underlying MySQL database, but media files are directly uploaded to the directory structure managed by the web server running the WordPress software. Whenever I tried uploading media, I got the dreaded “Unable to create directory – Is its parent directory writable by the server?” error message.

Now, being an old Linux hand, I blamed permission issues right away, and started doing the usual tests — find out under which user account apache and php scripts are run, chown the offending directory tree to that user, set proper permissions on that directory tree, all to no avail. I even tried the last-resort fix of making the entire wordpress directory world-writable (don’t try this at home), but even that didn’t work. And that had me stumped.

So I turned to Google, and found out that about 10 million other people had already run into the same problem. There were lots of proposed fixes, most of them bogus of course (use ftp to upload media; manually create a new uploads/<year>/<month> directory every month; make everything world-writable; disable your plug-ins; re-install WordPress; change hosting services; exorcise your server; do a rain dance, etc.). Not a single one of them worked, including the rain dance.

Now here was the actual issue: my web server is sitting on a modern Linux kernel, and if you know your stuff you know where I’m going with this: it’s running SELinux. And of course SELinux was the culprit. It turns out that apache runs under a very restrictive SELinux regime (as it should), and this regime makes all files underneath the root html directory read-only, no matter what the UNIX file permissions say. You can chmod 0777 to your heart’s content, it will make not an ounce of difference. But once you re-label WordPress’ upload directory to httpd_sys_rw_content_t, everything is peachy keen.

So why is this so hard? SELinux is not to blame; it’s doing exactly what it’s supposed to be doing. It’s running apache in the most restrictive way possible that allows it to run at all. Changing the label of a directory is a one-line command, and there’s even a man page (httpd_selinux) that explains what needs to be done. So why on earth did not a single one of the answers I found mention SELinux at all? (Of course, in hindsight, if you Google for “WordPress SELinux media upload” you get lots of good advice, but if you are already suspecting SELinux is involved, you don’t need to Google anymore).

I think the basic problem is that the fact that SELinux has completely changed the way UNIX does security has stayed under the radar for most people. UNIX file permissions are no longer the first line of defense against unauthorized file accesses. I myself completely forgot about SELinux while frantically trying to solve the problem; I only remembered it when I had already wasted a good part of a day. What I’m saying is, SELinux needs a really good PR campaign. Oh, and somebody needs to write a blog post containing the keywords “WordPress cannot upload images” and “SELinux” and “httpd_sys_rw_content_t” so that poor noobs like me will be able to find it on Google in the future. Oh, I guess I just did.

So here’s my solution, where /var/www/html/wordpress is my wordpress root directory, and apache is running as user apache:

  1. Chown the entire /var/www/html hierarchy to root:apache and make it readable for user and group only:
    • chown -R root:apache /var/www/html
    • chmod -R g-w,o-rwx /var/www/html
  2. Create (if it doesn’t already exist) and chown /var/www/html/wordpress/wp-content/uploads to apache:apache and make sure it’s user-writable (it should already be):
    • mkdir /var/www/html/wordpress/wp-content/uploads
    • chown -R apache:apache /var/www/html/wordpress/wp-content/uploads
    • chmod -R u+w,g-w,o-rwx /var/www/html/wordpress/wp-content/uploads
  3. Change the SELinux context of /var/www/hml/wordpress/wp-content/uploads to httpd_sys_rw_content_t:
    • chcon -R –type=httpd_sys_rw_content_t /var/www/html/wordpress/wp-content/uploads
  4. Optionally, make the change permanent, i.e., make it survive a complete file system re-label:
    • semanage fcontext -a -t httpd_sys_rw_content_t “/var/www/html/wordpress/wp-content/uploads(/.*)?”

Oh, and if you think my advice to make all of /var/www/html verboten for other is too restrictive, at least do the world a favor and make the WordPress configuration file, you know the one that contains your MySQL database’s admin password in plain text, yeah go ahead and make that one user- and group-only.

Ah hell, while you’re at it, just save yourself a lot of trouble and go ahead and read this.

Update: I finally figured out how to get notification emails from WordPress. SELinux was the problem again.