Project

General

Profile

Docs ModProxyCore » History » Revision 46

Revision 45 (KB1PYW, 2008-10-23 06:22) → Revision 46/51 (matthijs, 2008-11-07 14:30)

h1. the Proxy Interface 

 


 *Module: mod_proxy_core* 

 {{>toc}} 


 h1. h2. Description 

 FastCGI, SCGI, HTTP, ... are doing the same simple job: they forward the HTTP-request to a backend and send the response back to the server. They just use different protocols to encode the data. 

 * FastCGI, developed by Open Market and documented on http://www.fastcgi.com/, is a binary container around HTTP requests which reduces the parsing overhead. In addition to normal response generation it supports authorization queries 
 * SCGI is similar to HTTP and only adds a length header for the HTTP-header. http://www.mems-exchange.org/software/scgi/ says "The SCGI protocol is a replacement for the Common Gateway Interface (CGI) protocol. It is a standard for applications to interface with HTTP servers. It is similar to FastCGI but is designed to be easier to implement." 
 * for HTTP we support HTTP/1.0 and HTTP/1.1 on the backend side 
 * AJP13 is the Apache JServ Protocol version 1.3 (see http://tomcat.apache.org/tomcat-3.3-doc/AJPv13.html), implemented by mod_jk and mod_proxy_ajp (Apache 2.2+) in the Apache world. 

 A small guide shall help you to choose the right protocol for your needs. 

 |_. <pre> 
 ======== ============= =============== ========== 
 Protocol    |_. preferred by |_.    binary protocol |_. keep-alive | 
 | ======== ============= =============== ========== 
 HTTP          |       mongrel          |         no                  |                yes            | 
 | SCGI          |       WSGI (python)    | not really          |        no             | 
 | FastCGI       |    PHP, rails       |      yes                 |               yes            | 
 | AJP13         |      Tomcat           |          yes                 |               yes            | 
 ======== ============= =============== ========== 
 </pre> 

 h1. h2. Installation 

 If you want to use mod-proxy-core you have to load it first. Each protocol is a module too and has to be loaded 
 after the core-module.: :: 
 <pre> 
   server.modules = ( 
     ...,  
     "mod_proxy_core", 
     "mod_proxy_backend_http", 
     "mod_proxy_backend_fastcgi", 
     ... ) 
 </pre> 

 h1. h2. Load Balancing 

 mod-proxy-core supports 4 different load balancers: 

  
  * the static load balancer (static) does no load balancing, only fail-over in case the first listed backend is not available. See http://permalink.gmane.org/gmane.comp.web.lighttpd/4686 for an example (basically local and remote backends). 
  * in Round Robin (round-robin) the requests are distributed equally over all backends. In our implementation we are not enforcing true round robin, but do a random selection of a backend. 
  * Shortest Queue First (sqf) is similar to round-robin and prefers the backend with the shortest wait-queue.  
  * the Cache Array Routing Protocol (carp) is a bit different as it is the only balancing protocol which improves the locality of the backends. It hashes the URL and send the same URL always to the same backend. http://icp.ircache.net/carp.txt explains the full spec. 
    

 Currently not implemented: 

   
  * sticky-session 
  * a lot of the http://www.ietf.org/proceedings/99mar/I-D/draft-melve-intercache-comproto-00.txt protocols 


 h1. h2. Fail-Over Handling 

 In case a request to the backend fails (connections refused, connection timeout, ...) the request is sent to another backend. If no backend is a available, ``504 Gateway Timeout`` is returned. (see http://forum.lighttpd.net/topic/4993) 

 h1. h2. Timeouts 

 If your incoming requests is exceeding the number of backends you have the request is put into a backlog queue. As soon as a backend is available again the first connection from the queue is woken up and is processed.  

 In case a request is waiting for more than 10 seconds in the queue, the request is terminated and ``504 Gateway timeout`` is returned. 


 h1. h2. Options 


 *proxy-core.balancer* 
 

 proxy-core.balancer 
   might be one of 'round-robin', 'sqf', 'carp' or 'static'. 

 

   See:  

     * http://blog.lighttpd.net/articles/2006/11/14/mod-proxy-core-and-sqf 

 *proxy-core.protocol* 
 proxy-core.protocol 
   might be one of 'http', 'fastcgi', 'ajp13' or 'scgi'.    Make sure you load the backend 
   modules (see mod_proxy_backend_<name>) 

 *proxy-core.backends* 
 proxy-core.backends 
   tell the module where to send Proxy requests to. 

 



   It is a list of hostname/ip address/unix-domain socket 

 e.g. 

   Example: :: 
 <pre> 
     proxy-core.backends = (  
       "10.0.0.1:80",       ## IPv4 address 
       "unix:/tmp/php.socket", ## unix domain socket 
       "[::1]:80",          ## IPv6 addresss 
       "google.com:80"      ## hostname, resolved at startup 
     ) 
 </pre> 

 *proxy-core.max-pool-size* 
 proxy-core.max-pool-size 
   max size for pool of connections to a single backend. 

 

   * for mongrel this should be 1 
 
   * for PHP this should match the PHP_FCGI_CHILDREN setting 
 
   * for WSGI it should match the number of threads of the backend 
 
   * for HTTP proxying it is up to you how many parallel requests you want to allow to the same backend 

 

   Default: 1 

 *proxy-core.allow-x-sendfile* 
 proxy-core.allow-x-sendfile 
   enables use of "X-Sendfile/X-LIGHTTPD-Sendfile/X-LIGHTTPD-send-tempfile" headers. 

 
   Note: If you're running PHP with zlib compression, turn it off using ini_set("zlib.output_compression", "off") or the file you're trying to send will be just 1 byte and not work. 

 

   See:  

     * http://blog.lighttpd.net/articles/2006/07/22/mod_proxy_core-got-x-sendfile-support 
     * http://blog.lighttpd.net/articles/2006/11/29/faster-fastcgi 

 *proxy-core.allow-x-rewrite* 
 


 proxy-core.allow-x-rewrite 
   enables use of X-Rewrite 

 

   Gives you the ability to redirect requests from one backend to another without the client noticing it by using the response headers "X-Rewrite-URI" and "X-Rewrite-Host" 

 

   Suppose you want to have some kind of loadbalancing but with a more complex logic behind it than roundrobin or weighted randomization. 
 
   The client requests http://host.tld/ which is handled by your fastcgi backend which does some computation to decide which backend should be used. 
 
   All your backend has to do now is to send a 200 OK together with e.g. "X-Rewrite-URI: /foo" and "X-Rewrite-Host: internal3.host.tld" 
 
   What that does is that it will cause mod_proxy_core to handle the current request from the client again but with URI "/foo" instead of "/" and host "internal3.host.tld" instead of "host.tld" 

 

   See: 

     
     * http://blog.lighttpd.net/articles/2006/07/22/x-sendfiles-new-friend-x-rewrite 

 *proxy-core.rewrite-request* 
 proxy-core.rewrite-request 
   rewrite request headers or request uri. 

 
   The following keys are currently supported: 

 

   * "_uri": ''_uri'': The full path + querystring of the request, e.g. "/some/file/in/some/dir.fcgi?request&uri=1" 
 
   * "_docroot": ''_docroot'': Path to the document root, useful if the request goes to another server with a different file system layout 
 
   * "_pathinfo": ''_pathinfo'': CGI Environment variable PATH_INFO (e.g. /foobar for a request to /myfcgiapp/foobar) 
 
   * "_scriptname": ''_scriptname'': CGI Environment variable SCRIPT_NAME (e.g. /myfcgiapp for a request to /myfcgiapp) 

 

   Note, see #1600. 

 #1600 . 

   Example: 

 

     trac needs a guessed PATH_INFO: :: 
 <pre> 
       $HTTP["url"] =~ "^/trac/" { 
         proxy-core.backends = ( "127.0.0.1:9090" ) 
         proxy-core.protocol = "fastcgi" 
         proxy-core.rewrite-request = ( 
            "_pathinfo" => ( "^/trac(/.*)" => "$1" ), 
            "_scriptname" => ( "^(/trac/)" => "$1" ) 
         ) 
       } 
 </pre> 
     We build the PATH_INFO from the request-uri (the same as in the $HTTP["url"]) and  
     extract the part after the trac-base from it as PATH_INFO. The SCRIPT_NAME is shortened shortend 
     accordingly. 

     trac will only see: :: 
 <pre> 
       SCRIPT_NAME=/trac 
       PATH_INFO=/wiki 
 </pre> 
      For proxies can make a relative part of your URL: :: 
 <pre> 
       $HTTP["url"] =~ "^/blog" { 
         proxy-co... 

         proxy-core.rewrite-request = ( 
           "_uri" => ( "^/blog/?(.*)" => "/$1" ), 
           "Host" => ( ".*" => "blog.example.org" ), 
         ) 
       } 
 </pre> 
     All requests to http://example.org/blog will be fetched from http://blog.example.org/  
     transparently for the user. 

 *proxy-core.rewrite-response* 
 proxy-core.rewrite-response 
   rewrite response headers. 

 *proxy-core.max-keep-alive-requests* 
 proxy-core.max-keep-alive-requests 
   number of request before closing a keep-alive connection. 

 

   Default: 0 

 *proxy-core.split-hostnames* 
 proxy-core.split-hostnames 
   If the backends uses DNS hostnames each with multiple ip address, split each address into a separate backend. 
 
   Disable this option to put the ip addresses into an address pool for that backend. 

 

   Default: enabled 

 h1. Example h2. Example: 

 Using lighttpd + mod_proxy_core in front of 8 Squids which handle the  
 caching of dynamic content for you. All requests for the host  
 www.example.org should be forwarded to the proxy. All proxies 
 listen on port 80 for requests. :: 
 <pre> 
   server.modules    += ( "mod_proxy_backend_http" ) 
   $HTTP["host"] == "www.example.org" { 
     proxy-core.protocol = "http" 
     proxy-core.balancer = "carp" 
     proxy-core.backends = ( "10.0.0.10", 
                             "10.0.0.11", 
                             "10.0.0.12", 
                             "10.0.0.13", 
                             "10.0.0.14", 
                             "10.0.0.15", 
                             "10.0.0.16", 
                             "10.0.0.17" ) 
   } 
 </pre> 
 If one of the hosts goes down the all requests for this one server are  
 moved equally to the other servers. If you want to know more about 
 the algorithm used here google for 'Microsoft CARP'. 

 For for php using unix-domain socket "/tmp/php-fastcgi.sock" :: 
 <pre> 
   server.modules    += ( "mod_proxy_backend_fastcgi" ) 
   $PHYSICAL["existing-path"] =~ "\.php$" { 
     proxy-core.balancer = "round-robin" 
     proxy-core.protocol = "fastcgi" 
     proxy-core.allow-x-sendfile = "enable" 
     proxy-core.backends = ( "unix:/tmp/php-fastcgi.sock" ) 
     proxy-core.max-pool-size = 16 
     proxy-core.rewrite-request = ( 
       "_pathinfo" => ( "\.php(/.*)" => "$1" ) 
     ) 
   } 
 </pre> 
 for SCGI :: 
 <pre> 
   server.modules    += ( "mod_proxy_backend_scgi" ) 
   $PHYSICAL["existing-path"] =~ "\.scgi$" { 
     proxy-core.balancer = "round-robin" 
     proxy-core.protocol = "scgi" 
     proxy-core.allow-x-sendfile = "enable" 
     proxy-core.backends = ( "127.0.0.1:9090" ) 
     proxy-core.max-pool-size = 16 
   } 
 </pre> 
 for http-proxy with host and file-extension conditionals :: 
 <pre> 
   server.modules    += ( "mod_proxy_backend_http" ) 
   $HTTP["host"] == "www.example.org" { 
     proxy-core.protocol = "http" 
     proxy-core.balancer = "carp" 
     $HTTP["url"] =~ "\.php$" { 
       proxy-core.backends = ( "10.0.0.10:80" ) 
     } 
     else $HTTP["url"] =~ "\.scgi$" { 
       proxy-core.backends = ( "10.0.0.11:80" ) 
     } 
   } 
 </pre> 
 Reverse-Proxying :: 
 <pre> 
   server.modules    += ( "mod_proxy_backend_http" ) 
   $HTTP["url"] =~ "^/proxyme(/|$)" { 
     proxy-core.balancer = "round-robin" 
     proxy-core.protocol = "http"  
     proxy-core.backends = ( "en.wikipedia.org" ) 
     proxy-core.rewrite-response = ( 
       "Location" => ( "^http://en.wikipedia.org/(.*)" => "http://127.0.0.1:1025/proxyme/$1" ), 
     ) 
     proxy-core.rewrite-request = ( 
       "_uri" => ( "^/proxyme/?(.*)" => "/$1" ), 
       "Host" => ( ".*" => "en.wikipedia.org" ), 
     ) 
   } 
 </pre> 
 for proxying to Tomcat using AJP13 protocol :: 
 <pre> 
   server.modules    += ( "mod_proxy_backend_ajp13" ) 
   $HTTP["url"] =~ "^/tomcat/" { 
     proxy-core.balancer = "round-robin" 
     proxy-core.protocol = "ajp13" 
     proxy-core.backends = ( "localhost:8009" ) 
     proxy-core.max-pool-size = 16 
   } 
 </pre> 
 example of allow-x-rewrite config :: 

 <pre> 
   server.modules    += ( "mod_proxy_backend_fastcgi" ) 
   $PHYSICAL["existing-path"] =~ "\.php$" { 
     proxy-core.balancer = "round-robin" 
     proxy-core.protocol = "fastcgi" 
     proxy-core.allow-x-rewrite = "enable" 
     proxy-core.backends = ( "unix:/tmp/php-fastcgi.sock" ) 
     proxy-core.max-pool-size = 16 
   } 
   server.modules    += ( "mod_proxy_backend_http" ) 
   $HTTP["host"] == "backend-cluster" { 
     proxy-core.balancer = "round-robin" 
     proxy-core.protocol = "http"  
     proxy-core.max-pool-size = 4 
   } 
 </pre> 
 example X-Rewrite script :: 

 <pre> 
   <?php 
   header("X-Rewrite-URI: /"); 
   header("X-Rewrite-Host: backend-cluster"); 
   header("X-Rewrite-Backend: " . $_REQUEST['backend']); // dynamicaly add/select a backend to the "backend-cluster" proxy-core 
   ?> 
 </pre> 

 Proxying requests for a Rails app to a locally hosted pack of mongrels. :: 

 <pre> 
   $HTTP["host"] == "rails.dom.ain" { # or, e.g., =~ "^([^.])+\.rails\.tld$" 
     proxy-core.protocol = "http" 
     proxy-core.balancer = "round-robin" 
     proxy-core.allow-x-sendfile = "enable" # avoid send_file memory ballooning by using the x_send_file plugin 
     proxy-core.backends = ( 
       "127.0.0.1:8000", 
       "127.0.0.1:8001", 
       "127.0.0.1:8002", 
       "127.0.0.1:8003" 
     ) 
   } 

 
 </pre>