MigratingFromApache » History » Revision 44
Revision 43 (hoffie, 2012-05-16 21:57) → Revision 44/51 (hoffie, 2012-08-11 10:42)
h1. Migrating from Apache to lighty [[PageOutline]] h2. Configuration Basics Lighttpd is a great option as a replacement for existing apache or apache2 systems. If you are seriously considering migrating, read the documentation for the configuration file [[lighttpd:Docs_Configuration|Docs:Configuration]]. [[lighttpd:Docs:Configuration]]. The configuration syntax initially has the most significant learning curve, but you will see its flexibility once you familiarize yourself with it. One of the most powerful features of the lightttpd configuration is its *conditionals*. Lighttpd allows you to setup configuration options based on the clients' request. Conditionals can be nested, so you can create some very complex, yet effective configuration options. Conditionals are the key to many solutions which people encounter when migrating from apache/apache2. Here are some examples: *Problem*: I want to disable directory listing for directory /download: Entry in Configuration file: <pre> ####### Enable dir listing for all directories dir-listing.activate = "enable" ####### If the URL is like ^/download/ then disable dir-listing $HTTP["url"] =~ "^/download/" { dir-listing.activate = "disable" } </pre> You should familiarize yourself with regular expressions to truly become familiar with conditionals. You will use conditionals in your configuration file(s) for a multitude of things. Authentication, URL Rewriting, Virtual Hosting, and many more. All the variables you can use in conditionals are listed here along with further explanation about the match operators [[lighttpd:Docs_Configuration|Docs:Configuration]]. [[lighttpd:Docs:Configuration]]. ''' Problem''': You want the status page to be available just for users from the local network: Entry in configuration file: <pre> $HTTP["remoteip"] == "10.0.0.0/8" { status.status-url = "/server-status" } </pre> And here is a nested example. *Problem*: If the host is www2.example.org and the directory is /download enable directory listing: <pre> $HTTP["host"] == "www2.example.org" { server.document-root = "/var/www/servers/www2.example.org/pages/" $HTTP["url"] =~ "^/download/" { dir-listing.activate = "enable" } } </pre> For more conditional examples read: * [[HowToRedirectHttpToHttps]] * [[HowToRedirectWww]] * [[HowToAuthenticationFromMultipleFiles]] ----- h2. Basic Options <pre> Options +FollowSymLinks </pre> becomes <pre> server.follow-symlink = "enable" </pre> h2. Accesslog Accesslogs are written by mod_accesslog and support the same options in <pre> accesslog.format = ... </pre> as Apache. If you need logfile rotation use one of two ways: * "logrotate":http://iain.cx/src/logrotate/ as it is used in debian package * "cronolog":http://www.cronolog.org/ h3. logrotate If you don't use the debian package copy ./debian/lighttpd.logrotate to /etc/logrotate.d/ logrotate will send lighttpd a SIGHUP when it is time to rotate the logs and lighttpd will reopen the logs accordingly. h3. cronolog With cronolog you pipe the accesslog to a pipe and let a external program handle the logfile writing: <pre> accesslog.filename = "|/usr/sbin/cronolog /web/logs/%Y/%m/%d/access.log" </pre> Please note that this does not work for server.errorlog h2. mod_rewrite "mod_rewrite":http://www.lighttpd.net/documentation/rewrite.html is more difficult as the implementation of how the rules are written is completely different. First of all, we always match on the full relative request-uri that is submitted by the user. That means we can emulate apache's QSA flag (query string append; see "mod_rewrite in Apache":http://httpd.apache.org/docs/mod/mod_rewrite.html) by matching on the query string and adding it back to the target: <pre> url.rewrite = ( "^/something/(\d+)(?:\?(.*))?" => "/index.php?bla=$1&$2" ) </pre> The important thing is (?:\?(.*))? which matches on the query string and is inserted in the target url using $2 (the query string [[part|after ?]] is the second matching bracket pair; ?: makes the brackets non-capturing, i.e. the content is not available via $x as we don't need it). The following example is based on a problem from http://dir.onlinesearch.ws/ sent in by dbird@freenode. [[Note|link is inactive as of January 24, 2007.]] <pre> RewriteEngine On RewriteBase /instadir/ RewriteCond %{REQUEST_FILENAME} -d # Fix trailing slash problem RewriteRule ^(.+[^/])$ $1/ [R,L] # Do not try to treat the following resources as parameters to index.php RewriteRule ^index\.php.*$ - [L] RewriteRule ^dmoz\.css$ - [L] RewriteRule ^admin[/]?.*$ - [L] RewriteRule ^img[/]?.*$ - [L] RewriteRule ^[/]{0,}(.*)$ index.php?area=browse&cat=$1 [QSA,L] </pre> These rewrites want to rewrite everything that is not the index.php, dmoz.css, admin-interface or something from the image-directory to a parameter of the index.php page. The base directory for this match is ''/instadir/''. <pre> ## for all URLs in /instadir/ that are not index.php, dmoz.css, admin or img, do ... url.rewrite-once = ( "^/instadir/(?!index\.php|dmoz\.css|admin|img).*" => "$0", "^/instadir/([^?]*)(?:\?(.*))?" => "/instadir/index.php?area=browse&cat=$1&$2") </pre> The first pattern is using regex-magic called "zero-width negative look-ahead assertion":http://search.cpan.org/dist/perl/pod/perlre.pod#Extended_Patterns and is something from the advanced chapters of your "regex book":http://www.oreilly.com/catalog/regex/. h2. mod_fastcgi If you have 2 extensions assigned to the fastcgi handler in Apache like <pre> AddType fastcgi-php .php .phtml </pre> then you need two entries in the fastcgi.server config: <pre> fastcgi.server = ( ".php" => (( "bin-path" => "/my/fastcgi-php", "socket" => "/path/to/php.socket" )), ".phtml" => (( "socket" => "/path/to/php.socket-0" )) ) </pre> The first entry will create the php-fcgi process and the second will reuse the same socket. If you need to use PHP and Python in the same setup, just add two extensions: <pre> fastcgi.server = ( ".php" => (( "bin-path" => "/my/fastcgi-php", "socket" => "/path/to/php.socket" )), ".py" => (( "host" => "127.0.0.1", "port" => 3200 )) ) </pre> For this setup python was spawned externally and is a waiting for requests at port 3200, localhost. h2. !MultiViews How to setup a similar mechanism to the "Apache's MultiViews option":http://httpd.apache.org/docs/2.0/content-negotiation.html ? Fortunately, "Christian Hoffman":http://hoffie.info wrote a "lua script":http://files.hoffie.info/static/lighttpd-multiviews.lua to do that. Here is how to use it : <pre> server.modules = ( "mod_magnet", ) server.document-root = "/var/www" magnet.attract-physical-path-to = ( server.document-root + "/multiviews.lua" ) </pre> h2. Directory !ForceType Migration There are several PHP packages and tutorials that use the apache ForceType directive instead of mod_rewrite. They use it as a _Search Engine_ friendly way to pass arguments as fake directories. Let say you have this setup: * Your script is called _news_ (note no php extension) * Your URLs look like /news/100/ (/news/_id of the news_) * Your script grabs $_GET!['PHP_SELF'] to determine the news id and apache is configured with a Location or LocationMatch entry like this: <pre> <Location /news> ForceType application/x-httpd-php </Location> </pre> The easiest way to migrate this is: * First setup PHP with lightty and make sure .php extension is working * Rename filename _news_ to _news.php_ * Use a lighttpd rewrite to replace the Forcetype entry In lighttpd configuration file: <pre> url.rewrite-once = ("^/news/.*" => "/news.php") </pre> If your script is still not working, try to replace $_GET!["PHP_SELF"] with $_GET!["REQUEST_URI"] You can find it usually at the top of the script. PHP does not register PHP_SELF correctly when running in FastCGI. h2. Pretty URLs (or '.php' script auto-detection) I had a problem after migrating in duplicating my old Apache1.x + PHP setup had '''http://server.com/script/blah''' happily running ''script.php_ with arguments _/blah''. This is really useful for easily making pretty URLs. I couldn't see an easy solution to replicate this behaviour, or any entries in the docs here, so I decided to share my findings. Essentially there are two ways to go about replicating this in a semi-generic way so that you don't have to recode / rename your actual scripts. If you were happy to rename you could probably make things work using lighttpd's forcetype support. h3. mod_rewrite solution This is the one I picked because it's faster and seemed neater. Basically I added <pre> include "mod_rewrite.conf" </pre> ... and then created that file with the contents ... <pre> url.rewrite-repeat = ( "/script/(.*)" => "/script.php/$1" ) </pre> I guess you can also do this in a semi-generic way by naming each script: <pre> url.rewrite-repeat = ( "/(script|script2|script3)/(.*)" => "/$1.php/$2" ) </pre> h3. 404 handler solution This is probably minutely slower but may be a better idea if you have more complex (ie: not pure regex) considerations in your URL rewriting. You can also replicate the regex above using PHP preg_match(). Just add: <pre> server.error-handler-404 = "/404.php" </pre> ... then write your handler in that file. h2. !ScriptAlias <pre> $HTTP["host"] == "example.com" { alias.url = ( "/bin/" => "/path/to/my/bin/" ) $HTTP["url"] =~ "^/bin" { cgi.assign = ( ".pl" => "/usr/bin/perl" ) } } </pre> the above works. but i have another version that i thought it should work but don't : <pre> cgi.assign = ( ".pl" => "/usr/bin/perl" ) $HTTP["host"] == "example.com" { alias.url = ( "/bin/" => "/path/to/my/bin/" ) } </pre> Another sollution could be to use mod_alias with: <pre> cgi.assign = ( ".py" => "/usr/bin/python" ) alias.url = ( "/chrome" => var.basedir + "/foo.org/chrome", "" => var.basedir + "/foo.org/dispatch.py" ) </pre> The lack of an ending '/' will work as a wildcard. Inside this script, get the environment variable 'REQUEST_URI' to figure out the 'pretty' ending string. In python this would be; {{{os.environ[['REQUEST_URI']]}}} (ommiting import), in php; {{{$_SERVER[['REQUEST_URI']]}}}.