Configuring an Apache Jail with Jailkit in CentOS-6.x and 7.x

Jailkit is a nice, Linux application, that enables you to easily create a chroot environment. It's written for Debian, and as the author says, one might have to make some adjustments for a non-Debian or Debian based system. While its docs do go into decent detail to set up a jailed ssh shell, setting up apache proved to be a bit more problematic. In this case, I just wanted a simple apache server--no cgi, no special scripts, just serving up straight html pages like this one.

Jailkit is available as an rpm though it may take a bit of searching. Try pkgs.org. In my case, when I last used it, for CentOS-7, I found it at the Lux repo. The pkgs.org page is here. I just clicked the download link, got the rpm and installed it with rpm -ivh.

Note that somewhere in the jailkit docs, they say it's necessary to disable SELinux. This hasn't been the case in my experience. It's worked without SELinux issues for me in CentOS 6 and 7 without any SELinux policy modification.

Eventually, on CentOS-7, it interfered with a python update or another, so I just rebuilt it from source. It was very straight forward, I downloaded the package, untarred it, and after cd-ing into the directory, ran ./config make and sudo make install. It continued to use the configuration I had been using with the rpm. (Which also saves your jk_init.ini with an rpm save suffix, so I just moved that back to jk_init.ini after installing the source version.

The first thing to do, once it's installed, is to edit the /etc/jailkit/jk_init.ini file. It won't work properly as it is. I like to first copy it with
cp jk_init.ini jk_init.ini.orig

This guards against mistakes. Next, edit it with your favorite text editor. First create an ldconfig section, otherwise, trying to create jails with the command won't work.
[ldconfig]
executables = /sbin/ldconfig
regularfiles = /etc/ld.so.conf

Next add this to any sections you will use. I won't reproduce the file here, suffice it to say it has sections for uidbasics, netbasics, logbasics, and many others. You can actually add the following to all the sections, it won't hurt anything.
includesections = ldconfig

When a section has other items in the include section line, just add it at the end. using a comma to separate it. For example, the basicshell section has includesections = uidbasics. Change this to read
includesections = uidbasics, ldconfig

Depending upon what you want from your server, you can include or exclude (by commenting out with a # ), various sections. However, when creating jails, even if a section is not commented out, one has to specifically name that section, as explained below.

The jailkit homepage does have a few examples, such as a chroot ssh. The fewer things that you put in the jail, the better, but there are various essentials. This is where the documentation fell short for me, and why I've created this page. Unlike the FreeBSD jail, Linux-Vserver, and OpenVZ all of which contain a compete, if minimal, operating system, and then use system tools to install apache inside the jail, one either copies over binaries and other necessary files during setup, or else uses the jk_cp command, which we'll cover below.

The default apache instance in the jk_init.ini file is insufficient. It reads
[apache]
comment = the apache webserver, very basic setup, probably too limited
for you
executables = /usr/sbin/apache
users = root, www-data
groups = root, www-data
includesections = netbasics, uidbasics

As the author mentions, it's too limited. It's also apparently based on Debian systems. I changed mine to read
[apache]
comment = the apache webserver 
executables = /usr/sbin/apachectl,/usr/sbin/httpd
users = root, apache
groups = root, apache
regularfiles = /etc/mime.types
directories = /etc/httpd, /var/www/html, /var/lock/subsys, /var/log/httpd
includesections = netbasics, uidbasics, editors, basicshell, ldconfig
devices = /dev/urandom, /dev/null

If you don't bring over /var/lock/subsys, and /var/log, httpd will refuse to start. We'll also need /var/run, but we'll create that in the jail, as copying it over would bring other things we don't want.

Lastly, we need the devices urandom and null for it to work. I also edited my editors section, which included nano, joe and vim, so that it just included vi. I could have done without the editors section, and probably without the basicshell, editing the jail from without, but this way, I can do it while already in the jail. The important notes here are that I've changed the group and executable name from what I assume are their Debian versions, changing the excutable apache to CentOS' httpd and the default group from www-data to apache.

Now that this has been done, the jail can be created. The website gives an example using /home/testuser, in this case, we'll just create a /home/apache directory. Much of this will have to be done as root with su - or you'll run into problems with the ldconfig command. I found, that even as a user with /sbin in their $PATH, running it with sudo would give an error that ldconfig wasn't found. So, note the space and hyphen after the su - which puts you in root's environment. (See my page on paths for more explanation). I never figured out why it didn't work--googling only indicated that one should have /sbin in their $PATH, but, as mentioned, even doing that didn't work.

We will create the directory, change its ownership to root:root and its permissions to 755.
mkdir /home/apache
chown root:root /home/apache
chmod 0755 /home/apache

Now we can start putting things in it.
jk_init -j /home/apache apache

You will see it copying multiple files into the jail. If you have an existing /var/www/html (or whatever path you may have specified) it will copy that as well.

Otherwise, you can populate your /var/www/html directory. From outside the jail, just copy it into /home/apache/var/www/html. To be sure of permissions being correct, with any suid's being removed, you can use jk_cp. The command is also useful if you've forgotten something. For example, if you forgot to add /dev/null, and now you see that apache won't start because of that, use jk_cp.
jk_cp -j /home/apache /dev/null

First one specifies the jail with the -j option and then the file to be copied. The command is even more useful if one has forgotten an essential binary, as it will, in theory at least, copy over any libraries that the binary needs.

The file or directory being copied must be in the same place on the host that you want it to be in the jail. For example, if I have my html files in /home/scott/html and then use the jk_cp command with jk_cp -j /home/apache /home/scott/html, it will create a /home/scott/html directory in the jail, rather than in /var/www/.

Also, create your /var/run directory in the jail, either from outside the jail or while in it. From outside the jail it can be done with

mkdir /home/apache/var/run

To enter the jail, type
chroot /home/apache

The command is chroot /home/<jaildirectory>

You'll be presented with a root prompt. From there, in CentOS-6x, you can start apache, assuming you've already edited your httpd.conf file, with
apachectl start

To stop it, one can use apachectl stop or apachectl graceful-stop.

CentOS-7

In CentOS-7, this gave me an error that /usr/bin/systemctl wasn't found. So, I used jk_cp as we've mentioned.
jk_cp -j /home/apache /usr/bin/systemctl

However, that may not have been necessary. At some point I'll have to check. With CentOS-7 and systemd, if one runs apachectl, they get a message, unable to connect to D-Bus, operation not permitted. As near as I could determine, this has to do with systemd. While researching the problem, I found that this error is common with Docker,and is usually caused by people using systemctl, rather than httpd itself. So, in CentOS-7, once it's all prepared, and you've done chroot /home/apache the command should be
httpd -k start

It can be stopped or gracefully restarted with httpd -k stop and httpd -k gracceful.

As mentioned, one tries to keep a jail minimal. If we try to use service httpd, one not only needs /etc/init.d/httpd, but also /etc/init.d/functions, and a few other things such as basename and env.

Also, for me, at least, in the chroot jail, service httpd stop would fail for no apparent reason. I did find a bugzilla entry about it, but it seems to be relatively uncommon, so I probably missed something. Regardless, apachectl works without problems.