From 3f3d8d9974c24a633361626d8e24170c19dbdb85 Mon Sep 17 00:00:00 2001 From: Doug Koerich Date: Mon, 3 Aug 2026 12:22:45 -0300 Subject: [PATCH 1/2] Momentum#1466 document Proxy_Protocol and PROXY protocol v2 support Proxy_Protocol and Proxy_Protocol_Timeout had never been documented, though the option has existed since 4.2.11. Add reference pages for both, covering what the option does, that the header is mandatory once enabled, that version 1 and version 2 headers are both accepted and detected automatically, how LOCAL and unknown-family headers fall back to the real peer address, and the trust model: there is no source allowlist, so any client that can reach the endpoint can assert any client address. Link the pages from the ESMTP listener and Listeners pages, and add both options to the configuration options summary. --- content/momentum/4/config-options-summary.md | 2 + .../4/config/ref-proxy-protocol-timeout.md | 44 +++++++++++ .../momentum/4/config/ref-proxy-protocol.md | 76 +++++++++++++++++++ content/momentum/4/esmtp-listener.md | 18 ++++- content/momentum/4/listeners.md | 8 +- 5 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 content/momentum/4/config/ref-proxy-protocol-timeout.md create mode 100644 content/momentum/4/config/ref-proxy-protocol.md diff --git a/content/momentum/4/config-options-summary.md b/content/momentum/4/config-options-summary.md index aae3bcfde..6f3b2d541 100644 --- a/content/momentum/4/config-options-summary.md +++ b/content/momentum/4/config-options-summary.md @@ -288,6 +288,8 @@ The `Version` column indicated the version(s) of Momentum that support the optio | [pool_name](/momentum/4/esmtp-listener#esmtp_listener.config) – Associate a threadpool with a listener | receiving |   | 4.0 and later | control_listener, eccluster_listener, ecstream_listener, esmtp_listener, http_listener, listen, xmpp_listener | | [prefer_ipv6_mxs](/momentum/4/config/ref-prefer_ipv6_mxs) - Prefer IPv6 addresses over IPv4 addresses at a given MX priority level | sending | false | 4.0 and later | global | | [prohibited_hosts](/momentum/4/config/ref-prohibited-hosts) – Prevent mail from being delivered to invalid destinations | sending |   | 4.0 and later | global | +| [proxy_protocol](/momentum/4/config/ref-proxy-protocol) – Read the originating client address from a PROXY protocol header | receiving | false | 4.2.11 and later | control_listener, ecstream_listener, esmtp_listener, http_listener, listen, peer, xmpp_listener | +| [proxy_protocol_timeout](/momentum/4/config/ref-proxy-protocol-timeout) – How long to wait for a complete PROXY protocol header | receiving | 60 | 4.2.11 and later | control_listener, ecstream_listener, esmtp_listener, http_listener, listen, peer, xmpp_listener | | [rcptto_timeout](/momentum/4/config/ref-rcptto-timeout) – Timeout after RCPT TO | sending | 300 | 4.0 and later | binding, binding_group, domain, global | | **received_hostname** – Hostname that is placed in the received headers; these are added to the messages as it transits Momentum | receiving |   | 4.0 and later | esmtp_listener, listen, pathway, pathway_group, peer | | [reconfig_message](/momentum/4/esmtp-listener-reconfig-message) – Message if the configuration has changed | receiving | 4.3.2 Reconfiguration in progress | 4.0 and later | esmtp_listener | diff --git a/content/momentum/4/config/ref-proxy-protocol-timeout.md b/content/momentum/4/config/ref-proxy-protocol-timeout.md new file mode 100644 index 000000000..49a882e13 --- /dev/null +++ b/content/momentum/4/config/ref-proxy-protocol-timeout.md @@ -0,0 +1,44 @@ +--- +lastUpdated: "08/03/2026" +title: "Proxy_Protocol_Timeout" +description: "proxy protocol timeout sets how long a listener with proxy protocol enabled waits for a complete PROXY protocol header before closing the connection." +--- + + +## Name + +Proxy_Protocol_Timeout — how long to wait for a complete PROXY protocol header. + +## Synopsis + +`Proxy_Protocol_Timeout = 60` + + +## Description + +On a listener with [Proxy_Protocol](/momentum/4/config/ref-proxy-protocol) enabled, this is the number of seconds the listener waits for a complete header before closing the connection. + +The timeout covers the header only. Once the header has been read, the connection continues under the listener's normal timeouts, such as [Idle_Time](/momentum/4/config/ref-idle-time). + +The default value is `60`. A value of `0` disables the timeout, which is not recommended: a client that opens a connection and sends a partial header would then occupy a session slot indefinitely. + +A header is a few dozen bytes sent immediately on connection, so it should arrive within one round trip. The generous default exists to tolerate unusual networks; lowering it to a few seconds reclaims slots faster from clients that connect and then stall. Because a held slot counts against [Listener_Sessions](/momentum/4/config/ref-listener-sessions) and [Service_Sessions](/momentum/4/config/ref-service-sessions), a long timeout combined with a low session cap lets stalled connections crowd out real mail. + +## Example + +``` +ESMTP_Listener { + Listen "10.0.0.5:25" { + Proxy_Protocol = true + Proxy_Protocol_Timeout = 10 + } +} +``` + +## Scope + +Set on any listener with `Proxy_Protocol` enabled, or on an individual `Listen` endpoint. It has no effect where `Proxy_Protocol` is not enabled. + +## See Also + +[Proxy_Protocol](/momentum/4/config/ref-proxy-protocol), [Idle_Time](/momentum/4/config/ref-idle-time), [Listener_Sessions](/momentum/4/config/ref-listener-sessions) diff --git a/content/momentum/4/config/ref-proxy-protocol.md b/content/momentum/4/config/ref-proxy-protocol.md new file mode 100644 index 000000000..8cb6d1362 --- /dev/null +++ b/content/momentum/4/config/ref-proxy-protocol.md @@ -0,0 +1,76 @@ +--- +lastUpdated: "08/03/2026" +title: "Proxy_Protocol" +description: "proxy protocol makes a listener read a PROXY protocol header from each incoming connection and use the client address it reports instead of the address of the proxy or load balancer that connected. Both the version 1 text format and the version 2 binary format are accepted and detected automatically." +--- + + +## Name + +Proxy_Protocol — read the originating client address from a PROXY protocol header. + +## Synopsis + +`Proxy_Protocol = false` + + +## Description + +When a listener sits behind a proxy or load balancer, every connection appears to come from the proxy. `Proxy_Protocol` makes the listener read a [PROXY protocol](http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt) header at the start of each connection and adopt the client address it reports. + +That address is then the one Momentum uses everywhere it refers to the connecting client, including: + +* policy decisions such as `Relay_Hosts` and `Peer` scope matching, +* SPF evaluation, +* the reception entry in the mainlog and the address reported to policy scripts, +* inbound concurrency accounting. + +The default value is `false`. + +### Versions and automatic detection + +Both header formats are accepted, and the listener tells them apart from the first byte of the connection. Nothing needs to be configured to select one: + +* **Version 1** is a line of text, as sent by older load balancers and by AWS Classic Load Balancers. +* **Version 2** is a binary header, and is what current HAProxy (`send-proxy-v2`), AWS Network Load Balancers and Envoy send. + +Version 2 headers may carry extra type-length-value fields after the addresses — for example the AWS VPC endpoint identifier. These are read and discarded; their contents are not available to policy. + +### The header is required + +Once `Proxy_Protocol` is enabled on a listener, every connection to it **must** begin with a valid header. A client that sends none, or sends a malformed one, is disconnected without a banner. Reserve the listener for traffic that arrives through the proxy, and give direct clients a separate `Listen` endpoint. + +Some headers deliberately carry no client address, and are accepted with the real connecting address left in place: + +* the version 2 `LOCAL` command, which proxies use for their own health checks, +* a version 1 `PROXY UNKNOWN` line, +* an address family the listener does not use for policy, such as UNIX sockets. + +### Trust + +There is no source-address allowlist. Any client that can reach a listener with `Proxy_Protocol` enabled can assert whatever client address it likes, which means it can present itself as a relay-permitted host or defeat an IP-based block. + +Trust is therefore scoped entirely by *which* endpoint has the option enabled. Only enable it on endpoints reachable from the proxy — bind them to an internal address, or restrict them with a firewall or security group. + +## Example + +``` +ESMTP_Listener { + # behind the load balancer: adopt the client address it reports + Listen "10.0.0.5:25" { + Proxy_Protocol = true + Proxy_Protocol_Timeout = 30 + } + + # direct submission, no header expected + Listen "127.0.0.1:587" {} +} +``` + +## Scope + +`Proxy_Protocol` is available on any listener, not only the `ESMTP_Listener`, and may be set on the listener itself or on an individual `Listen` endpoint. Setting it per `Listen` endpoint is usually what you want, so that proxied and direct traffic can be served side by side. + +## See Also + +[Proxy_Protocol_Timeout](/momentum/4/config/ref-proxy-protocol-timeout), [Configuring Inbound Mail Service Using SMTP](/momentum/4/esmtp-listener), [ha_proxy_client](/momentum/4/modules/ha-proxy-client) for sending a PROXY protocol header on outbound connections. diff --git a/content/momentum/4/esmtp-listener.md b/content/momentum/4/esmtp-listener.md index 0cec1e6c4..ff5ed157d 100644 --- a/content/momentum/4/esmtp-listener.md +++ b/content/momentum/4/esmtp-listener.md @@ -1,5 +1,5 @@ --- -lastUpdated: "03/26/2020" +lastUpdated: "08/03/2026" title: "Configuring Inbound Mail Service Using SMTP" description: "The ESMTP Listener is the listener that enables you to inject message using SMTP Momentum can listen on any number of Unix domain sockets and or IP port addresses for TCP IP service The ESMTP Listener supports all of the extended properties and extensions described below The ESMTP Listener is..." --- @@ -49,6 +49,22 @@ The `Pool_Name` option associates the `accept-pool` ThreadPool with the listener When using threaded accepts for listeners, you must provision the thread pool you intend to use via the ThreadPool directive. If the thread pool you name is not found or is unspecified, the IO pool will be used and a critical message will appear in your log. +### Accepting Connections Through a Proxy or Load Balancer + +If the listener is fronted by a proxy or load balancer, set [Proxy_Protocol](/momentum/4/config/ref-proxy-protocol) on that endpoint so the originating client address is taken from the PROXY protocol header instead of showing the proxy for every connection. Version 1 (text) and version 2 (binary) headers are both accepted, detected automatically, so no additional option selects between them. + +Once enabled the header is required on every connection to that endpoint, so serve direct clients from a separate `Listen` stanza. [Proxy_Protocol_Timeout](/momentum/4/config/ref-proxy-protocol-timeout) bounds how long an incomplete header is waited for. + +``` +ESMTP_Listener { + Listen "10.0.0.5:25" { + Proxy_Protocol = true + Proxy_Protocol_Timeout = 10 + } + Listen "127.0.0.1:587" {} +} +``` + ### Limiting Inbound Concurrency You can cap the number of concurrent inbound sessions with two options: diff --git a/content/momentum/4/listeners.md b/content/momentum/4/listeners.md index 112a461f6..072bbe46d 100644 --- a/content/momentum/4/listeners.md +++ b/content/momentum/4/listeners.md @@ -1,5 +1,5 @@ --- -lastUpdated: "03/26/2020" +lastUpdated: "08/03/2026" title: "Listeners" description: "Momentum is built around a powerful event based scheduling engine A key part of that engine is responding to events that occur on inbound sockets known as listeners These listeners are configured in Momentum's configuration files The following is an example of a basic listener syntax In this example the..." --- @@ -127,6 +127,12 @@ Listens on port 25 of the IPv6 address. For a detailed discussion of IPv6 syntax see [“Listeners and IPv6 Addresses”](/momentum/4/listeners#listeners.ipv6). +### Listeners Behind a Proxy or Load Balancer + +When a listener sits behind a proxy or load balancer, every connection appears to come from the proxy rather than from the originating client. Enable [Proxy_Protocol](/momentum/4/config/ref-proxy-protocol) on that endpoint to read the client address from the PROXY protocol header the proxy prepends, so that policy, SPF and logging all see the real client. Both the version 1 text format and the version 2 binary format are accepted and detected automatically. + +The header is mandatory once the option is enabled, so keep proxied and direct traffic on separate `Listen` endpoints, and see [Proxy_Protocol_Timeout](/momentum/4/config/ref-proxy-protocol-timeout) for how long an incomplete header is tolerated. + ### Unix Domain Listener Address Syntax The following is an example of a Unix listen address configuration: From cb7dce07b51dc93dc2eb80c3872b053ad959d038 Mon Sep 17 00:00:00 2001 From: Doug Koerich Date: Mon, 3 Aug 2026 12:38:08 -0300 Subject: [PATCH 2/2] Momentum#1466 distinguish PROXY protocol v1 and v2 availability The pages read as though both header formats had always been accepted, and the options summary gave a single "4.2.11 and later" for the option. The option does date from 4.2.11, but only for the version 1 text header; version 2 arrives in 5.4, the next on-prem release, and is rejected before it. State both facts wherever the formats are mentioned, and name the symptom on earlier releases (connection closed without a banner) so it is searchable. --- content/momentum/4/config-options-summary.md | 2 +- content/momentum/4/config/ref-proxy-protocol.md | 12 ++++++++---- content/momentum/4/esmtp-listener.md | 4 +++- content/momentum/4/listeners.md | 4 +++- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/content/momentum/4/config-options-summary.md b/content/momentum/4/config-options-summary.md index 6f3b2d541..ca5be6e2c 100644 --- a/content/momentum/4/config-options-summary.md +++ b/content/momentum/4/config-options-summary.md @@ -288,7 +288,7 @@ The `Version` column indicated the version(s) of Momentum that support the optio | [pool_name](/momentum/4/esmtp-listener#esmtp_listener.config) – Associate a threadpool with a listener | receiving |   | 4.0 and later | control_listener, eccluster_listener, ecstream_listener, esmtp_listener, http_listener, listen, xmpp_listener | | [prefer_ipv6_mxs](/momentum/4/config/ref-prefer_ipv6_mxs) - Prefer IPv6 addresses over IPv4 addresses at a given MX priority level | sending | false | 4.0 and later | global | | [prohibited_hosts](/momentum/4/config/ref-prohibited-hosts) – Prevent mail from being delivered to invalid destinations | sending |   | 4.0 and later | global | -| [proxy_protocol](/momentum/4/config/ref-proxy-protocol) – Read the originating client address from a PROXY protocol header | receiving | false | 4.2.11 and later | control_listener, ecstream_listener, esmtp_listener, http_listener, listen, peer, xmpp_listener | +| [proxy_protocol](/momentum/4/config/ref-proxy-protocol) – Read the originating client address from a PROXY protocol header (version 1; version 2 headers since 5.4) | receiving | false | 4.2.11 and later | control_listener, ecstream_listener, esmtp_listener, http_listener, listen, peer, xmpp_listener | | [proxy_protocol_timeout](/momentum/4/config/ref-proxy-protocol-timeout) – How long to wait for a complete PROXY protocol header | receiving | 60 | 4.2.11 and later | control_listener, ecstream_listener, esmtp_listener, http_listener, listen, peer, xmpp_listener | | [rcptto_timeout](/momentum/4/config/ref-rcptto-timeout) – Timeout after RCPT TO | sending | 300 | 4.0 and later | binding, binding_group, domain, global | | **received_hostname** – Hostname that is placed in the received headers; these are added to the messages as it transits Momentum | receiving |   | 4.0 and later | esmtp_listener, listen, pathway, pathway_group, peer | diff --git a/content/momentum/4/config/ref-proxy-protocol.md b/content/momentum/4/config/ref-proxy-protocol.md index 8cb6d1362..91b1cf90d 100644 --- a/content/momentum/4/config/ref-proxy-protocol.md +++ b/content/momentum/4/config/ref-proxy-protocol.md @@ -1,7 +1,7 @@ --- lastUpdated: "08/03/2026" title: "Proxy_Protocol" -description: "proxy protocol makes a listener read a PROXY protocol header from each incoming connection and use the client address it reports instead of the address of the proxy or load balancer that connected. Both the version 1 text format and the version 2 binary format are accepted and detected automatically." +description: "proxy protocol makes a listener read a PROXY protocol header from each incoming connection and use the client address it reports instead of the address of the proxy or load balancer that connected. The version 1 text format has been accepted since 4.2.11; the version 2 binary format is accepted since Momentum 5.4." --- @@ -16,6 +16,8 @@ Proxy_Protocol — read the originating client address from a PROXY protocol hea ## Description +> **NOTE: version 2 headers require Momentum 5.4.** The option itself dates from Momentum 4.2.11, but until 5.4 it accepted only the version 1 text header. Momentum 5.4 is the next on-prem release; on 5.3 and earlier, a version 2 header is rejected and the connection is closed. See “Versions and automatic detection” below. + When a listener sits behind a proxy or load balancer, every connection appears to come from the proxy. `Proxy_Protocol` makes the listener read a [PROXY protocol](http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt) header at the start of each connection and adopt the client address it reports. That address is then the one Momentum uses everywhere it refers to the connecting client, including: @@ -29,10 +31,12 @@ The default value is `false`. ### Versions and automatic detection -Both header formats are accepted, and the listener tells them apart from the first byte of the connection. Nothing needs to be configured to select one: +The protocol has two header formats, and support for them arrived at different times: + +* **Version 1** is a line of text, as sent by older load balancers and by AWS Classic Load Balancers. It has been accepted since the option was introduced in Momentum 4.2.11. +* **Version 2** is a binary header, and is what current HAProxy (`send-proxy-v2`), AWS Network Load Balancers and Envoy send. It is accepted **since Momentum 5.4**. On earlier releases a version 2 header is not recognised, and such a connection is closed without a banner — the symptom of pointing a version 2 sender at a listener running 5.3 or earlier. -* **Version 1** is a line of text, as sent by older load balancers and by AWS Classic Load Balancers. -* **Version 2** is a binary header, and is what current HAProxy (`send-proxy-v2`), AWS Network Load Balancers and Envoy send. +From 5.4 on, both formats are accepted on the same endpoint and the listener tells them apart from the first byte of the connection. Nothing needs to be configured to select one, and no configuration change is needed when an upstream proxy is switched from version 1 to version 2. Version 2 headers may carry extra type-length-value fields after the addresses — for example the AWS VPC endpoint identifier. These are read and discarded; their contents are not available to policy. diff --git a/content/momentum/4/esmtp-listener.md b/content/momentum/4/esmtp-listener.md index ff5ed157d..8fdf12bbc 100644 --- a/content/momentum/4/esmtp-listener.md +++ b/content/momentum/4/esmtp-listener.md @@ -51,7 +51,9 @@ When using threaded accepts for listeners, you must provision the thread pool yo ### Accepting Connections Through a Proxy or Load Balancer -If the listener is fronted by a proxy or load balancer, set [Proxy_Protocol](/momentum/4/config/ref-proxy-protocol) on that endpoint so the originating client address is taken from the PROXY protocol header instead of showing the proxy for every connection. Version 1 (text) and version 2 (binary) headers are both accepted, detected automatically, so no additional option selects between them. +If the listener is fronted by a proxy or load balancer, set [Proxy_Protocol](/momentum/4/config/ref-proxy-protocol) on that endpoint so the originating client address is taken from the PROXY protocol header instead of showing the proxy for every connection. + +The version 1 (text) header has been accepted since Momentum 4.2.11. The version 2 (binary) header, which current HAProxy, AWS Network Load Balancers and Envoy send, is accepted **since Momentum 5.4**; on earlier releases such a connection is closed without a banner. From 5.4 on both formats are detected automatically, so no additional option selects between them. Once enabled the header is required on every connection to that endpoint, so serve direct clients from a separate `Listen` stanza. [Proxy_Protocol_Timeout](/momentum/4/config/ref-proxy-protocol-timeout) bounds how long an incomplete header is waited for. diff --git a/content/momentum/4/listeners.md b/content/momentum/4/listeners.md index 072bbe46d..e997377e2 100644 --- a/content/momentum/4/listeners.md +++ b/content/momentum/4/listeners.md @@ -129,7 +129,9 @@ For a detailed discussion of IPv6 syntax see [“Listeners and IPv6 Addresses” ### Listeners Behind a Proxy or Load Balancer -When a listener sits behind a proxy or load balancer, every connection appears to come from the proxy rather than from the originating client. Enable [Proxy_Protocol](/momentum/4/config/ref-proxy-protocol) on that endpoint to read the client address from the PROXY protocol header the proxy prepends, so that policy, SPF and logging all see the real client. Both the version 1 text format and the version 2 binary format are accepted and detected automatically. +When a listener sits behind a proxy or load balancer, every connection appears to come from the proxy rather than from the originating client. Enable [Proxy_Protocol](/momentum/4/config/ref-proxy-protocol) on that endpoint to read the client address from the PROXY protocol header the proxy prepends, so that policy, SPF and logging all see the real client. + +The version 1 text header has been accepted since Momentum 4.2.11; the version 2 binary header is accepted **since Momentum 5.4** and is rejected on earlier releases. The header is mandatory once the option is enabled, so keep proxied and direct traffic on separate `Listen` endpoints, and see [Proxy_Protocol_Timeout](/momentum/4/config/ref-proxy-protocol-timeout) for how long an incomplete header is tolerated.