Apache Chroot Jail: Virtual Hosting

Now your chrooted Apache jail is ready. It is time to add domains using Apache virtual hosting features.

Our sample setup for two domains called theos.in and nixcraft.com is as follows:

  • Domain: nixcraft.com
  • JailDir ($J): /httpdjail
  • Domain configuration file: /etc/httpd/conf/vdomains/nixcraft.com.conf
  • DocumentRoot: $J/home/httpd/.nixcraft.com/http
  • Log Directory: $J/home/httpd/.nixcraft.com/logs

Virtualhosting settings for theos.in:

  • Domain: theos.in
  • JailDir ($J): /httpdjail
  • Domain configuration file: /etc/httpd/conf/vdomains/theos.in.conf
  • DocumentRoot: $J/home/httpd/.theos.in/http
  • Log Directory: $J/home/httpd/.theos.in/logs

Step #1: Create SKEL directory for our jail

Type the following command:
# mkdir /etc/httpd.skel
# mkdir /etc/httpd.skel/{http,logs,stats,subdomains,private}

Update httpd.conf for virtual hosting

Create /etc/httpd/vdomains directory, type:
# mkdir /etc/httpd/vdomains
Open httpd.conf file, enter:
# vi /etc/httpd/conf/httpd.conf
Make sure following line exists. Use name-based virtual hosting:

NameVirtualHost *:80

At the bottom of file add the following directive:

