Apache document root in users home directory with SELinux

Serving web-content from a user’s home directory allows the user to conveniently upload files. By default, the apache configuration in many Linux distributions assumes content is uploaded to a single directory owned by the webserver’s user, but it might be useful to allow a user to upload his own content to a special subdirectory of his home directory. To allow this SELinux and its default rulesets need to be configured accordingly, too.

The idea to provide the user with a directory to upload his webcontent is not new. This means there is a already known pattern of how to do it. Especially with SELinux in place, following those patterns causes less modifications to the SELinux ruleset.

Prepare the user

The first step is to prepare the user and the user’s home directory. Creating the user on the server can be done with the adduser(8) command. Depending on you needs, add the necessary arguments. To use all the system’s defaults, run the command just with the username.

[root]$ useradd webuser

This will create the user “webuser” and a matching user-group “webuser” on the server and a home directory at /home/webuser/. Inside the user’s home directory, the subdirectory for the web content can be created. I suggest switching to the “webuser” and following the pattern of creating the directory with the name “public_html” as this name is known to be used for this purpose.

[root]$ su - webuser
[webuser]$ mkdir ~/public_html/

A quick check for the SELinux context of the created directory already reveals some details about this well-known pattern. The “-Z” option shows the SELinux context of the users home directory and all its files and directories.

[webuser]$ ls -alZ
drwx------. webuser webuser unconfined_u:object_r:user_home_dir_t:s0 .
drwxr-xr-x. root    root    system_u:object_r:home_root_t:s0 ..
-rw-r--r--. webuser webuser unconfined_u:object_r:user_home_t:s0 .bash_logout
-rw-r--r--. webuser webuser unconfined_u:object_r:user_home_t:s0 .bash_profile
-rw-r--r--. webuser webuser unconfined_u:object_r:user_home_t:s0 .bashrc
drwxrwxr-x. webuser webuser unconfined_u:object_r:httpd_user_content_t:s0 public_html

The SELinux context of the “public_html” folder was automatically set to “httpd_user_content_t” instead of “user_home_t” which is used for the rest of the user’s home directory. This is because the public_html directory is a well-known directory used for web-content.

[webuser]$ restorecon -r ~/public_html

The above command can be used if the SELinux context of the “public_html” and / or its content is not as expected “httpd_user_content_t”. This situation can happen, for example, if content is moved to the directory instead of copied. The SELinux context remains unchanged when moving files or directories but is not copied over if a file or directory is copied.

Prepare the webserver

The webserver needs to be configured to use the user’s “public_html” directory. This can be done by configuring the document-root of a virtualhost to the “public_html” directory of the user or by using the userdir module. This module allows to reaching the user’s “public_html” directory via a HTTP request to the “/~webuser/” path.

The following assumes the apache document-root is configured to the user’s “public_html” directory. To allow the apache user for the webserver to access this directory, the public_html directory needs the correct rights.

There are two possibilities to allow apache to access the public_html folder. The directory access can be changed to allow “others” read and execute rights on the user’s home directory and the “public_html” directory. These very open permissions might cause other side effects and are not recommended. The suggested method is to add the user’s group as a secondary group to the apache user and grant the group permission (read and execute) for the public_html and home directory.

[root]$ usermod -a -G webuser apache

The above command adds (-a) the group “webuser” as secondary group (-G) to the user apache. This will allow the apache daemon to access the user’s home directory via the group permission. To allow access for the group, change the permission for the home and public_html directory.

[root]$ chmod g+rx /home/webuser
[root]$ chmod g+rx /home/webuser/public_html

Allow access via SELinux

Before the webserver can access the public_html directory of the user, an SELinux boolean with the related rules needs to be enabled. This boolean enables the rules allowing access by the apache daemon to the public_html directory. The “-P” option in the setsebool(8) command will make the change persistent.

[root]$ setsebool -P httpd_enable_homedirs true

Testing the setup

As the apache configuration was changed as well, the webserver daemon needs to be restarted. In case of CentOS 7, via systemd.

[root]$ systemctl restart httpd

To verify the access to the public_html, create an index.html file in the users public_html directory with some content.

[webuser]$ echo "*** TEST ***" >/home/webuser/public_html/index.html

Now this file can be requested via a webbrowser or just from the command line via curl.

$ curl http://127.0.0.1/
*** TEST ***

Alternatively, the telnet(1) command can be used to communicate with the webserver.

$ telnet 127.0.0.1 80
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
GET /
*** TEST ***
Connection closed by foreign host.

When the telnet connection is established, type “GET / ” and press enter to retrieve the content. The result should show the content of the test file that was created earlier.


Read more of my posts on my blog at https://blog.tinned-software.net/.

This entry was posted in Security, Web technologies and tagged , , , . Bookmark the permalink.