POUND(8)

NAME
pound - HTTP/HTTPS reverse-proxy and load-balancer

SYNOPSIS

pound
    [-f config_file]

DESCRIPTION

Pound is a reverse-proxy load balancing server. It accepts requests from HTTP/HTTPS clients and distributes them to one or more Web servers. The HTTPS requests are decrypted and passed to the back-ends as plain HTTP.

If more than one back-end server is defined, Pound chooses one of them randomly, based on defined priorities. By default, Pound keeps track of associations between clients and back-end servers (sessions).

OPTIONS
Options available (see also below for configuration file options):

-f config_file
    Location of the configuration file (see below for a full description of the format). Default: /usr/local/etc/pound.cfg

In general, any number of back-end servers may be specified. Use the priority to affect the load distribution among unequal-performance servers.

One (or more) copies of Pound should be started at boot time. Use "big iron" if you expect heavy loads: while Pound is as light-weight as I know how to make it, with a lot of simultaneous requests it will use quite a bit of CPU and memory. Multiple CPUs are your friend.

CONFIGURATION FILE
Each line in the file is considered a complete configuration directive. The directives are case-insensitive. Empty lines or lines starting in '#' are ignored. There are two types of directives: global directives (they affect the settings for the entire program instance), and group directives (they affect only a specific group of requests).

GLOBAL DIRECTIVES
Global directives may appear anywhere within the configuration file, though it is customary for them to be at the start. They may appear in any order.

ListenHTTP host,port
    Specify the address and port number where Pound will listen for HTTP requests. Multiple directives imply listening on multiple ports. A host name of "*" implies listening on all available interfaces (but be careful: no checks are made for conflicting definitions).

ListenHTTPS host,port cert_file [ciphers]
    Specify the address and port number where Pound will listen for HTTPS requests. cert_file is the file containing the certificate, possibly a certificate chain and the signature for this port; the same file may be specified for multiple ports (as above - multiple directives imply listening on multiple ports). A host name of "*" implies listening on all available interfaces. If specified, ciphers is the list of ciphers that will be accepted by the SSL connection; it is a string in the same format as in OpenSSL ciphers(1) and SSL_CTX_set_cipher_list(3). Both ListenHTTP and ListenHTTPS may be specified as may times as required.

HTTPSHeaders cert "header"
    Add HTTPS-specific headers. By default, Pound passes requests unchanged to the back-end server(s). If the header is not empty it represents the value of a header to be added to the request. The cert tells Pound what to do about client certificates: 0 - don't ask (default), 1 - ask, 2 - ask and fail if no certificate was presented.

CAlist CAcert_file verify_depth
    Set the list of "trusted" CA's for this server. The CAcert_file is a file containing a sequence of CA certificates (PEM format). The names of the define CAs will be sent to the client on connection). Verify_depth is the depth of verification for a client certificate (up to 9). A value of 0 (the default) implies no verification at all.

User user_name
    Specify the user Pound will run as (must be defined in /etc/passwd).

Group group_name
    Specify the group Pound will run as (must be defined in /etc/group).

RootJail directory_path_and_name
    Specify the directory that Pound will chroot to at runtime. Please note that OpenSSL requires access to /dev/urandom, so make sure you create the a device by that name, accessible from the root jail directory.

ExtendedHTTP value
    if value is 1, allow extended HTTP requests (PUT, DELETE). By default, Pound only allows GET, POST and HEAD.

WebDAV value
    if value is 1, allow WebDAV requests (LOCK, UNLOCK and if compiled with MS support: SUBSCRIBE, PROPFIND, PROPPATCH, SEARCH, POLL, MKCOL, MOVE, COPY, DELETE, BDELETE, CONNECT, OPTIONS, TRACE, MKACTIVITY, CHECKOUT, MERGE, REPORT). This, as far as I can tell, is what Microsoft needs in its private WebDAV version. Whether my understanding of their semantics is correct is debatable. Whether their understanding of their semantics is correct is also debatable (they had to patch their own proxy several times in order to support WebDAV). MS support is also required for Subversion (see http://subversion.tigris.org for details) access.

LogLevel value
    Specify the logging level: 0 for no logging, 1 (default) for regular logging, 2 for extended logging (show chosen backend server as well), 3 for Apache-like format (Common Log Format with Virtual Host) and 4 (same as 3 but without the virtual host information).

NoHTTPS11 value
    Behave like an HTTP/1.0 server for HTTPS clients (default: 0). If value is non-zero do not allow multiple requests on SSL connections. Required work-around for a bug in certain versions of IE.

Alive value
    Specify how often Pound will check for resurected back-end hosts (default: 30 seconds). In general, it is a good idea to set this as low as possible - it will find resurected hosts faster. However, if you set it too low it will consume resources - so beware.

Server value
    Specify for how long Pound will wait for a server response. After this long has passed without the server sending any data Pound will consider the response finishedand abort the connection. A value of 0 (default) implies waiting forever. Set it higher if your server(s) occasionally time-out on a slow network or are over-loaded.

Client value
    Specify for how long Pound will wait for a client request (default: 10 seconds). After this long has passed without the client sending any data Pound will close the connection. Set it higher if your clients time-out on a slow network or over-loaded server, lower is you start getting DOS attacks or run into problems with IE clients.

SSLEngine name
    Use an OpenSSL hardware accelleration card called "name". Available only if OpenSSL-engine is installed on your system.

Err500 "filename"
    A file with the text to be displayed if an Error 500 occurs. Default: "An internal server error occurred. Please try again later.".

Err501 "filename"
    A file with the text to be displayed if an Error 501 occurs. Default: "This method may not be used.".

Err503 "filename"
    A file with the text to be displayed if an Error 503 occurs. Default: "The service is not available. Please try again later.".

CheckURL value
    If value is 1 check the requested URL for correct syntax. If value is 0 (default) no checking is performed, and additional CSsegment or similar directives are quietly ignored.

CSsegment chars
    The allowed character set for the segment part of the request. Same for CSparameter, CSqid, CSqval and CSfragment. See below for details on URL matching.

MaxRequest nnn
    Request maximal size. All requests will be limited to these many bytes. If a request contains more data than allowed an error is returned. Default: unlimited.

HeadRemove "header"
    Remove certain headers from the incoming requests. All occurences of the matching specified header will be removed. Please note that this filtering is done prior to other checks (such as HeadRequire or HeadDeny), so you should not try to check for these headers in later matches. Multiple directives may be specified in order to remove more than one header, and the header itself may be a regular pattern (though this should be used with caution).

GROUP DIRECTIVES
Group directives apply to a specific group of requests. The order of the group directives is important - incoming requests will be matched against the given patterns in the order they appear in the file, and the first group that matches wins.

If a request does not match any of the defined groups it will not be sent anywhere (there is no default server). This can come in handy if you want to block a specific kind of requests, though it would be better style to do this with a catch-all group with no servers.

UrlGroup "pattern"
    Specify a group of backend servers based on a URL pattern. All requests fitting the pattern will be served by the defined servers. Pattern is a regular pattern as specified in regex(7) - extended version. The patterns are tested in order of definition, so the last pattern should usually be a catch-all .* The group ends with a EndGroup directive.

BackEnd address,port,priority[,ha_port]
    Specify a backend server: address and port. Priority is 1 to 9 and defines a weighting - higher priority servers get used more often. May only be used in an UrlGroup directive. If no servers are specified, then the specified URLs will be simply blocked.

Session TYPE [id] seconds
    Specify the time (in seconds) that a session will be kept. May be used exactly once and only in an UrlGroup directive. TYPE is one of:

    IP - the session is kept based on client IP address. No id is allowed.

    BASIC - the session is kept based on Basic Authentication data. No id is allowed.

    URL - the session is kept based on the value of a parameter in the request URL. The id indicates which parameter will be checked.

    COOKIE - the session is kept based on a cookie (in the request or the response). The id indicates which cookie will be checked.

HeadRequire header "pattern"
    Specifiy header(s) that must appear in the request. Only requests that include the specified HTTP header will match. May only be used in an UrlGroup directive. The headers will be checked against the "^header: *pattern$" regular pattern. As many HeadRequire directives as necessary may appear in a single group.

HeadDeny header "pattern"
    Specifiy headers that may not appear in the request. Only requests that do not include the specified HTTP header will match. May only be used in an UrlGroup directive. The headers will be checked against the "^header: *pattern$" regular pattern. As many HeadDeny directives as necessary may appear in a single group.

See below for some examples.

HIGH-AVAILABILITY
Pound attempts to keep track of active back-end servers, and will temporarily disable servers that do not respond (though not necessarily dead: an overloaded server that Pound cannot establish a connection to will be considered dead). However, every alive_check seconds, an attempt is made to connect to the dead servers in case they have become active again. If this attempt succeeds, connections will be innitiated to them again.

In general it is a good idea to set this time interval as low as is consistent with your resources in order to benefit from resurected servers at the earliest possible time. The default value of 30 seconds is probably a good choice.

Set the interval to 0 to disable this feature. The clients that happen upon a dead backend server will just receive a 503 Service Unavailable message.

The ha_port parameter specifies an additional port that is used only for viability checks: if this port is specified in a BackEnd directive, Pound will attempt periodically (every Alive seconds) to connect to this port. If the port does not respond the server is considered dead.

URL MATCHING
Pound attempts to filter out illegal request URLs. In general a URL is defined as

{ / segment [; parameter] } [? qid [ = [ qval ] ] { & qid [ = [ qval ] ] } ] [ # fragment ]

Each of the elements is matched against the allowed character set. By default, the parts are defined as:

CSsegment - ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.!~*'():@&=+$,%-
CSparameter - ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.!~*'():@&=+$,%-
CSqid - ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.!~*'()-
CSqval - ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.!~*'()%-
CSfragment - ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.!~*'()

If Pound was compiled with support for MS DAV the segment part includes, in addition, the characters {}<>".

This mechanism comes in handy should you need to define some other "legal" URLs. A common occurence is that PHP programmers use unencoded parameters in their requests such as /xxx?id[2]=abc. For such cases define:

CSqid ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.!~*'()-[]

in your config file. Additionally this can be useful for accented characters and other non-RFC conformant requests.

Please be aware that each of these additional definitions may introduce security problems - use them at your own risk.

HTTPS HEADERS
If a client browser connects to Pound via HTTPS and if it presents a client certificate and if HTTPSHeaders is set (HTTPSHeaders 1 "value"), Pound adds the following headers to the request it issues to the server:

value
    The value, if present, is added to the headers.

X-SSL-Subject
    Details about the certificate owner.

X-SSL-Issuer
    Details about the certificate issuer (Certificate Authority).

X-SSL-notBefore
    Starting date of certificate validity.

X-SSL-notAfter
    Ending date of certificate validity.

X-SSL-serial
    Certificate serial number (decimal).

X-SSL-cipher
    The cipher currently in use.

X-SSL-certificate
    The full client certificate (PEM-format multi-line)

It is the application's responsability to actually use these headers - Pound just passes this information without checking it in any way (except for signature and encryption correctness).

SECURITY

In general, Pound does not read or write to the hard-disk. The exceptions are reading the configuration file and (possibly) the server certificate file(s) and error message(s), which are opened read-only on startup, read, and closed, and the pid file which is opened on start-up, written to and immediately closed. Following this there is no disk access whatsoever, so using a RootJail directive is only for extra security bonus points.

Pound tries to sanitise all HTTP/HTTPS requests: the request itself, the headers and the contents are checked for conformance to the RFC's and only valid requests are passed to the back-end servers. This is not absolutely fool-proof - as the recent Apache problem with chunked transfers demonstrated. However, given the current standards, this is the best that can be done - HTTP is an inherently weak protocol.

ADDITIONAL NOTES
Pound uses the system log for messages (default facility LOG_DAEMON). The format is very similar to other web servers, so that if you want to use a log tool:

fgrep pound /var/log/messages | your_log_tool

Translating HTTPS to HTTP is an iffy proposition: no client information is passed to the server itself (certificates, etc) and the backend server may be misled if it uses absolute URLs. A patch for Zope is included in the distribution to address this issue - for other Web servers you are on your own. May the source be with you.

Pound deals with (and sanitizes) HTTP/1.1 requests. Thus even if you have an HTTP/1.0 server, a single connection to an HTTP/1.1 client is kept, while the connection to the back-end server is re-opened as necessary.

EXAMPLES
To translate HTTPS requests to a local HTTP server (assuming your network address is 123.123.123.123):

    ListenHTTPS 1.2.3.4,443 /etc/pound/server.pem
    UrlGroup ".*"
    BackEnd 127.0.0.1,80,1
    EndGroup

To distribute the HTTP/HTTPS requests to three read-only Web servers, where the third one is a newer and faster machine:

    ListenHTTP 123.123.123.123,80
    ListenHTTPS 1.2.3.4,443 /etc/pound/server.pem
    UrlGroup ".*"
    BackEnd 192.168.0.10,80,1
    BackEnd 192.168.0.11,80,1
    BackEnd 192.168.0.12,80,3
    EndGroup

To distribute the HTTP/HTTPS requests to two Web servers with long session times; also change the uid/gid of the running program and do a chroot:

    ListenHTTP 123.123.123.123,80
    ListenHTTP 123.123.123.123,8080
    ListenHTTPS 1.2.3.4,443 /etc/pound/server.pem
    User www
    Group www
    RootJail /var/pound
    UrlGroup ".*"
    BackEnd 192.168.0.10,80,1
    BackEnd 192.168.0.11,80,1
    Session IP 600
    EndGroup

To separate between image requests and other Web content and block all requests for a specific URL:

    ListenHTTP 123.123.123.123,80
    # Images server(s)
    UrlGroup ".*.(jpg|gif)"
    BackEnd 192.168.0.12,80,1
    EndGroup
    # Block all requests for /forbidden
    UrlGroup "/forbidden.*"
    EndGroup
    # Catch-all server(s)
    UrlGroup ".*"
    BackEnd 192.168.0.10,80,1
    BackEnd 192.168.0.11,80,1
    Session BASIC 300
    EndGroup

Here is a more complex example: assume your static images (GIF/JPEG) are to be served from a single back-end 192.168.0.10. In addition, 192.168.0.11 is to do the hosting for www.myserver.com with URL-based sessions, and 192.168.0.20 (a 1GHz PIII) and 192.168.0.21 (800Mhz Duron) are for all other requests (cookie-based sessions). The logging will be done by the back-end servers. The configuration file may look like this:

    # Main listening ports
    ListenHTTP 1.2.3.4
    ListenHTTPS 1.2.3.4,443 /etc/pound/pound.pem
    User nobody
    Group nogroup
    RootJail /var/pound/jail
    Client 15
    Alive 60
    HTTPSHeaders 1 ""
    LogLevel 0
    # Image server
    UrlGroup ".*.(jpg|gif)"
    BackEnd 192.168.0.10,80,1
    EndGroup
    # Virtual host www.myserver.com
    UrlGroup ".*sessid=.*"
    HeadRequire Host ".*www.myserver.com.*"
    BackEnd 192.168.0.11,80,1
    Session URL sessid 120
    EndGroup
    # Everybody else
    UrlGroup ".*"
    BackEnd 192.168.0.11,20,5
    BackEnd 192.168.0.11,21,4
    Session COOKIE userid 180
    EndGroup

FILES

/var/run/pound.nnn
    this is where Pound will attempt to record its process id.

/usr/local/etc/pound/pound.cfg
    the default configuration file (the location may be changed when compiling - see the F_CONF flag in the Makefile).

/usr/local/etc/pound/cert.pem
    the certificate file(s) for HTTPS. The location must be defined in the configuration file - this is only a suggestion. The file must contain a PEM-encoded certificate, optionally a certificate chain from a known Certificate Authority to your server certificate and a PEM-encoded private key (not password protected). See OpenSSL(1) for details. This file should be well protected, lest someone gets your server private key.

AUTHOR
Written by Robert Segall, Apsis GmbH.

REPORTING BUGS
Report bugs to <roseg@apsis.ch>.

COPYRIGHT
Copyright © 2002 Apsis GmbH.
This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.