The job of a proxy server is to receive incoming HTTP or HTTPS requests, route them to the corresponding web server (backend), wait for it to reply and forward the response back to the querying party. If more than one backend is configured to serve requests, the proxy should distribute requests evenly between them, so that each backend gets a share of requests proportional to its capacity.
Pound
gets information about backends and instructions on
HTTP request routing from its configuration file pound.cfg. It
is located in the system configuration directory, which is
normally /etc2. Syntactically, the configuration file is a sequence of
statements and sections, separated by arbitrary amount of
empty lines and comments. A simple statement occupies a single
line and consists of a keyword (directive) and one or more
values separated by whitespace. A section is a compound
statement that encloses other statements and sections. Sections begin
with a keyword, optionally followed by arguments, and end with a word
End
on a line by itself. All keywords are case-insensitive.
The configuration file defines three kinds of objects: listeners, services, and backends. These are defined as configuration sections.
A listener defines IP address (and optionally port),
pound
will be listening on for incoming requests. It
can also be regarded as a frontend definition. Listener
declarations start with ListenHTTP
(for plaintext HTTP
frontends) or ListenHTTPS
(for HTTPS frontends) keywords.
Service sections define rules that decide to which backend to route requests received by the listeners. These rules normally involve analysis of the requested URL or HTTP headers. A service may also contain statements that modify requests or responses.
Services are normally declared inside listeners. Thus, when a listener receives a request, it iterates over its services (in the order of their appearance in the configuration file) to find the one that matches the request. If such a service is found, it receives the request and eventually passes it on to a backend.
Services may also be declared outside any listeners, in the global scope. Such services are shared between all listeners. They are tried if none of the services declared within a listener match the incoming request.
Service declarations start with the Service
keyword.
Backends are objects that actually handle requests and produce responses. Most often these are regular backends, which declare IP addresses and ports of servers that are to handle the requests. Backends are defined inside of services, so that the service that matched the request routes it to its backend. If more than one backend is defined within a service, incoming requests will be distributed so that each backend gets its share of the load.
Several special backend types are provided, such as emergency backends, redirects, etc. Only one special backend can be declared for a service, and it cannot be used together with other backend types.
Thus, an average request processing looks as follows. First, a request is received by one of the listeners. The listener then iterates over its services, until it finds one that matches the request. If no such service was found, the listener retries the process with the services defined in the global scope. If no matching service is found, a 503 error (‘Service Unavailable’) is returned. Otherwise, if the matching service was found, that service passes the request to one of its backends. It may modify the request before that, if it is instructed so by the configuration. Once the backend responds, the service passes the response back to the listener (again, optionally modifying it, if needed), which finally passes it back to the querying party.
The exact location depends on
compilation options. When in doubt, examine the output of
pound -V
.