Relocating an Apache DocumentRoot under Selinux

Selinux works pretty well straight out of the box, but I have learnt that when application reconfigurations mysteriously result in failures to startup – then Selinux is generally the culprit. In particular, if any file locations are customised from what’s installed, Selinux will lock it down, and for the uninitiated, the debugging process can be quite confusing. Apache webserver (HTTPD) provides a good example of what happens in this scenario, and I’ll demonstrate how to make it work with the Document Root in a different location.

Selinux can be distinctly daunting for Linux sysadmins, and often seems to be more trouble than it’s worth. However it is an extremely powerful tool which increases security and encourages rigour in configuration. Essentially, Selinux augments the usual Unix file permissions and ownership by adding more granular application-specific contexts as well. I won’t go into the details here, as it’s well documented elsewhere.

What I’ll aim to show here is two ways for relocating the Apache DocumentRoot directory – the proper way, and a quicker dirtier way.

Say, you decide to situate the Apache webserver root under /home/apache/www instead of the default /var/www/html. You edit the /etc/httpd/conf/httpd.conf and change the DocumentRoot line to:

DocumentRoot /home/apache/www

Copy your HTML files into place, change the directory and file onwerships, and permissions:

# chown -R apache. /home/apache/www
# chmod 755 /home/apache/www
# chmod 644 /home/apache/www/*

(NB: That’s not a typo – you can type “apache.”, with the dot at the end, in chown rather than “apache:apache” and save yourself a few keystrokes).

Restart httpd to make sure, and browse to your web page. You’ll get something like this in your browser:

You don't have permission to access / on this server.

And in /var/log/httpd/error_log:

[client] (13)Permission denied: access to /index.html denied

This is because the Apache back-end process, running as user “apache”, can’t access the file /home/apache/www/index.html – even though we granted all the correct permissions. What gives? Turns out, with Selinux, having regular old permissions and ownership isn’t enough.

Here’s how you can fix this, nice and quickly.

First things first, check that you’ve got Selinux running, and that this is in fact the source of your problem:

  # getenforce

Yep. Next, check the Selinux context of the original HTTPD DocumentRoot directory. The ls command has the “-Z” switch which displays this:

# ls -ldZ /var/www/html
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 /var/www/html

Take note of the colon-delimited string “system_u:object_r:httpd_sys_content_t:s0″. Take note of this string; you’ll need it later. Each field is:

  • User: system_u
  • Role: object_r
  • Type: httpd_sys_content_t
  • Level: s0

Checking the Selinux context on our new erroneously configured folder, we see this:

# ls -Z file1
drwxr-xr-x. root root unconfined_u:object_r:default_t:s0 /home/apache/www

So this explains why Apache can’t read the index.html file – it’s got the wrong Selinux context for Apache to read it. You can see how this enhances security. Apache can never server up a page unless it has explicitly got a context set that matches Apache privilege.

To reset the directory and file contexts, you need to ensure that the semanage software is installed (it may not be, depending on what package groups you have):

  # yum whatprovides */semanage
  # yum -y install policycoreutils-python

A very full discussion of how to change Selinux policies and file contexts is given here, but briefly, the steps are:

  # semanage fcontext -a -t httpd_sys_content_t "/home/apache/(/.*)?"
  # restorecon -Rv /home/apache
restorecon reset /home/apache context unconfined_u:object_r:var_t:s0->system_u:object_r:httpd_sys_content_t:s0
restorecon reset /home/apache/www context unconfined_u:object_r:var_t:s0->system_u:object_r:httpd_sys_content_t:s0
restorecon reset /home/apache/www/index.html context unconfined_u:object_r:var_t:s0->system_u:object_r:httpd_sys_content_t:s0

The semanage argument “/home/apache/(/.*)?” is a regular expression indicating the context should apply to the directory “/home/apache” and everything under it. Yes you need to do this for the home directory as that stays in user_sys_content. Unless you change that the https will still complain.

Quick and Dirty Fix
If, however you don’t have access to the semanage program or if you just need to make a small ad hoc change to a file context, you can simply set this manually. Remember that string coloured red earlier? Grab the relevant text from it.

  # chcon -R -u system_u -t httpd_sys_content_t /home/apache/

This command uses the “-R” switch so will apply recursively to all files under the directory. Note that the difference between this command and the semanage command is that chcon will not update the Selinux policy.

So the proof of the pudding will be in the reloading. Ctrl-R your browser and BOOM! Your page is back and being happily server up.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s