Project

General

Profile

MigratingFromApache » History » Revision 49

Revision 48 (CCormier, 2021-07-30 03:17) → Revision 49/51 (gstrauss, 2021-08-22 19:23)

h1. Migrating from Apache to lighty 

 {{>toc}} 

 h2. Configuration Basics 

 Lighttpd is a great option as a replacement for existing apache or apache2 systems. 

 Please start by reading about [[lighttpd:Docs_Configuration|Configuration: File Syntax]]. If you are seriously considering migrating, read the documentation for the configuration file [[lighttpd:Docs_Configuration|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 lighttpd configuration is its *conditionals*. Lighttpd allows you to setup configuration options based on the client 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 appreciate the flexibility of lighttpd 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 in [[lighttpd:Docs_Configuration|Configuration: File Syntax]] here along with further explanation about the match operators. 


 *Q*: How do I enable directory listings everywhere except for directory /download? 
 <pre> 
 ####### Enable dir listing for all directories 
 dir-listing.activate = "enable" operators [[lighttpd:Docs_Configuration|Docs:Configuration]]. 

 ####### If *Problem*: You want the URL is like ^/download/ then disable dir-listing 
 $HTTP["url"] =~ "^/download/" { 
   dir-listing.activate = "disable" 
 } 
 </pre> 
 *Q*: How do I restrict the status page to be available only just for users from the local network? network: 
 Entry in configuration file: 


 <pre> 
 $HTTP["remoteip"] == "10.0.0.0/8" { 
   status.status-url = "/server-status" 
 } 
 </pre> 
 *Q*: How do I enable directory listing only if 


 And here is a nested example. 

 *Problem*: If the host is www2.example.org and the url directory is under @/download/@? 
 Conditions can be nested: 
 /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]] 
 * [[Docs_ModRedirect#Examples|HowToRedirectWww]] 
 * [[HowToAuthenticationFromMultipleFiles]] 
  

 ----- 



 h2. Basic Options 


 @Options +FollowSymLinks@ becomes @server.follow-symlink = "enable"@ 


 h2. Accesslog 

 


 Accesslogs are written by [[Docs_ModAccessLog|mod_accesslog]] @accesslog.format = "..."@ supports many of and support the same options in @accesslog.format = ...@ as in Apache.  
  

 If you need logfile rotation is also handled similarly to as in Apache, e.g. 
 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. 
 * "cronolog":http://www.cronolog.org/ 
   


 h3. cronolog 


 With cronolog, cronolog you pipe the accesslog to a pipe and let a external program handle the logfile writing: 
   @accesslog.filename 


 <pre> 
 accesslog.filename = "|/usr/sbin/cronolog /web/logs/%Y/%m/%d/access.log"@ /web/logs/%Y/%m/%d/access.log" 
 </pre> 


 h2. Rewrite 

 [[lighttpd:Docs_ModRewrite|mod_rewrite]] can be mod_rewrite 


 "mod_rewrite":http://www.lighttpd.net/documentation/rewrite.html is more complex.    The lighttpd difficult as the implementation of how the rules are written is very different from that completely different. 

 First of Apache.    lighttpd all, we always matches match on the full relative request-uri that is submitted by the user (and is not url-decoded).    user. That means we can emulate apache's QSA flag ("query (query string append"; 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@, $2 (the query string [[part|after ?]] is the second _capturing_ parentheses of the regex.    @?:@ matching bracket pair; ?: makes the surrounding parentheses non-capturing. 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 dir.onlinesearch.ws 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/@.    The first pattern below uses regex syntax 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/. ''/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/. 

 In lighttpd 1.4.50 and later, the above can be simplified to 
 <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)" "^/instadir/(?!index\.php|dmoz\.css|admin|img).*" => "", 
                      "^/instadir/([^?]*)" => "/instadir/index.php?area=browse&cat=$1${qsa}") 
 </pre> 

 If some combination of Apache rewrite rules can not be written in lighttpd [[lighttpd:Docs_ModRewrite|mod_rewrite]] rules, then another option is lighttpd [[lighttpd:Docs_ModMagnet|mod_magnet]], which uses lua (a real programming language) as opposed to .     [[#Arbitrarily-complex-logic|Arbitrarily complex logic]] can be written using lighttpd [[lighttpd:Docs_ModMagnet|mod_magnet]] in lieu of [[lighttpd:Docs_ModRewrite|mod_rewrite]] 


 h2. FastCGI mod_fastcgi 


 If you have 2 extensions assigned to the fastcgi handler in Apache like  
 @AddType  


 <pre> 
 AddType fastcgi-php .php .phtml@ .phtml 
 </pre> 


 then you need to tell lighttpd [[lighttpd:Docs_ModFastCGI|mod_fastcgi]] to treat two entries in the extensions as the same: 
 fastcgi.server config: 


 <pre> 
 fastcgi.map-extensions = ( ".phtml" => ".php" ) 
 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 the above example, 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> 

 Another option is [[AbsoLUAtion#Content-Negotiation|content-negotiation.lua]] 


 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 lighttpd 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> 


 Another solution 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'] (omitting import), in php: $_SERVER['REQUEST_URI']. 


 h2. Arbitrarily complex logic 

 If lighttpd modules do not natively support a specific set of logic, there is another option: lighttpd [[lighttpd:Docs_ModMagnet|mod_magnet]]. 
 Arbitrarily complex logic can be written into a lua scripts and run with [[lighttpd:Docs_ModMagnet|mod_magnet]].