Per-directory configuration (.htaccess) in LightTPD
The frequent visitor of Diary Products knows that it runs on the LightTPD aka Lighty web server. The machine that hosts Diary Products is serving other sites as well so it needs to have some kind of virtual hosting mechanism in place. I use LightTPD's very straight-forward and easy to use mod_simple_vhost module. The only draw-back with LightTPD is that it doesn't support directory specific configuration files similar to Apache's .htaccess files. But this is not such a big deal for me because as much as I liked the convenience of .htaccess, I always considered it a waste of cycles and a security issue. The ideal solution in my opinion would be one which
- prevents me from having to modify the global /etc/lighttpd.conf file every time I add a virtual host,
- let's you put a LightTPD configuration file into a directory and somehow have its directives only apply to that particular directory and sub-directories therein
- is read only once at the start-up of the LightTPD daemon.
I've come very close to that ideal using mod_simple_vhost and LightHTP's include_shell inclusion mechanism. Just a quick reminder on how these work: The mod_simple_vhost module maps virtual hosts to directories based on the assumption that every virtual host's directory is named after the domain name of that virtual host. If a virtual hosts has additional domain names (aliases), there should be one symbolic link per alias pointing to the main domain's directory. The include_shell statement launches a custom program, most likely a shell script of some sort and parses that program's output as if it were a configuration file.
I wrote a Ruby script that
- scans the virtual hosts' directories for files called lighttpd.conf,
- reads those file and
- prints them to standard output from where they are parsed by LightTPD.
In order to make sure that the directives in each of these configuration file only apply to one particular virtual host, the script wraps the content of each file in a conditional. The script also supports a global configuration template which applies to all virtual hosts and in which the %dir%
string is replaced by the name of the current directory, i.e. virtual host. If you would like to use my solution with your LightTPD installation, here's what you would need to do:
- Enable the simple virtual hosting module by uncommenting the in corresponding like in your
lighttpd.conf
:
server.modules = ( "mod_simple_vhost",
- Configure the simple virtual hosting module based on you needs. Note that the actual content directory is not the virtual host's directory itself but the
htdocs
subdirectory thereof. This enables us to later add other virtual host-specific directories likecgi-bin
, a log directory and the like.
simple-vhost.server-root = "/home/virtual/" simple-vhost.default-host = "doodah.com" simple-vhost.document-root = "/htdocs/"
- Create the
/home/virtual/your-domain.com/htdocs
directories:
mkdir -p /home/virtual/your-domain.com/htdocs
- Place the following ruby code into
/home/virtual/vhost-lighttpd.conf.rb
:
#! /usr/bin/ruby -w confName = "lighttpd.conf" path = File.expand_path( File.dirname( $0 ) ) globalConfName = path + "/" + confName def readConf( conf, context ) if File.file?( conf ) File.open( conf, "r" ) do | conf | while line = conf.gets puts " " + line.gsub( /%(\w+)%/ ) { if eval( "local_variables", context ).include?( $1 ) eval( $1, context ) end } end end end end Dir.foreach( path ) do | host | if host != "." and host != ".." dir = path + "/" + host if File.directory?( dir ) puts "$HTTP[\"host\"] == \"#{host}\" {" readConf globalConfName, binding readConf dir + "/" + confName, binding puts "}" end end end
- Make that script executable:
chmod ug+x /home/virtual/vhost-lighttpd.conf.rb chgrp lighttpd /home/virtual/vhost-lighttpd.conf.rb
- Add the following line to
/etc/lighttpd.conf
:
include_shell "/home/virtual/vhost-lighttpd.conf.rb"
- Create host-specific configuration files:
# vi /home/virtual/your-domain.com/lighttpd.conf
- Adjust the permissions of that host-specific file. Note that the necessary specifications are highly dependent on your particular setup, so don't follow this step blindly. Use your brains. If you have separate user accounts for your virtual hosts or the lighttpd daemon, make sure neither the virtual host users nor the lighttpd account can write the configuration file or the directory that it's in:
# chown root:lighttpd /home/virtual/your-domain.com /home/virtual/your-domain.com/lighttpd.conf # chmod go-w /home/virtual/your-domain.com /home/virtual/your-domain.com/lighttpd.conf
- Optionally, create a template configuration file:
# vi /home/virtual/lighttpd.conf
Within that file, you may use the string
%dir%
. It will be substituted by the actual virtual host directory. For example,accesslog.filename = "%dir%/logs/access.log" alias.url = ( "/cgi-bin/" => "%dir%/cgi-bin/" )
will become
accesslog.filename = "/home/virtual/your-domain.com/logs/access.log" alias.url = ( "/cgi-bin/" => "/home/virtual/your-domain.com/cgi-bin/" )
Besides
%dir%
, you may also the names of other local variables between percent signs, e.g.%host%
(the name of the virtual host),%conf%
(the name of the host-specific configuration file) and%path%
(the virtual host root, same assimple-vhost.server-root
) . - Perform a dry run of the script by running it in your shell and closely examine its output.
- Restart LightTPD Depends on your distribution; on Gentoo do this:
/etc/init.d/lighttpd restart
# /home/virtual/vhost-lighttpd.conf.rb
I chose to write the script in Ruby because Ruby is very popular among LightTPD users as it is an excellent server for application based on the Rails framework which is written in Ruby. I also am generally interested in that language and wanted to get to know it a little better, "als erste Dehnübung, sozusagen." If you don't have Ruby installed, the script could easily be recoded in Perl. I might even do it for you if you ask nicely. Hint, hint ...