include vdomains/*.conf

Save and close the file.

Step #1a: Add user for nixcraft.com domain

Type the following commands:
# J=/httpdjail
# useradd -m -d $J/home/httpd/.nixcraft.com -k /etc/httpd.skel -s /sbin/nologin nixcraft
# chmod +x $J/home/httpd/.nixcraft.com

Step #1b: Add user for theos.in domain

Type the following commands:
# J=/httpdjail
# useradd -m -d $J/home/httpd/.theos.in -k /etc/httpd.skel -s /sbin/nologin theos
# chmod +x $J/home/httpd/.theos.in

Virtual hosting configuration for nixcraft.com

Create /etc/httpd/vdomains/nixcraft.com.conf file as follows:

<virtualHost *:80>
    ServerAdmin webmaster@nixcraft.com
    DocumentRoot "/home/httpd/.nixcraft.com/http"
    ServerName nixcraft.com
    ServerAlias www.nixcraft.com
    ErrorLog "/home/httpd/.nixcraft.com/logs/error_log"
    CustomLog "/home/httpd/.nixcraft.com/logs/access_log" common
    ScriptAlias /cgi-bin/ "/home/httpd/.nixcraft.com/cgi-bin/"
<directory "/home/httpd/.nixcraft.com/http">
        Options -Indexes FollowSymLinks +ExecCGI
        AllowOverride AuthConfig FileInfo
        DirectoryIndex index.php index.html
        Order allow,deny
        Allow from all
<directory "/home/httpd/.nixcraft.com/cgi-bin">
	AllowOverride None
	Options None
	Order allow,deny
	Allow from all

Save and close the file.

Virtual hosting configuration for theos.in


<virtualHost *:80>
    ServerAdmin webmaster@theos.in
    DocumentRoot "/home/httpd/.theos.in/http"
    ServerName theos.in
    ServerAlias www.theos.in
    ErrorLog "/home/httpd/.theos.in/logs/error_log"
    CustomLog "/home/httpd/.theos.in/logs/access_log" common
    ScriptAlias /cgi-bin/ "/home/httpd/.theos.in/cgi-bin/"
<directory "/home/httpd/.theos.in/http">
        Options -Indexes FollowSymLinks +ExecCGI
        AllowOverride AuthConfig FileInfo
        DirectoryIndex index.php index.html
        Order allow,deny
        Allow from all
<directory "/home/httpd/.theos.in/cgi-bin">
	AllowOverride None
	Options None
	Order allow,deny
	Allow from all

Save and close the file. Restart httpd, enter:
# /etc/init.d/httpd restart
You can automate the entire process using a shell or perl script which is left as an exercise to the reader.

🐧 Get the latest tutorials on Linux, Open Source & DevOps via RSS feed or Weekly email newsletter.

🐧 23 comments so far... add one
CategoryList of Unix and Linux commands
Disk space analyzersncdu pydf
File Managementcat
FirewallAlpine Awall CentOS 8 OpenSUSE RHEL 8 Ubuntu 16.04 Ubuntu 18.04 Ubuntu 20.04
Network UtilitiesNetHogs dig host ip nmap
OpenVPNCentOS 7 CentOS 8 Debian 10 Debian 8/9 Ubuntu 18.04 Ubuntu 20.04
Package Managerapk apt
Processes Managementbg chroot cron disown fg jobs killall kill pidof pstree pwdx time
Searchinggrep whereis which
User Informationgroups id lastcomm last lid/libuser-lid logname members users whoami who w
WireGuard VPNAlpine CentOS 8 Debian 10 Firewall Ubuntu 20.04
23 comments… add one
  • Janam Mar 23, 2009 @ 7:24

    Hello, I followed your tutorial in chrooting Apache and creating Virtual domains. However I have a problem. When I try accessing my website via the URL: http://mydomain.com/

    I’m getting an error as indicated below:

    “You don’t have permission to access / on this server.
    Additionally, a 404 Not Found error was encountered while trying to use an ErrorDocument to handle the request.”

    What could I have not done correctly? This seems to be a common problem with new Linux installations such as mine but I have failed to find a solution that matches my case.

  • Janam Mar 23, 2009 @ 14:39

    Thanks for the page. I had not seen it. Btw 1 question on the virtualhost config files shown above. Why doesn’t the path to the DocumentRoot not begin from the jail directory. I.e Why do we use “/home/httpd/.nixcraft.com/http” in the config file and not “httpdjail/home/httpd/.nixcraft.com/http” ?

    • 🐧 nixCraft Mar 23, 2009 @ 15:07

      / or /httpdjail is not accessible from the jail. Your /httpdjail becomes a new / directory and protects real / file system. So you need to use home/httpd/.nixcraft.com/http as path.

  • Janam Mar 23, 2009 @ 16:49


    I see. Then I can now understand why do not include httpdjail. Thanks alot.

    I have tried to follow the above instructions to the letter but I get the following on console when I restart httpd:

    Starting httpd: Warning: DocumentRoot [/home/httpd/.nixcraft.com/http] does not exist

    Then viewing the error log, I also found this:
    No such file or directory: httpd: could not open error log file /home/httpd/nixcraft.com/logs/error_log. Unable to open logs

    So it occurs to me that Apache attempts to read the DocumentRoot before it gets chrooted into the jail or something like that? Could these two pieces of information be pointing at some configuration problem?

  • Janam Mar 24, 2009 @ 6:24


    I finally got Apache to start up and everything works but I had to do change the logs directory and do a symlink to it. I think this is not yet a good solution enough but at least Apache starts and works fine. I am still combing this issue and I hope I shall share my solution once I am convinced I have one good enough.

  • Jeroen Mar 24, 2009 @ 18:35


    I had the same issues. After changing the log directories to the real path (/httpdjail/home/httpd/.theos.in/logs/*_log) it starts up buth with the warning that the directory /home/httpd/.theos.in does not exist. After that it works like a charm. Do we just have to ignore this warning, or is something not working as it should? I am using CentOS 5.2.

  • willi Jun 14, 2009 @ 22:32

    thank you for this howto.
    A few things to say:
    Please alter the Path in:
    Virtual hosting configuration for nixcraft.com
    Create /etc/httpd/conf/vdomains/nixcraft.com.conf file as follows:
    should be /etc/httpd/vdomains/nixcraft.com.conf
    so far I got it qithout errors /chroot is built and mod_chroot says it is happy chrooting.
    BUT the virtual domains path with /home… will not be reckoned by httpd.
    SELinux is off but auditd is on.

    Though I assume I’am not chrooted! Test with chroot without vdomains result in /var/www/html calls but not in {chroot}/var/www/html.

    Thank you for your help.

  • 🐧 nixCraft Jun 15, 2009 @ 5:33


    Thanks for the heads up. I’ve update tutorial. Let me know if you need any other help.

  • willi Jun 15, 2009 @ 5:43

    well yes my main problem is:

    from last posting:
    so far I got it qithout errors /chroot is built and mod_chroot says it is happy chrooting.
    BUT the virtual domains path with /homeÒ€¦ will not be reckoned by httpd.

    thank youi

  • xinobit Jun 30, 2009 @ 0:53

    But this doesn’t prevent a php script from reading a file in another virtualhost just by browsing the path. Is any solution for that? I mean a chroot for every virtualhost

    • 🐧 nixCraft Jun 30, 2009 @ 4:00

      You can chroot each jail or better use suexec which prevents reading other users files by UID.

  • Milan Cveetic Oct 18, 2009 @ 13:26

    apachectl -t

    Warning: DocumentRoot [/home/httpd/.nixcraft.com/http] does not exist
    Warning: DocumentRoot [/home/httpd/.theos.in/http] does not exist
    Syntax OK

    I did everything as written, do not know what the problem is

  • Arpad Mar 17, 2010 @ 14:49

    Hi, thanks for the tutorial.
    I’ve checked and overchecked everything. The settings are the same except from the chroot jail name. I have the same problem as others, it can’t seem to find the directories from the virtualhosts. If i use it without the virtualhost it starts normally and chroots the directory to /var/www/html (the chrooted not the real one). Where could be the problem?

    • Hal Wong May 18, 2010 @ 8:01

      This configuration did not work for me either however, I was able to get Virtual Hosting working by using the using the VirtualDocumentRoot directive instead. It works successfully inside the httpdjail.

      Here’s how to do it. If you have applied the above instructions and it didn’t work then you should do the following:

      Edit the Apache conf file:
      vi /etc/httpd/conf/httpd.conf

      First, comment out the NameVirtualHost:
      #NameVirtualHost *:80

      And comment out the vdomain directory lookup:
      #include vdomains/*.conf

      Then add (or uncomment) the following:
      VirtualDocumentRoot /home/www/%0/
      VirtualScriptAlias /home/www/%0/cgi-bin/

      Then Save and Exit.

      Now make the directories for all/any virtual hosts that you want:
      mkdir /httpdjail/home/www/www.example.com

      And give it the proper permissions
      chmod +x /httpdjail/home/www/www.example.com

      Then restart Apache:
      /etc/init.d/httpd restart

      If it comes up OK, then it should work. Test it out by placing an index.html in that new VirtualDocumentRoot directory that you just created and see if you can pull it up in a web browser. Keep in mind that you need to have the DNS entry already resolving to the box (OR you can modify your HOSTS file on your local system to manually direct to the webserver you are working on. More info: http://en.wikipedia.org/wiki/Hosts_file).

      If everything works then you can delete the /etc/httpd/vdomain directory, and the /etc/httpd.skel directory, and also the /home/httpd/.nixcraft.com and also remove the new users you created from /etc/passwd and back out all the changes from this page.

      Hope this helps.

      • drake Feb 25, 2011 @ 18:45

        hi it works:)

        Tell me sth:
        1. how can users access to chroot e.g to sent their own index.html (users dont exist in os)
        2. only access to chroot, got a root

        I Think, I don’t undrestand sth in that chroot…

  • pron Aug 25, 2010 @ 21:10

    tryed several manuals for chroot, but i always get next error :

    Warning: date(): It is not safe to rely on the system’s timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected ‘Europe/Berlin’ for ‘CEST/2.0/DST’ instead in /var/www/html/index.php on line 6 Fatal error: date(): Timezone database is corrupt – this should *never* happen! in /var/www/html/index.php on line 6

    it’s on fedora 13.

    again – always if i try to integrate mod_chroot, i get that error.

    if i “turn off” mod_chroot, i do have no problem.

    what could be the cause?

    • Hal Wong Aug 26, 2010 @ 7:30

      You need to make a copy the zoneinfo files into your jail so php can read them and understand the definition of all the timezones and internationalization settings.

      if your jail is in /httpdjail, just do this:

      cp -fR /usr/share/zoneinfo/* /httpdjail/usr/share/zoneinfo/

      • Janhouse Jan 9, 2011 @ 15:25

        Thank you!
        Took some time for me to find this comment. I knew that I had to copy something to jail but didn’t know what. πŸ™‚

  • A.Jesin Sep 27, 2010 @ 16:20

    Is there a PHP script available to add/edit/remove apache virtual host through the browser ?

  • bill Mar 22, 2011 @ 8:23

    hi guys .. this looks like an ok solution but does anyone know how to do this with the mod_chroot now included with apache2 since .10 release? it seems to me that the mod_chroot allows all of one directory to be in a jail but does not prevent virtual hosts from intruding into each other.

  • Mato Mar 1, 2012 @ 4:51

    I have the same problem as Milan and Arpad. Followed the previous instructions and these, but apachectl -t or restarting apache tells me that the /home/httpd/.mydomain.com/http does not exist. I also get errors in the global apache error log that the vhost logs file does not exist. Using Centos 5.7 with apache 2.2.3 and have turned selinux off temporarily. Hope someone has some advice.

  • inlink Aug 8, 2012 @ 16:34

    you can use mpm_itk. This isolates different virtual hosts from each other.

Leave a Reply

Your email address will not be published.

Use HTML <pre>...</pre> for code samples. Still have questions? Post it on our forum