Pound -- history of user-visible changes. 2026-11-06 See the end of file for copying conditions. Pound is a continuation of the software originally developed by Robert Segall at Apsis GmbH, which was officially discontinued on 2022-09-19. See the README file for details. Please send pound bug reports to Version 4.24.90 * Relative redirects The Redirect statement now accepts relative URI as its argument. * ACLs in Tunnel section Usual ACL statements are allowed in Tunnel sections. The connection will be served only if the source IP matches one of the CIDRs in them. * New metric family pound_beacon States (on/off) of beacons declared in the configuration. * Fixed memory leak in metrics backend Version 4.24, 2026-10-29 * Changes in configuration syntax. ** Sizes Arguments to the following keywords can be suffixed with usual size suffixes "k", "m", and "g" or their upper-case equivalents: ContentCapture LineBufferSize MaxURI WorkerStackSize ** Durations A duration is a sequence of decimal numbers, each of which is followed by a time unit suffix, "s", "m", "h" or "d", standing for seconds, minutes, hours, or days, correspondingly. The suffix is optional for the last number in the sequence, in which case "s" is assumed. The following keywords take a duration value as argument: Alive Client ConnTO Grace OverrideTTL RetryInterval TTL (in the "Session" section) TimeOut WSTimeOut WatcherTTL WorkerIdleTimeout ** Synchronization lines Synchronization lines in traditional formats are understood: #line N #line N "FILE" # N # N "FILE" ** Pragmatic comments Comments that start with the word "pragma" are treated specially. Such comments modify parsing of the configuration file. This version introduces two pragmatic comments: #pragma preprocessor COMMAND Enables configuration file preprocessing. See below for details. #pragma tab-width N Instructs pound to consider each TAB character to be equal to N spaces. This is used when computing column offsets in configuration file, for diagnostic and reporting. * Cert and ACME statements take into account include directory Arguments to "Cert" or "ACME" are taken relative to the current include directory. * Wildcards are allowed in Cert statement The argument to the "Cert" directive in "ListenHTTPS" can contain glob(7) patterns, e.g.: Cert "ssl/*.pem" * Placement of Cert directive within ListenHTTPS In previous versions, the "Cert" directive was required to precede any other SSL-specific statement (such as "ClientCert", etc.) in the "ListenHTTPS" section. This is no longer the case. This directive can now be placed anywhere within "ListenHTTPS". * The "Use" statement in Backend sections The "Use" statement inherits settings from a named backend referred to by its argument. The "Priority" and "Disables" directives can be used together with it, e.g.: Service Backend Use "nb" Priority 3 End End * HTTPS statement in Backend sections In previous versions, the "HTTPS" statement was required to be used prior to any of the following statements in a Backend section: Cert, Ciphers, Disable. This requirement was lifted. Moreover, any of these statements already imply that the backend is HTTPS capable, which means that the "HTTPS" statement can be omitted if any of these is used. * Fall-through services This version introduces a new kind of services: fall-through services. If the request matches such a service, any modification statements from that service are applied to the request, and the selection process continues from the next service. In other words, a fall-through service provides a way to apply a set of modifications common for all services that follow. A service is declared as fall-through using the "FallThrough" statement. Such services cannot contain backend definitions or "Rewrite response" statements. An example of a fall-through service follows: Service Path -beg "/status/" SetHeader "Host: internal" LogSuppress success FallThrough End * Early rewrites A new flavor of the "Rewrite" statement is introduced: Rewrite early In contrast to normal rewrites, which are applied to requests before passing them on to the corresponding backends, "Rewrite early" statements are applied at the early stage of request processing so that the resulting modifications become visible to subsequent configuration statements. "Rewrite early" sections used in ListenHTTP (or ListenHTTPS) sections are applied first, right after the request headers have been received and parsed. Those used in Service sections, are applied during service selection, before applying service selection statements for that service. It is important to notice that any modifications done by early rewrites in a Service section remain visible for subsequent sections, if this one is not selected for processing the request. To summarize, this release provides two mechanisms for making request modifications visible to conditional statements: early rewrites and fall-through sections. * Beacons Beacons are special boolean values that can be used in conditional statements to select the service to use. Beacons can change their value only via the pound control interface, using poundctl or similar tool. Beacons provide a mechanism for adopting pound configuration to changes in external conditions (such as current load average or request rate) without the need to reconfigure the pound daemon. Beacons are declared using the "DeclareBeacon" statement in the global scope: DeclareBeacon "NAME" [BOOL] Beacons are examined using the "Beacon" statement in "Section", "Match", or "Rewrite" section, e.g.: Beacon "NAME" To change or inspect the actual value of a beacon, use poundctl: poundctl beacon Examine all declared beacons and their values. poundctl beacon NAME Examine the value of beacon NAME. poundctl -s NAME Set beacon NAME to "true". poundctl -d NAME Set beacon NAME to "false". * Query accessor The "query" accessor takes an optional argument. If the query part is present, the argument is prepended to the expansion. This is useful when rewriting URLs, for example: Rewrite 308 "https://example.com/%[query ?]" * Request timings The %T log conversion specifier takes an optional prefix, that determines the starting point for time measuring. Its possible values are init The time between establishing connection or sending last byte of the previous response and sending last byte of the response to the client. req The time between receiving first byte of the request and sending last byte of the response to the client. This is the default. reqend The time after receiving last byte of the request header and sending last byte of the response to the client. be The time between sending first byte to the backend and sending last byte of the response to the client. E.g.: "%{reqend:us}T" Similar extension applies to the "D" conversion. Here, the prefix indicates the stage of request processing whose duration is requested. Its values are: init Time between establishing the connection or sending last byte of the previous response and receiving first byte of the request. header Total time reading the request headers, i.e. between receiving first byte of the request and sending it over to the backend. select Time spent selecting the service and backend. resp Time taken by response processing, i.e. time elapsed between the moment when the service and backend have been selected and the moment after the last byte of the response has been sent to the client. be Time between sending first byte to the backend and sending last byte of the response to the client. totalreq Time between receiving first byte of the request and sending last byte of the response to the client. grandtotal Time between establishing the connection or sending last byte of the previous response and sending last byte of the response to the client. * Tracing Tracing helps in debugging complex service selection or rewrite conditions. Each service has an associated trace flag. When this flag is set, each evaluated conditional is reflected in the pound log. Example output: (7f2d5534f640) Request from: 192.0.2.11 (7f2d5534f640) Request: GET /media/id.jpg HTTP/1.1 (7f2d5534f640) Headers: (7f2d5534f640) Host:example.com (7f2d5534f640) User-Agent: Mozilla/5.0 (7f2d5534f640) Accept: */* (7f2d5534f640) service selection: pound.cfg:29.9-36.11:considering service (7f2d5534f640) service selection: pound.cfg:30.17-26: header: 1 (7f2d5534f640) service selection: pound.cfg:31.17-25: path /media: 1 (7f2d5534f640) service selection: implicit AND: 1 (7f2d5534f640) service selection: pound.cfg:29.9-36.11: service selected The value in parentheses identifies the worker thread that did the selection. The result of each conditional is printed as a boolean value (0/1). To manage trace flags, a new poundctl subcommand, trace, is provided: - poundctl trace /L/S Show trace flag for service S in listener L. - poundctl trace -s /L/S Set trace flag for service S in listener L. - poundctl trace -d /L/S Delete (unset) trace flag for service S in listener L. The object path specification can be shortened to /L, to operate on all services in the listener L, or to /, to operate on all services defined in the configuration. * Preprocessing Configuration files can be optionally preprocessed using an external program. To do so, specify the command line of the preprocessor in the "preprocessor" pragmatic comment appearing in the very beginning of the principal configuration file, like that: #pragma preprocessor m4 -s It is important that this comment appears before the first configuration statement. Comments and empty lines before it are allowed. A new command line option -E instructs pound to print the preprocessed text and exit. Version 4.23, 2026-05-26 * Important bugfix A bug in "SendFile" allowed for reading files outside of the configured directory. This is fixed. * Compilation The early pthread_cancel probe hack is no longer used. Consequently, the "--disable-pthread-cancel-probe" configure option is gone. * Handling of errors during service selection In previous versions, if service selection failed due to an error (e.g. because a non-existing backreference was used, a run-time error in a Lua function occurred, or the like), that service would be skipped as if its conditions returned false, and the next one would be tried. This could lead to selecting an improper service in case of error. Starting from this version, any error occurring during service selection causes pound to return internal server error (500). * File descriptor usage At startup, pound closes all inherited file descriptors numerically greater than 2. If this is undesirable for some reason, use the -Wno-close-extra-fds command line option. Capacity of the incoming connection queue (used when all workers become busy) is computed so as to prevent the program from running out of file descriptors. It can also be set explicitly, using the "ConnectionQueueSize" configuration file statement. * Configuration constants The "Constant" statement defines a configuration constant for use in string expansions and Lua code. A constant is a string value identified by a unique name. The "Constant" statement can appear in top-level, listener, and service scopes. The syntax is: Constant "NAME" "VALUE" or Constant "NAME" OPTIONS where OPTIONS are: -file FILE Read constant value from the file FILE at startup. -filewatch FILE Read constant value from the file FILE, and monitor it during the runtime for changes. -trim Trim off the trailing whitespace from the obtained value. Constants can be used in string expansions (using the "%[const NAME]" accessor), and in Lua code (using the "http:const(NAME)" method). Refer to the documentation, section "Constants", for a detailed discussion with examples. * Tunnels A tunnel passes an opaque stream of bytes between the client and backend. It is defined in configuration file using the following construct: Tunnel [ "ID" ] Address IPADDR Port PORT Backend Address IPADDR Port PORT End End Naturally, only one backend is allowed. Similarly to other listeners, the Address/Port pair in the Tunnel section can be replaced with a single SocketFrom statement. The following statements are allowed in Backend subsection: Timeout, ConnTO, Disabled. * Runtime log level control The "poundctl" command can be used to inspect log level settings or to change them without restarting pound. - poundctl log [/] Show global log level. - poundctl log /L Show log level for the listener L. - poundctl log /[L] F Set log level F. If argument is "/", global log level is set. Otherwise, log level for the listener L is set. - poundctl log -d /L Clears log level setting for the listener L. As a result, the listener will use global log level. - poundctl log -d [/] Set global log level to "null". * Lua: access to the originator IP Two new fields are available in the "http" table: * http.rmt_ip Request originator IP address (as string). * http.fwd_ip Request originator IP address (as string), determined using the X-Forwarded-For (or similar) header. If the request bears no such header or if the TrustedIP list is not declared, this is equivalent to http.rmt_ip. Version 4.22, 2026-03-29 * Remove spurious log messages. * Metric backend: close connection after response. * Support IPv4 mapped to IPv6 in ACLs. It is no longer necessary to use ::ffff: notation in ACLs to match mapped IPv4 addresses. Using is enough. * Support for split Header and Host conditions is rewritten A split "Header" condition is Header "NAME" [OPTIONS] "PATTERN" In previous versions, this construct was internally translated to a "Header -re ..." statement, and that introduced several inconsistencies. In particular, when using the "-re" option, "PATTERN" was treated as anchored, i.e. as if it started with a "^". Besides, -exact and -prefix were treated as equivalent. This is now fixed. The new implementation strictly follows the logic of the statement: it compares each header whose name is "NAME" with "PATTERN" in accordance with the given OPTIONS. This applies also to "Host" condition, which is equivalent to Header "Host" [OPTIONS] "PATTERN" * Bugfixes ** Fix durations on 32-bit architectures. ** Fix recognition of truncated request capture. Version 4.21, 2026-03-14 * Changes in Lua API ** http.balancer Balancer group of the currently selected backend. Setting this field to a numeric value instructs pound to re-send the request to a backend from the balancer group with the weight greater than or equal to the value supplied. ** http.resendcount Keeps number of resending attempts underwent by the current request. ** http.service.name Name of the currently selected service. Assigning to this variable instructs pound to send the current request to the named service. Assigning a nil also implies to rerun service selection from the beginning. ** http.service.locus Location of the currently selected service in the configuration file. * Setting ciphersuites for TLSv3 The syntax of the "Ciphers" statement (ListenHTTPs and Backend sections) has been extended to allow for specifying ciphersuites for TLSv3 protocol. The new syntax is: Ciphers [typeopt] "cipherlist" ... where optional typeopt option defines how to interpret the cipherlist argument that follows it. Its possible values are: -cipherlist Sets the list of ciphers that affects only TLSv2 and prior protocols. This is the default. -ciphersuites Sets the list of TLSv3 ciphersuites. It will be combined with any TLSv1.2 and below cipher lists that may have been configured. Notice, that a single "Ciphers" statement can set both TLSv2 and TLSv3 ciphersuites: Ciphers "HIGH:@STRENGTH:!RSA" -ciphersuites "TLS_AES_256_GCM_SHA384" * New configuration setting: WorkerStackSize Sets worker thread stack size, in bytes. * Lua compile-time check The compile-time check for Lua no longer depends on pkg-config. Version 4.20, 2026-02-06 * New selection statement: Method This conditional statement evaluates to true, if the request method matches the supplied pattern, e.g.: Service Method "POST" ... End * New internal backend: Success Always returns a 200 response code. This is intended mainly for handling special requests. For example, the service definition below replies to the OPTIONS requests: Service Method "OPTIONS" Rewrite response SetHeader "Access-Control-Allow-Origin: example.com" SetHeader "Access-Control-Allow-Methods: GET,POST,PUT" SetHeader "Access-Control-Max-Age: 1800" End Success End * Changes in Lua API ** http.req.body This field contains the captured content of the incoming request. For it to be available, content capturing must be explicitly enabled for the service on whose behalf the Lua code is called. Content capturing is enabled by the following new configuration statement: ContentCapture SIZE where SIZE sets the upper limit on the captured content size. If the actual content length is greater than this value, saved material is discarded and http.req.body is set to nil. ** http.resend Lua functions invoked in "Rewrite response" can set this variable to 'true' to have pound resend the modified request to backend. To avoid dead loops, pound limits the number of such resends to 4 per request. Version 4.19, 2025-12-11 * Support for Lua Functions written in Lua can be used to implement complex request matching conditions, modify requests and/or responses, and implement new backends. You will need Lua version 5.3 or newer. By default, configure will enable Lua support if it finds the necessary headers and libraries. This can be controlled using --disable-lua and --enable-lua options. At runtime, Lua sources are loaded using Load statement in the Lua global section of the configuration file: Lua Load "impl.lua" End A function returning boolean value can be used as a conditional: LuaMatch "myfun" "arg" Any number of arguments (all of string type) can be provided. Arguments undergo usual expansions prior to being passed to the function. Two more similar statements are added: LuaModify - Applies a Lua function to modify the request (or response). It can be used in ListenHTTP, ListenHTTPS, Service, Match and Rewrite statements. LuaBackend - Calls a Lua function that implements a backend. * Detached conditions Detached condition is a set of conditional statements not associated with any service, which is assigned a unique symbolic name. Detached conditions are defined using the Condition statement in the global scope of pound configuration file, e.g.: Condition "protected" Path -beg "/admin" ACL -file "internal.acl" BasicAuth "htpasswd" End Detached conditions can be invoked using the "Eval" statement, which is allowed anyplace where the normal conditional is allowed. Result of evaluation is cached and reused in subsequent Eval statements referring to the same condition. E.g.: Service Eval "protected" ... End Detached conditions provide a convenient way to define conditional statements with are used repeatedly in multiple Service statements. * New request modification statement: DeleteQuery Removes query part of the request URL. * One-argument form of SetQueryParam When used with one argument (name of a query parameter), SetQueryParam causes removal of that query parameter. * Percent encoding and decoding The Path and QueryParam conditional statements accept new option -decode. When given this option, the value will undergo percent-decoding prior to comparison. E.g.: QueryParam "t" -decode "?" Similarly, SetPath and SetQueryParam statements accept new option -encode. When given this option, the value will be percent-encoded prior to setting it. * Relative pathname in SendFile statement. If the argument to SendFile statement is not an absolute file name, it is resolved relative to pound include directory. * Turning PID file off. To disable PID file creation, use PIDFile "-". Version 4.18, 2025-10-29 * Emacs mode for editing pound configuration files Major mode for editing pound configuration files in GNU Emacs is implemented in file src/pound-mode.el. Its installation and usage is covered by Chapter 11 of the Pound Manual, entitled "Emacs Major Mode". * Include statement accepts globbing patterns If the argument to "Include" configuration statement is a shell globbing pattern, all regular files matching that pattern will be included, in lexicographical order. * New configuration statement: LineBufferSize Sets the line buffer size. Line buffer is used when reading request line, backend response status line, and header fields in both requests and responses. Thus, this value limits the maximum length allowed for these parts of HTTP messages. By default, it is set to the internal buffer size (4096), which is also its minimum allowed value. This statement can be used in global scope and within ListenHTTP (ListenHTTPS) sections. * TBF statement This conditional statement implements token bucket filter. Its arguments are: the ID of the bucket (a string, subject to backreference expansion and request accessor interpretation), maximum allowed rate (requests per second) and a burst size (number of requests). The statement evaluates to true if the token bucket accepts the request and to false otherwise. See Pound Manual, Section 4.6 "Rate-limiting", for a detailed discussion. * New request accessor: remoteip %[remoteip 0] expands to the real originator IP; %[remoteip 1] expands to the IP determined from the X-Forwarded-For (or similar) header. * Originator IP for ACL matching By default, ACLs are applied to the IP address from which the request was received. It is now possible to use the IP obtained from X-Forwarded-For header, instead. To do so, use the -forwarded option keyword, e.g.: ACL -forwarded -file "acl.lst" * Changes in log format specifications ** Expansion of %v changed The %v specifier now expands to the host name used in the request, as obtained from the "Host" header, with port specification removed. If you want the old expansion (name of the listener that served the request), use "%{listener}N". ** Support for new specifiers . %l Reserved for future use. Expands to single dash. . %p Port number of the listener that served the request. ** Built-in formats changed accordingly: 3, "vhost_combined" "%v:%p %a %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-Agent}i\"" 4, "combined" "%a %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-Agent}i\"" 5, "detailed" "%v:%p %a %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-Agent}i\" (%{service}N -> %{backend}N) %{f}T sec" * poundctl core This command shows core pound statistics: server time, daemon version, pid, and uptime, as well as worker threads configuration and statistics. * Openmetrics output Metrics describing listeners and services are labeled by the listener and service names, as well as by their ordinal numbers in the configuration. * Testsuite: optionally use multi-process model If Perl is built without ithreads, testsuite harness switches to multi-process model. Version 4.17, 2025-07-29 * Tagging conditional statements All conditional statements that match against a pattern can be tagged using the following option: -tag "T" where T is an arbitrary string. This tag can then be used to refer to a subexpression obtained as a result of matching, for example: Path -tag "dir" -re "^/static(/.*)" Header -tag "type" "Content-Type:([^/]+)/([^;]+)" SetPath "/assets/$1(type).$2(type)$1(dir)" * Changes to the "ACL" statements Two new forms of the ACL statements are provided: - ACL -file "NAME" Reads ACL from the file NAME. The file shall contain a list of CIDRs, one per input line. CIDRs need not be quoted. Empty lines and comments are allowed. The file is read once, at program startup. - ACL -filewatch "NAME" Same as above, but the file will be monitored for changes during the runtime. If a change is detected, the file will be rescanned and the ACL updated. To ensure file changes are noticed immediately, pound relies on filesystem monitoring API provided by the operating system - inotify on GNU/Linux systems and kqueue on BSD. On systems not supporting either interface, the file will be checked periodically. The interval between two successive checks is defined by the WatcherTTL global directive. The corresponding new forms are implemented for all ACL statements, i.e.: - Named ACLs: ACL "name" -file "filename" ACL "name" -filewatch "filename" - Trusted IP lists: TrustedIP -file "filename" TrustedIP -filewatch "filename" * Use of "-filewatch" with request matching directives In addition to ACL, the -filewatch flag discussed above can be used with the following request matching directives: Header, Path, Query, QueryParam, StringMatch, URL. * Changes to the "BasicAuth" statement The statement takes an option: -filewatch or -file. The option -filewatch is the default (see above). The -file option can be used to disable file change monitoring. * Changes to the "Header" statement New statement form is introduced: Header "FIELD" [OPTIONS] "VALUE" In this form, pattern modification options apply to header value only, e.g. Header "Content-Type" -beg "text/" * New special backend "SendFile" This backend treats the path part of the request as local file name and sends back the contents of that file, if it exists. Default content type is "text/plain". Both parameters can be changed using request (for file name), and response (for content type) rewriting. The syntax is: SendFile DIR where DIR specifies the directory from which to serve files. * Error file contents Error file supplied with "Error", "ErrorFile", or any "ErrNNN" directvie, can begin with HTTP headers. If so, these will be sent along with the response, and the actual response contents will begin after the empty line that terminates the headers. * Error response rewriting When a regular backend responds with an error, the content (body) of that response can be replaced with an arbitrary custom page. For this to work, the listener must define a custom page for the status code in question using the ErrorFile statement, and error response rewriting must be explicitly enabled. The latter is done with the following statement: RewriteErrors on The statement can be used both in ListenHTTP (ListenHTTPS) and in Service blocks, the latter overriding the former. * Bugfixes ** Improper pattern handling in patterns read from file When using -file with one of the following pattern types: -exact, -beg, -end, -contain, only first pattern from the file was compiled using the requested pattern type. Remaining ones were treated as POSIX regular expressions. Version 4.16, 2025-01-13 * Fix backend probing when compiled without support for dynamic backends. * Reject requests with oversized chunk bodies. * Handle errors that occur during evaluation of conditionals. Version 4.15, 2024-11-17 * New configuration statement: IgnoreSRVWeight Instructs pound to ignore weight value of an SRV record when generating new backend from it. Priority of the generated backend is copied from its matrix backend. * New configuration statement: OverrideTTL When used with dynamic backends, instructs pound to use the supplied value as TTL, instead of the one returned in DNS response. * Load balancing code revisited Removed arbitrary limit on backend priority value. The allowed range is now 1..65535. Remove priority mapping for SRV-generated backends. SRV weights are assigned to backend priorities verbatim. * Fix access to freed memory in session handling code. * Improve testsuite Check for missing perl modules and skip tests if needed. DNS-based tests are disabled by default, due to their experimental nature. Use --enable-dns-tests to enable them. The poundharness.pl script runs a self-test when invoked with the --fakedns option, to avoid spurious test failures. Version 4.14, 2024-10-13 * Dynamic backends Dynamic backends are created and updated on the fly based on the information from DNS. To declare backend as dynamic, use a symbolic host name in its "Address" statement and add the "Resolve" statement with one of the following values: first Resolve the symbolic host name and use first IP from the DNS response as the address of the created dynamic backend. Thus, at most one dynamic backend will be created. all Resolve the symbolic host name and create one backend for each address from the DNS response. This enables load balancing between created backends. Each backend will be assigned the same priority. srv Obtain SRV records for the host name and use them to generate regular backends. Each record produces new dynamic backend of "Resolve all" type, which creates regular backends as described above. The weight field of the SRV record is mapped to the priority field of each generated backend. The SRV priority field determines the balancing group (see below) where the backend will be hosted. By default, both IPv4 and IPv6 addresses are looked for. You can select the specific address family using the "Family" statement. Its allowed values are: any Use all address families available. This is the default. inet Use only IPv4 addresses. inet6 Use only IPv6 addresses. For example: Backend Address "be0.example.net" Port 8080 Resolve first Family inet End Dynamic backends will be updated periodically, when the TTL of the corresponding DNS records expires. If the hostname cannot be resolved or a DNS failure occurs, next update will be scheduled in 600 seconds after the failure. This interval can be configured using the "RetryInterval" statement in the "Backend" section, or globally, in the "Resolver" section. The "Resolver" section allows you to control how DNS lookups are performed. It can contain the following directives: CNAMEChain (integer) Maximum allowed length of a "CNAME chain". CNAME chains are formed by DNS CNAME records pointing to another CNAME. Although prohibited by the RFC, such usage occurs sometimes in the wild. By default, pound does not accept CNAME chains. If you work with a nameserver that uses them, set this statement to a small integer value, defining maximum number of CNAMEs in the chain that pound will accept. The value of 2 or 3 should suffice in most cases. ConfigFile (string) Name of the resolver configuration file. Default is "/etc/resolv.conf". ConfigText ... End The material within this section is read verbatim and used as the content of the resolver configuration file. If both ConfigFile and ConfigText are used, the last statement used wins. Debug (boolean) Whether to enable DNS debugging info. RetryInterval (integer) Interval in seconds, after which to retry failed DNS queries or queries that returned no RRs. This value is used unless the backend defines its own retry interval value. Dynamic backends can be controlled using poundctl. For example, consider the following output from "poundctl list": 1. Listener http://192.0.2.1:80 enabled 0. Service active (5) 0. matrix "be0.example.com" 2 0 active 1. backend http 198.51.100.15:8081 5 alive active 2. backend http 203.0.113.121:8081 5 alive active 3. backend http 192.0.2.203:8081 5 alive active The backend 0 ("matrix") refers to the "Backend" statement in the configuration file that produced the other three dynamic backends. Disabling it (poundctl disable /1/0/0) causes the dynamic ones to be removed. Enabling it will create them again. In a pinch, this can be used to force backend re-creation prior to TTL expiration. ** Compiling To enable dynamic backend support, you will need the adns library. On debian-based systems, it is installed by the following command apt-get install libadns1-dev If all preconditions necessary for enabling dynamic backends are met, the output from configure will end with the following status line: Dynamic backends .............................. yes ******************************************************************* When compiled with the dynamic backend support, output of "pound -V" will contain the following line in the "Built-in defaults" section: Dynamic backends: enabled * Backend groups Backend groups are a new pound feature, that extends the idea of regular and emergency backends used in previous versions. Any number of backend groups can be associated with a service. Each group is assigned an integer number (weight). The groups are ordered by weight (in ascending order) and are tried in that order when looking for a backend to serve the request. The look up starts with the first group. The balancing algorithm configured for the service is applied. If no backend can be selected, next group will be tried, and so on. In the static configuration, regular backends are hosted in backend group of weight 0 and emergency (high availability) backends are stored in group of weight 65535. One consequence of this is that any number of Emergency backend declarations are now allowed in a service. More backend groups can be allocated when using dynamic backends of "srv" resolve type (see above). * Emergency backends Any number of emergency backends can be defined. Usual request balancing algorithm applies when selecting an emergency backend. All statements valid within a "Backend" section are also valid within an emergency backend declaration. * Listener address configuration Both "Address" and "Port" statements are now optional. If "Address" is omitted, pound will listen on all available interfaces. If "Port" is omitted (and not listening on a UNIX socket), default port number for this kind of listener will be used: 80, for "ListenHTTP", and 443, for "ListenHTTPS". * New request matching conditional: ClientCert The syntax is: ClientCert "FILENAME" The conditional evaluates to true if the client presented the certificate matching that from the given file (PEM format). It cannot be used in standalone services (i.e. services that are defined in global scope). It also cannot be used if the "ListenHTTPS" section that hosts the service has the "ClientCert" statement on its own. * Remote access to the management interface A new backend type "Control" is introduced to make it possible to access the management interface remotely. The example below shows how to configure pound to expose the management interface on http://192.0.2.1:3434: ListenHTTP Address 192.0.2.1 Port 3434 Service ACL "secure" Control End End * poundctl Changes in poundctl functionality reflect those in the management interface. First of all, the -s option accepts URL as its argument: -s https://user:password@hostname:8080/path Additionally, the following new options are implemented: -C FILE Load CA certificates from FILE. If FILE is a directory, all PEM files will be loaded from it. -K FILE Load client certificate and key from FILE. During TLS handshake, send them to the peer for authentication. -k Insecure mode: disable peer verification. -S NAME Take settings for server NAME from the poundctl configuration file (see below). ** .poundctl The file ".poundctl" in user home directory provides configuration settings for the poundctl command. Syntactically, it is similar to pound.cfg. Upon startup, poundctl first checks if "~/.poundctl" exists and reads it if so. If the program cannot determine the URL of the control socket from it (possibly using the argument to the -S option, if given), it scans the pound configuration file (if it exists), looking for Control statement. Finally, if neither method determines the URL, poundctl requires the user to supply the -s option. The default name and location of the poundctl configuration file can be changed using the environment variable POUNDCTL_CONF. Setting it to empty string disables the configuration mechanism altogether. * configure Removed historic "--with-owner" and "--with-group" options. Version 4.13, 2024-08-24 * Support for pcre and pcre2 rewritten The pcre2posix (or pcreposix) layer is no longer used. Instead, pound uses the native API of the corresponding library. This provides for additional speed-up and (in case of pcre2) avoids coredumps under high load. * Use of POSIX and Perl-compatible regular expressions In contrast to previous versions, both types of regular expressions can be used simultaneously in the configuration file. The flavour of the regex to use can be specified either individually with each request matching statement (such as URL, Header, etc.), or globally. To set it globally, use the RegexType statement. The type of regular expression set by it will be used in all matching statements that appear below that statement, unless they declare regex type explicitly. It remains in effect until next RegexType statement or end of file is encountered, whichever occurs first. For example, to use PCRE by default, add the following statement somewhere near the beginning of your pound.cfg file: RegexType pcre To change the default back to POSIX regexps, do RegexType posix Regular expression type can also be specified with each matching statement individually. For example, the -pcre option indicates that Perl-compatible regular expression is given as argument, e.g.: Host -pcre -icase "(? statement for the enclosing listener is consulted. If it is not present, the default error page is used. * New special backend: Metrics This backend type implements openmetrics telemetry endpoint. The minimal configuration is: Service URL "/metrics" Metrics End Enabling backend statistics (see below) is strongly suggested when using the Metrics backend. * Backend statistics Backend usage statistics is enabled by the BackendStats configuration directive: BackendStats true When enabled, the "stats" object will be added to the JSON output for each backend. This object holds the following fields: request_count Number of requests processed by this backend. request_time_avg Average request processing time. request_time_stddev Standard deviation of the above. The Metrics backend, if declared, will then include the following metric families in its output pound_backend_requests pound_backend_request_time_avg_nanoseconds pound_backend_request_stddev_nanoseconds These three families are labeled by the corresponding backend index, e.g. (output split in two lines for readability): pound_backend_request_time_avg_nanoseconds {listener="1",service="1",backend="1"} 17232220 * Core statistics The default output returned by pound control thread now includes additional core statistics: pound version, PID, worker subsystem configuration and state. The default poundctl template has been changed to reflect it. * New options: -F and -e The -F option forces the foreground mode: the program won't detach itself from the controlling terminal and will remain in foreground even if configuration settings require otherwise. The -e option directs error diagnostics to stderr (stdout for LOG_DEBUG and LOG_INFO facilities). It implies foreground mode. * Changes in verbose mode (-v) Error messages emitted to stderr (stdout) are duplicated in the syslog, if the configuration settings require so. * Arithmetic operations in poundctl templates The four new functions are provided to implement basic arithmetic operations in templates: add, sub, mul, and div. * Fixed the LogFacility configuration statement Version 4.4, 2023-01-19 * New directive: HeaderOption The HeaderOption directive controls what kind of "canned" headers pound adds to the HTTP request before passing it on to the backend. By default, it adds "forwarded" headers (X-Forwarded-For, X-Forwarded-Proto, and X-Forwarded-Port) and, if serving a HTTPS session, X-SSL-* headers. The arguments to the HeaderOption directive enable or disable these canned headers. The default corresponds to HeaderOption forwarded ssl To disable any kind of headers, precede its name with a "no-": HeaderOption no-forwarded The special keywords "none" and "all", can be used to disable or enable all canned headers. The HeaderOption directive can appear in the global scope or within a ListenerHTTP (or ListenerHTTPS) section. * Header modification and service matching Header modification directives are applied after service matching directives (such as Header or HeadRequire). This is a disruptive change: in previous pound version header removal was done prior to service selection. * Header modification order Header modification directives are applied in the following order: HeaderOptions, HeaderRemove, HeaderAdd. In other words, built-in headers are added first. Then, header removal directives are applied. Finally, headers requested by the user are added. Added headers overwrite headers with the same name that may already be present in the request. Thus, you can use HeaderRemove and HeaderAdd to trim down headers added by HeaderOptions. * Back-references in Redirect and ACME statements Arguments to Redirect and ACME statements can contain references to parenthesized subexpressions in the most recently matched URL, Header, or Host statements. Syntactically, $N refers to URL subexpression and %N refers to subexpression of Header (or Host). $0 and %0 are expanded to the entire URL or header (host). For example, to redirect all requests to https: Service Host -re ".+" URL ".*" Redirect "https://%0$0" End Version 4.3, 2023-01-13 * Template support in poundctl The output of poundctl is controlled by a template. Templates are read from a template file, which is looked up in template search path (normally ~/.poundctl.tmpl:/usr/share/pound/poundctl.tmpl). The poundctl.tmpl file shipped with the distribution defines templates for the traditional (plain-text) and XML output. The option "-t FILE" instructs poundctl to use FILE instead of the default template file. The option "-T NAME" supplies the name of the template to be used. * Fix parsing of Subject in X509 certificates Version 4.2, 2022-12-31 * Rewrite periodic tasks The timer thread is rewritten completely in order to do periodic operations (such as backend probing and session expiration) precisely when needed, instead of waking up in fixed intervals and checking what should be done. Among others, this helps reduce the CPU load. Whenever a backend is marked as dead, a periodic job is scheduled for "alive_to" seconds from the current time, which will probe the backend and either mark it as alive (if it responds) or reschedule itself for a later time (if it does not). Thus, no unnecessary iterations over listeners/servers/backends occur. Sessions are kept on per-service basis in a combined structure consisting of a hash table (to quickly look-up a session) and a doubly-linked list (to provide for session expiration). Sessions within the latter are sorted by their expiration time. A periodic job is scheduled to the expiration time of the first session in the list, i.e. the least recently used one. After removing the expired session, the job reschedules itself to the expiration time of the next session (which becomes first in the list), if any. * The "haport" feature has been removed. * Control interface rewritten The new control interface uses REST API. * Poundctl rewritten Version 4.1, 2022-12-10 * Worker Model Each incoming request is processed by a specific worker, i.e. a thread in the running program. The number of running workers is controlled by three configuration parameters. WorkerMinCount defines the minimum number of workers that should always be running (5, by default). Another parameter, WorkerMaxCount sets the upper limit on the number of running workers (defaults to 128). At each given moment, a worker can be in one of two states: idle or active (processing a request). If an incoming request arrives when all running workers are active, and total number of workers is less than maximum, a new thread is started and the new request is handed to it. If the number of active workers has already reached maximum, the new request is added to the request queue, where it will wait for a worker to become available to process it. The third parameter, WorkerIdleTimeout, specifies maximum time a thread is allowed to spend in the idle state. If a worker remains idle longer than that and total number of workers is greater than the allotted minimum, the idle worker is terminated. The default value for WorkerIdleTimeout is 30 seconds. * URL expansion in Redirect statement URL argument to the Redirect statement can contain references to parethesized subexpressions in the most recently matched URL statement of the enclosing Service. References are of the form $N, where N is the number of the parenthesized subgroup. To insert literal $ sign, use $$. * New statement: PIDFile Defines the name of the PID file. The -p command line option overrides this setting. * New statement: ACME The ACME statement creates a service specially crafted for answering ACME HTTP-01 challenge requests. It takes a single argument, specifying a directory where ACME challenges are stored. It is supposed that another program is started periodically, which checks for certificates approaching their expiration, issues renewal requests and stores the obtained ACME challenges in that directory. The statement can appear in ListenHTTP block. Example usage: ListenHTTP ACME "/var/www/acme" ... End * New statement: Host The "Host" statement is provided to facilitate handling of virtual services. The statement: Host "example.com" is equivalent to: HeadRequire "Host:[[:space:]]*example\\.com" * ACLs Access control lists (ACLs) allow you to make some services available for users coming from certain IP ranges. There are two kinds of ACLs: named and unnamed. Named ACLs are defined in the global scope, using the following syntax: ACL "name" "CIDR" ... End where ... denotes more CIDR lines. A CIDR is an IPv4 or IPv6 address, optionally followed by a slash and network mask length. Named ACLs can be referred to in Service sections using the following syntax: Service ACL "name" ... End This service will be used only if the request comes from IP address that matches the given ACL. Unnamed ACLs are defined within the service itself, as shown in the following example Service ACL "127.0.0.1" "192.0.2.0/26" "203.0.113.0/24" End ... End Semantically they are entirely equivalent to named ACLs. * Boolean operations over request matching directives By default, request matching directives are joined with an implicit boolean "AND". This can be changed using the new "Match" directive, e.g.: Match OR HeadRequire "Host:[[:space:]]*example\\.org" HeadRequire "Host:[[:space:]]*example\\.net" End Match directives can be nested to any depth. Any request matching directive (including "Match") can be prefixed with "not", to invert its result (boolean negation). * Alternative spelling for header matching/manipulation directives For consistency, the following configuration directives have been provided as alternatives for existing header manipulation directives: Old name New name Comment -------- -------- ------- HeadRequire Header Service section HeadDeny Not Header Service section. See "Boolean operations". HeadRemove HeaderRemove ListenHTTP and ListenHTTPS sections AddHeader HeaderAdd ListenHTTP and ListenHTTPS sections The use of new names is preferred. Version 4.0, 2022-12-02 * Support for OpenSSL 3.0 * Added testsuite. * Fixes in configuration parsing. ========================================================================= Copyright information: Copyright (C) 2018-2026 Sergey Poznyakoff Permission is granted to anyone to make or distribute verbatim copies of this document as received, in any medium, provided that the copyright notice and this permission notice are preserved, thus giving the recipient permission to redistribute in turn. Permission is granted to distribute modified versions of this document, or of portions of it, under the above conditions, provided also that they carry prominent notices stating who last changed them. Local variables: mode: outline paragraph-separate: "[ ]*$" eval: (add-hook 'write-file-functions 'time-stamp) time-stamp-start: "changes. " time-stamp-format: "%:y-%02m-%02d" time-stamp-end: "\n" end: