Light-weight reverse proxy and load balancer for HTTP/HTTPS.
Deploy this app to Linode with a free $100 credit!
Pound is a reverse proxy, load balancer and HTTPS front-end for Web servers. It was developed to enable distributing the load among several Web-servers and to allow for a convenient SSL wrapper for those Web servers that do not offer it natively. Pound is distributed under the GNU General Public License, Version 3, or (at your option) any later version.
The original version of pound was written by Robert Segall at Apsis GmbH. In 2018, Sergey Poznyakoff added support for OpenSSL 1.x to the then current version of the program (2.8). This version of pound, hosted on github was further modified by Rick O'Sullivan and Frank Schmirler, who added WebSocket support.
On April 2020, Apsis started development of pound 3.0 - essentially an attempt to rewrite pound from scratch, introducing dependencies on some third-party software.
On 2022-09-19, Robert announced that he stops further development and maintenance of pound. Following that, Sergey decided to continue development of the program starting from his fork.
Pound is a very small program, easily audited for security problems. It can run as setuid/setgid and/or in a chroot jail. Pound does not access the hard-disk at all (except for reading certificate files on start, if required) and should thus pose no security threat to any machine.
I took over pound development at its 2.x branch. The branch 3.x, which emerged for a short time before the original project was abandoned, I consider to be a failed experiment. To ensure consistent versioning and avoid confusion, my versioning of pound starts with 4.0.
Documentation in manpage format is available in the distribution. A copy of the documentation is available online.
To build, pound needs OpenSSL version 1.1.x or 3.0.x.
As of current release, pound still supports OpenSSL 1.0, but this support will soon be discontinued.
If you compile it on a Debian-based system, you need to install the
libssl-dev
package prior to building pound.
If you cloned pound from the repository, you will need the following tools in order to build it:
First, run
./bootstrap
This will prepare the necessary infrastructure files (Makefile.in
's
etc.)
If you are building pound from a tarball, the above step is not needed, since all the necessary files are already included in it.
To prepare pound for compilation, run ./configure
. Its command
line options will decide where on the filesystem the binary will be
installed, where it will look for its configuration file, etc. When
run without options, the binary will be installed at /usr/local/sbin
and it will look for its configuration in file /usr/local/etc/pound.cfg
.
If you run it as:
./configure --prefix=/usr --sysconfdir=/etc
then the binary will be installed at /usr/sbin/pound
and it will
read its configuration from /etc/pound.cfg
.
For a detailed discussion of --prefix
, --sysconfdir
, and other
generic configure options, refer to Autoconf documentation.
Apart from the generic ones, there are also several pound-specific configuration options:
--enable-pcreposix
or --disable-pcreposix
Enable or disable the use of the pcreposix
library. This is a
library that makes it possible to use both POSIX extended and
Perl-compatible regular expressions in pound configuration
file.
By default, its presence is determined automatically.
--enable-pthread-cancel-probe
or --disable-pthread-cancel-probe
Pound calls the pthread_cancel
function as part of its shutdown
sequence. In GNU libc, this function tries to load shared library
libgcc_s.so.1
. It will fail to do so, if the program is running in
chroot (the RootJail
statement is given), unless the library has
previously been copied to the chroot directory. To avoid this, pound
will do a temptative call to pthread_cancel
early, before chrooting,
so that the necessary library will be loaded and remain available after
chroot
. To determine whether to do this pthread_cancel probe hack,
configure
checks if the program is going to be linked with GNU libc.
These two options allow you to forcefully enable or disable this probe. For instance, you may wish to enable it, if another libc implementation exhibits a similar behavior.
--with-maxbuf=
nSets the value of MAXBUF
parameter - the size of a generic buffer
used internally by pound for various needs. The default is 4096.
You will probably not want to change it.
--with-owner=
userName of the system user who will own the pound executable file. When
not supplied, the first name from the following list that exists in
the /etc/passwd
file will be used: proxy
, www
, daemon
, bin
,
sys
, root
.
--with-group=
groupName of the system group who will own the pound executable. When
not supplied, the first name from the following list that exists in
the /etc/passwd
file will be used: proxy
, www
, daemon
, bin
,
sys
, root
.
--with-dh=
nDefault DH parameter length. Allowed values for n are 2048 (the default) and 1024.
This option has no effect when compiling with OpenSSL 1.1 or later.
--with-ssl=
directoryDirectory under which OpenSSL is installed. You will seldom need this
option. Most of the time configure
is able to detect that location
automatically.
--with-t_rsa=
nSets default time interval for regeneration of RSA ephemeral keys.
This option has no effect when compiling with OpenSSL 1.1 or later.
When configuration is finished, run
make
When building from a git clone, the first run of this command can take
considerable time, if you are compiling with OpenSSL
1.0. That's because
it involves generating DH parameters.
Testing a reverse proxy in general, and pound in particular, is not a trivial task. Testsuite in pound was implemented quite recently and is still somewhat experimental. Notwithstanding that, it has already helped to discover several important bugs that lurked in the code.
To test pound you will need Perl version 5.26.3 or later, and the IO::FDPass module. To install the latter on a reasonably recent debian-based system, run
apt-get install libio-fdpass-perl
On other systems you may need to install it directly from cpan by running
cpan -i IO::FDPass
To run tests, type
make check
from the top-level source directory. On success, you will see something like that:
## -------------------------- ##
## pound 4.5 test suite. ##
## -------------------------- ##
1: Configuration file syntax ok
2: Basic request processing ok
3: xHTTP ok
4: CheckURL ok
5: Custom Error Response ok
6: MaxRequest ok
7: HeadRemove ok
8: AddHeader ok
9: RewriteLocation ok
10: HeadRequire ok
11: URL ok
## ------------- ##
## Test results. ##
## ------------- ##
All 11 tests were successful.
If a test results in something other than ok
, it leaves the detailed
diagnostics in files in the tests/NN/testsuite.dir
directory, where
NN is the ordinal number of the test. Pack them all into a single
tarball and send it over to gray@gnu.org for investigation. See
also the section Bug Reporting below.
If both building and testing succeeded, it's time to install pound. To do so, run the following command as root:
make install
Pound looks for its configuration file in a location defined at
compile time, normally /etc/pound.cfg
,
or /usr/local/etc/pound.cfg
. The configuration file syntax is discussed
in detail in the manual.
Here we will describe some example configurations.
Any pound configuration must contain at least two parts:
a ListenHTTP
(or ListenHTTPS
) section, that declares a frontend,
i.e. the end of the proxy that is responsible for connection with the
outside world, and Service
section with one or more Backend
sections
within, which declares where the incoming requests should go. The
Service
section can be global or it can be located within the
ListenHTTP
block. Global Service
sections can be shared between
two or more ListenHTTP
sections. Multiple Service
sections can
be supplied, in which case the Service
to use when handling a
particular HTTP request will be selected using the supplied criteria,
such as source IP address, URL, request header or the like.
The following configuration instructs pound to listen for incoming HTTP requests on 192.0.2.1:80 and pass them to single backend on 10.10.0.1:8080.
ListenHTTP
Address 192.0.2.1
Port 80
Service
Backend
Address 10.10.0.1
Port 8080
End
End
End
Notice, that the two statements Address
, and Port
are in general
mandatory both in ListenHTTP
and in Backend
. There are two
exceptions, however: if Address
is a file name of a UNIX socket
file, or if an already opened socket is passed to pound via the
SocketFrom
statement. These two cases are discussed below.
Argument to the Address
statement can be an IPv4 or IPv6 address,
a hostname, that will be resolved at program startup, or a full
pathname of a UNIX socket file.
This example shows how to configure HTTPS frontend and redirect all
plain HTTP requests to it. It assumes the domain name of the site
is www.example.org
and its IP address is 192.0.2.1.
# Declare HTTP frontend
ListenHTTP
Address 192.0.2.1
Port 80
Service
# Redirect all requests to HTTPS. The redirection
# target has no path component, which means that the
# path (and query parameters, if any) from the request
# will be preserved.
Redirect 301 https://www.example.org
End
End
# Declare HTTPS frontend.
ListenHTTPS
Address 192.0.2.1
Port 443
# Certificate file must contain the certificate, optional
# certificate chain and the signature, in that order.
Cert "/etc/ssl/priv/example.pem"
# List of certificate authority certificates.
CAlist /etc/ssl/acme/lets-encrypt-root.pem"
# Disable obsolete protocols (SSLv2, SSLv3 and TLSv1).
Disable TLSv1
Service
Backend
Address 10.10.0.1
Port 8080
End
End
End
To implement virtual hosts, one needs to instruct pound to
route requests to different services depending on the values of
their Host:
headers. To do so, use the Host
statement in the
Service
section.
The argument to Host
specifies the host name. When an incoming request
arrives, it is compared with this value. The Service
section will be
used only if the value of the Host:
header from the request matched the
argument to the Host
statement. By default, exact case-insensitive
comparison is used.
Let's assume that you have internal server 192.168.0.10 that is supposed to serve the needs of virtual host www.server0.com and 192.168.0.11 that serves www.server1.com. You want pound to listen on address 192.0.2.1. The configuration file would look like this:
ListenHTTP
Address 192.0.2.1
Port 80
Service
Host "www.server0.com"
Backend
Address 192.168.0.10
Port 80
End
End
Service
Host "www.server1.com"
Backend
Address 192.168.0.11
Port 80
End
End
End
The same can be done using ListenHTTPS
.
If you want to use the same service for both the hostname and the
hostname prefixed with www.
, you can either use the Match
statement,
or a regular expression.
A Match
statement groups several conditions using boolean shortcut
evaluation. In the following example, boolean or is used to group
two Host
statements:
Service
Match OR
Host "server0.com"
Host "www.server0.com"
End
Backend
Address 192.168.0.10
Port 80
End
End
When this service is considered, the value of the Host:
header from the
incoming request is matched against each host listed in the Match OR
statement. If any value compares equal, the match succeeds and the service
is selected for processing the request.
By default, the Host
directive uses exact case-insensitive string match.
This can be altered by supplying one or more options to it. In the example
below, we use regular expression matching to achieve the same result as in
the configuration above:
Service
Host -re "^(www\\.)?server0\\.com$"
Backend
Address 192.168.0.10
Port 80
End
End
Notice double-slashes: a slash is an escape character and must be escaped if intended to be used literally.
Pound is able to keep track of sessions between a client browser and a backend server. Unfortunately, HTTP is defined as a stateless protocol, which complicates matters: many schemes have been invented to allow keeping track of sessions, and none of them works perfectly. What's worse, sessions are critical in order to allow web-based applications to function correctly - it is vital that once a session is established all subsequent requests from the same browser be directed to the same backend server.
Six possible ways of detecting a session have been implemented in pound (hopefully the most useful ones): by client address, by Basic authentication (user id/password), by URL parameter, by cookie, by HTTP parameter and by header value.
Session tracking is declared using the Session
block in Service
section. Only one Session
can be used per Service
. The type of
session tracking is declared with the Type
statement.
Type IP
: Session tracking by addressIn this scheme pound directs all requests from the same client IP address to the same backend server. Put the lines
Session
Type IP
TTL 300
End
in the configuration file to achieve this effect. The value indicates what period of inactivity is allowed before the session is discarded.
Type Basic
: by Basic AuthenticationIn this scheme pound directs all requests from the same user (as identified in the Basic Authentication header) to the same backend server. Put the lines
Session
Type Basic
TTL 300
End
in configuration file to achieve this effect. The value indicates what period of inactivity is allowed before the session is discarded.
This type is a special case of the Type Header
, described below.
WARNING: given the constraints of the HTTP protocol it may very well be that the authenticated request will go to a different backend server than the one originally requesting it. Make sure all your servers support the same authentication scheme!
Type URL
: by URL parameterQuite often session information is passed through URL parameters
(the browser is pointed to something like http://xxx?id=123
).
Put the lines
Session
Type URL
ID "id"
TTL 300
End
to support this scheme and the sessions will be tracked based on the value
of the id
parameter.
Type Cookie
: by cookie valueApplications that use this method pass a certain cookie back and forth. Add the lines
Session
Type Cookie
ID "sess"
TTL 300
End
to your configuration file - the sessions will be tracked by the value of
the sess
cookie.
Type Parm
: by HTTP parameter valueApplications that use this method pass an HTTP parameter
(http://x.y/z;parameter
) back and forth. Add the lines
Session
Type PARM
TTL 300
End
To your configuration file - sessions will be tracked by the value of the parameter.
Type Header
: by header valueApplications that use this method pass a certain header back and forth. Add the lines
Session
Type Header
ID "X-sess"
TTL 300
End
to your configuration file - the sessions will be tracked by the value of
the X-sess
header.
Please note the following restrictions on session tracking:
Service
. Thus, each
group may have other methods and parameters.Service
. If your application
has alternative methods for sessions you will have to define a separate
Service
for each method.A note on cookie injection: some applications have no session-tracking mechanism at all but would still like to have the client always directed to the same backend time after time. Some reverse proxies use a mechanism called cookie injection in order to achieve this: a cookie is added to backend responses and tracked by the reverse proxy.
Pound was designed to be as transparent as possible, therefore this
mechanism is not supported. If you really need this sort of persistent
mapping use the client address session mechanism (Type IP
), which
achieves the same result without changing the contents in any way.
If pound operates in daemon mode (the default), all diagnostics
goes to the syslog facility daemon
. Pound switches to syslog right
before it disconnects from the controlling terminal. Until then, it
sends its messages to the standard error.
By default only error and informative messages are logged. The amount
of information logged is controlled by the LogLevel
configuration
statement. Possible settings are:
0
No logging.
1
Regular logging: only error conditions and important informative
messages are logged.
2
Extended logging: show chosen backend servers as well.
3
Log requests using Apache-style Combined Log format.
4
Same as 3, but without the virtual host information.
5
Same as 4 but with information about the Service
and Backend
used.
The LogLevel
statement can be global (effective for all listeners),
as well as per-listener.
Pound can obtain socket to listen on from another program via
a UNIX socket. This mode of operation is requested by the following
statement in ListenHTTP
section:
SocketFrom "/path/to/socket"
When this statement is present, neither Address
nor Port
may be
used in this listener. Pound will connect to the named socket and
obtain the socket descriptor from it. Then it will start listening
for incoming requests on that socket.
This can be used both in ListenHTTP
and ListenHTTPS
sections.
Currently it is used in pound testsuite.
Normally, pound passes all incoming requests to backends
verbatim. Several request modification directives are provided, that
allow you to add or remove headers from the request. The following
two groups of headers are added by default. Each of them can be turned
off using the HeaderOption
directive.
The forwarded headers:
X-Forwarded-For:
header passes the actual IP address of the client
machine that sent the request.
X-Forwarded-Proto:
header contains the original protocol (http
or
https
).
X-Forwarded-Port:
header contains the port on the server that the
client connected to.
Second group contains ssl headers that are added only if the client
connected using HTTPS. The X-SSL-Cipher
header is always present if
this header group is enabled. The rest of headers below is added only if
the client certificate was supplied:
X-SSL-Cipher
: SSL version followed by a slash and active cipher algorithm.
X-SSL-Certificate
: the full client certificate (multi-line).X-SSL-Issuer
: information about the certificate issuer (CA).X-SSL-Subject
: information about the certificate owner.X-SSL-notAfter
: end od validity date for the certificate.X-SSL-notBefore
: start of validity date for the certificate.X-SSL-serial
: certificate serial number (in decimal).The HeaderOption
directive can be used (either globally or in listener
block) to disable any or both of these groups, e.g.:
HeaderOption no-ssl forwarded
Any number of headers can be added or removed using the HeaderAdd
and
HeaderRemove
directives in the listener section. The order in which these
directives are applied is:
HeaderOption
directive are added.HeaderRemove
directives are removed.HeaderAdd
directives are added.Pound offers built-in support for ACME (a.k.a. LetsEncrypt) HTTP-01 challenge type. Thus, it can be used with any certificate controller to obtain SSL certificates on the fly.
Assuming your certificate controller is configured to store challenges in
directory /var/lib/pound/acme
, all you need to do is add the ACME
statement to the ListenHTTP
block, for example:
ListenHTTP
ACME "/var/lib/pound/acme"
.
.
.
End
Now, each request whose URL ends in /.well-known/acme-challenge/NAME
will be served by directly by pound: it will send the content of
the file /var/lib/pound/acme/NAME
as a reply.
RootJail
The RootJail
configuration directive instructs pound to chroot
to the given directory at startup. Normally, its use should be quite
straightforward:
RootJail "/var/pound"
Pound tries to open all files and devices it needs before chrooting. There might be cases, however, when it is not enough and you would need to copy certain system files to the chroot directory.
When using RootJail
, pound does not remove its PID file
before shutting down.
If pound displays the following message and aborts when being stopped:
libgcc_s.so.1 must be installed for pthread_cancel to work
then you need to copy that library to the RootJail
directory, e.g.:
mkdir /var/pound/lib64
cp /usr/lib64/libgcc_s.so.1 /var/pound/lib64
or make sure it is loaded at program startup by defining the
LD_PRELOAD
variable:
export LD_PRELOAD=/usr/lib64/libgcc_s.so
This problem was fixed in version 4.7 (see the description of the
--enable-pthread-cancel-probe
configure option above).
If you think you found a bug in pound or in its documentation, please send a mail to Sergey Poznyakoff gray@gnu.org (or gray+pound@gnu.org.ua), or use the github issue tracker.
Please login to review this project.
No reviews for this project yet.
IPv4 over DNS tunnel solution, enabling you to start up a s…
Nginx Proxy Manager is an easy way to accomplish reverse pr…
Non-caching web proxy with advanced filtering capabilities …
Comments (0)
Please login to join the discussion on this project.