<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Behind a gateway, load balancer or reverse proxy: relays, PROXY, XCLIENT and HTTPS]]></title><description><![CDATA[<p dir="auto"><em>Written for 6.3.4. hMailServer 6.3.7 (17 October 2026) adds the PROXY protocol to the IMAP and POP3 listeners: each takes the client's address from a PROXY header as the SMTP listener does, from the peers on a list of its own, and both are off by default; their switches and peer lists are on the IMAP and POP3 cards of the Control Panel's Protocols page. The SMTP listener's PROXY protocol and XCLIENT are a card on Incoming relays, not on Server limits &amp; expert settings, and Ctrl+K takes every old title to its page. A state-changing REST request that carries a credential is now refused when the browser reports it as cross-site (<code>Sec-Fetch-Site</code>, or an <code>Origin</code> that is not this server's); scripts, <code>hmctl</code> and the PowerShell module send no such header and are unaffected. The ACME HTTP-01 challenge responder, which served one connection at a time, serves up to 64 at once. See <a href="/topic/28277">the 6.3.7 announcement</a>. hMailServer 6.3.8 (2 November 2026) no longer charges a failed sign-in through a proxy to the proxy: at the web services listener one from loopback or an address in <code>WebServicesTrustedProxies</code>, and at the REST listener an account's from loopback, is counted against the name alone, never towards a ban of the address, where up to 6.3.7 a ban could be written that shut the proxy, or <code>127.0.0.1</code>, out of the SMTP, POP3, IMAP and ManageSieve listeners. The web services listener now also refuses, before the TLS handshake, an address whose IP range allows none of SMTP, POP3 and IMAP, an auto-ban's or one of your own, though never loopback or an address in <code>WebServicesTrustedProxies</code>: where mail reaches the server only through a relay or a VPN and the Internet range allows nothing, that range now closes ACME's http-01 validation when this listener answers it, MTA-STS, CalDAV, CardDAV, Autodiscover, autoconfiguration and the Web Key Directory to the addresses it holds, so check before upgrading that the certificate authority, the sending MTAs and these services' clients do not come from it. See <a href="/topic/28278">the 6.3.8 announcement</a>.</em></p>
<p dir="auto">This topic is for a server that does not face the internet alone: behind a hosted spam filter or a filtering appliance, behind a load balancer, or with a reverse proxy terminating HTTPS in front of the webmail, the Control Deck, CalDAV and CardDAV. <strong>The one thing to know first: hMailServer judges the address that connected to it, and behind a front end that address is the front end's until you tell the server otherwise.</strong> Auto-ban, the rate limits, the IP ranges and every spam test then reason about the wrong machine: SPF fails on every message, and a block list that lists your gateway blocks all your mail. Each kind of front end is handled in its own way, and behind an HTTP reverse proxy the address stays the proxy's.</p>
<h3><a class="anchor-offset" name="which-mechanism-fits-which-front-end"></a>Which mechanism fits which front end</h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Front end</th>
<th>What reaches hMailServer</th>
<th>What tells it the truth</th>
</tr>
</thead>
<tbody>
<tr>
<td>A filtering gateway, hosted or an appliance, that accepts the mail and sends it on</td>
<td>A new SMTP session from the gateway, the sender's address in its <code>Received</code> header</td>
<td><strong>Incoming relays</strong>, <code>XCLIENT</code> if the gateway can send it, and the <code>gateway</code> setting profile</td>
</tr>
<tr>
<td>A load balancer or TLS terminator in front of the SMTP listener</td>
<td>The client's session, from the balancer's address</td>
<td>HAProxy <code>PROXY</code> v1 or v2</td>
</tr>
<tr>
<td>A reverse proxy terminating HTTPS for <code>/portal</code>, <code>/</code> and <code>/api/v1</code></td>
<td>HTTP from the proxy</td>
<td><code>X-Forwarded-Proto: https</code> from the proxy on the same machine, for the cookies; the address stays the proxy's</td>
</tr>
<tr>
<td>A reverse proxy in front of CalDAV, CardDAV and the other web services</td>
<td>HTTP from the proxy</td>
<td><code>X-Forwarded-Proto: https</code>, believed from loopback and from <code>WebServicesTrustedProxies</code></td>
</tr>
</tbody>
</table>
<h3><a class="anchor-offset" name="incoming-relays-what-listing-one-changes"></a>Incoming relays: what listing one changes</h3>
<p dir="auto"><strong>Mail flow &amp; delivery → Incoming relays</strong> in the Control Panel (Windows) lists servers that legitimately forward mail to you, each a name and an IP range (a lower and an upper address); a save applies at once. The same list is in the Control Deck, at <code>/api/v1/incoming-relays</code> over REST since 6.3.3 (a key confined to named domains is refused), and in COM <code>Settings.IncomingRelays</code> on Windows, where since 6.3.4 a change takes effect only at <code>Save()</code>.</p>
<p dir="auto">Listing a relay changes two things:</p>
<ul>
<li><strong>When spam protection runs.</strong> A connection from a listed relay is switched from pre-transmission to post-transmission testing. DNSBL, PTR and HELO checks judge the connecting IP, so they wait until the body has arrived and the real origin can be read from it. Spam is then no longer refused before the body: with quarantine on, a message reaching the delete threshold is held for review; without it, it is refused with <code>554 5.7.1</code> after the body.</li>
<li><strong>Which IP counts as the origin.</strong> The <code>Received</code> chain is walked from the top, and the first address that is not a listed relay becomes the originating IP. SPF, DMARC and ARC are evaluated against it.</li>
</ul>
<pre><code class="language-text">Received: from gw2.example.net [198.51.100.8]       listed relay: keep walking
Received: from gw1.example.net [198.51.100.7]       listed relay: keep walking
Received: from mail.sender.example [203.0.113.44]   not listed: the originating IP
</code></pre>
<p dir="auto">Since 6.2.24 the address taken is the one the relay observed, not the client's own HELO literal; thresholds tuned before then need checking again.</p>
<p dir="auto"><strong>Since 6.3.4 a listed relay changes more:</strong></p>
<ul>
<li>A remote domain policy's inbound rule, <em>Require TLS on mail from this domain</em> (<code>530 5.7.0</code> at <code>MAIL FROM</code>), is not applied to it. The hop that rule is about happened before the gateway, so require TLS on the gateway. <a href="/topic/28257">Requiring TLS and remote domain policies</a> covers the policies.</li>
<li>Mail it hands over counts as coming from inside. One rule, <code>MessageOrigin::IsExternalSender</code>, decides that for the external-sender tag, the first-contact note and impersonation protection, so none of the three applies behind a listed gateway. <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/DomainTransforms.md" rel="nofollow ugc">DomainTransforms.md</a>: the choice is between the tag and the relay declaration, and there is no third answer today. <a href="/topic/28251">Mail flow rules and what a domain does to a message</a> covers the tag.</li>
<li>A spam trap never bans it; the sender is still judged.</li>
<li>The domain white and black list sees the relay's own HELO name, so key rows for mail behind a relay on the envelope domain.</li>
</ul>
<p dir="auto"><strong>Keep the range to the exact gateway addresses.</strong> An attacker inside a range listed too wide can insert a forged <code>Received</code> header and choose which IP you evaluate. <strong>And leave spam protection on for the IP range the gateway connects from</strong>: clearing <em>Enable anti-spam</em> on a range turns off every spam test, greylisting and the recipient tarpit for it, relay or not.</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Symptom</th>
<th>Cause</th>
</tr>
</thead>
<tbody>
<tr>
<td>Every message is scored as though it came from your own filter; SPF always fails</td>
<td>The front end is not listed as an incoming relay</td>
</tr>
<tr>
<td>A DNSBL hit on the gateway's address blocks all mail</td>
<td>The same</td>
</tr>
<tr>
<td>Adding a relay stopped spam being rejected before the body</td>
<td>Expected: testing moved to after the body. Quarantine and scoring still apply</td>
</tr>
</tbody>
</table>
<h3><a class="anchor-offset" name="proxy-protocol-and-xclient"></a>PROXY protocol and XCLIENT</h3>
<p dir="auto">If the front end can pass the real client address itself, that is better than reconstructing it from headers. Two mechanisms have been accepted since 6.2.23-alpha1, both off by default and both honoured only from the addresses you list:</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Setting</th>
<th>Default</th>
<th>What it does</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>SMTPProxyProtocolEnabled</code></td>
<td><code>0</code></td>
<td>HAProxy <code>PROXY</code> v1 and v2 on the SMTP listener, read before TLS and before the banner</td>
</tr>
<tr>
<td><code>SMTPProxyProtocolTrustedIPs</code></td>
<td>empty</td>
<td>The real TCP peers allowed to send a <code>PROXY</code> header, comma-separated addresses or CIDR ranges. Empty means nobody</td>
</tr>
<tr>
<td><code>SMTPXClientEnabled</code></td>
<td><code>0</code></td>
<td>The Postfix <code>XCLIENT</code> verb</td>
</tr>
<tr>
<td><code>SMTPXClientTrustedIPs</code></td>
<td>empty</td>
<td>The peers allowed to use it. Empty means nobody</td>
</tr>
</tbody>
</table>
<ul>
<li><strong>Trust is decided against the real TCP peer</strong>, never an address a header supplied, so chained proxies cannot bootstrap trust. An entry that does not parse matches nothing and is logged once per run (<code>HM6281</code>).</li>
<li><strong>Once an address is listed for PROXY, the header is required from it.</strong> Configure the proxy to send it (in HAProxy, <code>send-proxy</code> or <code>send-proxy-v2</code>) or its connections are dropped; and a <code>PROXY</code> line from a peer that is not listed closes the connection without a reply. Change the proxy and the settings together.</li>
<li><strong><code>XCLIENT</code> is advertised in <code>EHLO</code> only to a trusted peer</strong>, as <code>XCLIENT ADDR NAME PORT PROTO HELO LOGIN</code>; an untrusted peer never learns the verb exists and gets <code>550</code> if it tries. With <code>LOGIN</code> the upstream vouches for a signed-in account: <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/RoomsAndEquipment.md" rel="nofollow ugc">RoomsAndEquipment.md</a> counts such a submission as a signed-in session, like SMTP <code>AUTH</code>. Listing an address for <code>XCLIENT</code> trusts it with that too.</li>
</ul>
<p dir="auto"><strong>What then sees the real client:</strong> auto-ban, the rate limits, the IP ranges, the spam tests, and since 6.3.4 the compromised-account detection's address signal (which never scores behind a proxy that speaks neither) and, with PROXY, the live view of one connection. <strong>What does not: country blocking</strong> (since 6.3.4). It judges the address the TCP connection came from, the proxy, and exempts loopback and private ranges; put the geographic policy on the proxy. Since 6.3.7 the IMAP and POP3 listeners take the client's address from a PROXY protocol header too, each from the peers on a list of its own (<code>IMAPProxyProtocolEnabled</code> and <code>IMAPProxyProtocolTrustedIPs</code>, <code>POP3ProxyProtocolEnabled</code> and <code>POP3ProxyProtocolTrustedIPs</code>), both off by default, the header read before an IMAPS or POP3S port's TLS handshake and before the greeting. No document describes either mechanism for ManageSieve.</p>
<p dir="auto"><strong>Where they are set.</strong> On Windows, the Control Panel's <strong>Maintenance → Server limits &amp; expert settings</strong> (card <em>Front-end proxies (PROXY protocol and XCLIENT)</em>; in 6.3.7's Control Panel the PROXY protocol and XCLIENT are a card on <strong>Incoming relays</strong>) or COM <code>Settings.SetIniSetting</code>. On either system, <code>PUT /api/v1/settings/ini/{name}</code> (the administrator password only; an API key is refused) or <code>hmctl ini set &lt;name&gt; &lt;value&gt;</code>; on Linux also <code>hmailserver --set-setting</code>. The Control Deck has no editor for these keys. All four apply when saved. Since 6.3.4 the database holds them, so a line edited in <code>hMailServer.ini</code> changes nothing the server uses; the store, the file's copy and <code>HM5804</code> are in <a href="/topic/28222">Settings: what is not stock and when a save takes effect</a>.</p>
<pre><code class="language-sh"># Over REST with the administrator password (an API key is refused), from any machine that reaches the listener; applies when saved
hmctl ini set SMTPProxyProtocolTrustedIPs 10.0.0.5,10.0.0.6
hmctl ini set SMTPProxyProtocolEnabled 1

# On a Linux server; a running service takes it at its next save, reinitialise or restart
sudo hmailserver --set-setting SMTPProxyProtocolTrustedIPs=10.0.0.5,10.0.0.6
sudo hmailserver --set-setting SMTPProxyProtocolEnabled=1
</code></pre>
<h3><a class="anchor-offset" name="the-gateway-profile-since-6.3.4"></a>The gateway profile (since 6.3.4)</h3>
<p dir="auto">A setting profile is a named, reviewed set of settings, shown as a diff first. <code>gateway</code> is for a server whose inbound mail a filtering gateway has already judged. Its 17 entries include:</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Entry</th>
<th>Value</th>
<th>Why (<a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/Profiles.md" rel="nofollow ugc">Profiles.md</a>, shortened)</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>usegreylisting</code></td>
<td><code>0</code></td>
<td>It judges the connecting address, which is the gateway's even through Incoming relays</td>
</tr>
<tr>
<td><code>SMTPXClientEnabled</code></td>
<td><code>1</code></td>
<td>Honoured only from <code>SMTPXClientTrustedIPs</code>, and from nobody while that is empty</td>
</tr>
<tr>
<td><code>ASArcFilteringEnabled</code></td>
<td><code>1</code></td>
<td>With DMARC on, the DMARC penalty is offset when a sealer named in <code>arc_trusted_sealers</code> sealed a pass</td>
</tr>
<tr>
<td><code>MaxSubmissionsPerIPPerMinute</code>, <code>SmtpTarpitCount</code></td>
<td><code>0</code></td>
<td>All inbound mail comes from the gateway's few addresses</td>
</tr>
<tr>
<td><code>QuarantineEnabled</code>, <code>RejectFullMailboxAtRcpt</code></td>
<td><code>1</code></td>
<td>A message at the delete threshold is held, not refused back to the gateway; a full mailbox is refused at RCPT so the gateway returns the message</td>
</tr>
<tr>
<td><code>usespf</code>, <code>ascheckhostinhelo</code>, <code>ascheckptr</code>, <code>ASDMARCEnabled</code></td>
<td><code>1</code></td>
<td>Through Incoming relays they judge the real sender</td>
</tr>
<tr>
<td><code>AutoBanOnLogonFailureEnabled</code>, <code>SmtpAuthenticatedSenderCheck</code></td>
<td><code>1</code></td>
<td>For people who sign in here directly</td>
</tr>
</tbody>
</table>
<p dir="auto">The rest switch on DKIM verification, the MX check and attachment blocking, all three off as shipped, and keep the reason headers on. The first four rows turn a check off or trust an address range, so applying asks for an explicit confirmation wherever one of them would change something.</p>
<p dir="auto">A profile never writes an incoming relay, an IP range, a port's TLS or the ARC sealer. The steps are yours, in this order:</p>
<ol>
<li><strong>Add the gateway's addresses to Incoming relays before applying the profile</strong>, and leave spam protection on for their IP range. Until they are there, the tests judge the gateway's own address.</li>
<li><strong>If the gateway sends <code>XCLIENT</code></strong>, put its addresses in <code>SMTPXClientTrustedIPs</code>.</li>
<li><strong>Name the ARC sealer the gateway signs as</strong> in <code>arc_trusted_sealers</code> (<code>PUT /api/v1/settings/antispam</code>, or COM <code>AntiSpam.ArcTrustedSealers</code>). Until then no seal is trusted.</li>
<li><strong>Read the diff and apply it</strong>, on the Control Panel's <strong>Setting profiles</strong> page under Maintenance, in the Deck's checklist, over REST or with <code>hmctl</code>, confirming the entries that ask. The apply is all or nothing and saves the values it replaces first; while an earlier profile is neither reverted nor discarded, another apply is refused with 409. The routes, the diff's token, the way back and the command-line verbs are in <a href="/topic/28231">the profiles section of the unattended installs topic</a>.</li>
<li><strong>Check "Require SSL/TLS when authenticating" on the Internet IP range</strong>, or make the submission port STARTTLS-required, for people who sign in here directly. A new installation turns it on; an upgraded one keeps what it had.</li>
<li><strong>On the listener the gateway delivers to, leave TLS optional unless the gateway offers it</strong>: a port's security is the port's, not a setting.</li>
</ol>
<h3><a class="anchor-offset" name="a-filter-on-the-same-machine"></a>A filter on the same machine</h3>
<p dir="auto">Since 6.3.4 SPF is RFC 7208, and <code>127.0.0.0/8</code> and <code>::1</code> no longer pass unconditionally. A content filter that re-injects mail over loopback should authenticate, or connect from an IP range with anti-spam off.</p>
<h3><a class="anchor-offset" name="the-http-listeners-behind-a-tls-terminating-proxy"></a>The HTTP listeners behind a TLS-terminating proxy</h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th></th>
<th>REST listener</th>
<th>Web-services listener</th>
</tr>
</thead>
<tbody>
<tr>
<td>Serves</td>
<td>The webmail at <code>/portal</code>, the Control Deck at <code>/</code>, the API under <code>/api/v1</code></td>
<td>ACME challenges, MTA-STS, <code>security.txt</code>, autoconfiguration, CalDAV, CardDAV, the OpenPGP key directory</td>
</tr>
<tr>
<td>Plain HTTP behind the proxy</td>
<td>Only on loopback: TLS is required unless bound to 127.0.0.1, localhost or ::1</td>
<td><code>WebServicesHttpPort</code></td>
</tr>
<tr>
<td>Whose <code>X-Forwarded-Proto: https</code> counts</td>
<td>The proxy on this machine</td>
<td>Loopback, and <code>WebServicesTrustedProxies</code> (since 6.3.3)</td>
</tr>
<tr>
<td>What it decides</td>
<td><code>Secure</code> on the session and sign-in cookies</td>
<td>Whether CalDAV and CardDAV treat the request as HTTPS; the Apple <code>.mobileconfig</code> profile; the key directory</td>
</tr>
</tbody>
</table>
<p dir="auto">A changed port or bind address (<code>RestApiPort</code>, <code>RestApiBindAddress</code>, <code>WebServicesHttpPort</code>, <code>WebServicesHttpsPort</code>) waits for a reinitialise (<strong>Apply now</strong>). <code>WebServicesTrustedProxies</code> applies when saved, and no document names a Control Panel field for it: set it with <code>PUT /api/v1/settings/ini/{name}</code>, <code>hmctl ini set</code>, COM <code>Settings.SetIniSetting</code> on Windows or <code>hmailserver --set-setting</code> on Linux (which a running service takes at its next save, reinitialise or restart).</p>
<p dir="auto"><strong>The cookies, since 6.3.4.</strong> <code>hmailsession</code> and the sign-in cookies <code>hmoidc</code>, <code>hmsso</code> and <code>hmpasskey</code> are marked <code>Secure</code> over TLS, or when the proxy on this machine says <code>X-Forwarded-Proto: https</code>. Before 6.3.4 only a TLS listener counted, so behind the usual proxy a browser would also send the session cookie over plain HTTP. A proxy that does not set the header still leaves them without <code>Secure</code>; a proxy on another machine can only reach a REST listener that speaks TLS itself.</p>
<p dir="auto"><strong>CalDAV (since 6.3.4) and CardDAV</strong> take HTTP Basic over HTTPS only: over plain HTTP the answer is 403 with the reason, unless a trusted proxy says <code>X-Forwarded-Proto: https</code>. From any other peer the header is ignored; an entry that does not parse matches nothing (<code>HM6281</code>). The Apple profile honours the header on the same terms, and the OpenPGP key directory (since 6.3.4) answers a plain request with the same 404 as an unknown address; point <code>openpgpkey.&lt;domain&gt;</code> at the proxy and forward <code>/.well-known/openpgpkey/</code> with the header. <a href="/topic/28252">The CalDAV and CardDAV topic</a> covers the rest.</p>
<p dir="auto"><strong>The client address stays the proxy's.</strong> Nothing reads <code>X-Forwarded-For</code>, so:</p>
<ul>
<li>The auto-ban leaves <code>127.0.0.1</code> and <code>::1</code> alone, and behind a proxy on this machine every webmail and Deck request comes from there. What brakes guessing is the per-name lockout, when <code>AccountLockoutThreshold</code> is set, and since 6.3.4 each owner's second-factor budget: five wrong codes in fifteen minutes refuse that owner's codes for the next fifteen (429, <code>second_factor_locked</code>).</li>
<li>The forgotten-password route (since 6.3.4) holds loopback to thirty requests in any sixty seconds, all together. A proxy on another host shares one per-client bucket of twenty an hour. Neither has a setting: put the proxy on the mail server or accept the cap.</li>
<li>For CalDAV, CardDAV and Autodiscover, since 6.3.8 a failed sign-in from loopback or an address in <code>WebServicesTrustedProxies</code> is counted against the name alone, never towards a ban of the address, and the listener never refuses those addresses by an IP range, so only proxies belong in that list, and the per-name lockout (<code>AccountLockoutThreshold</code>, off by default) is the limit on the guesses through one. Up to 6.3.7 each such failure was charged to the proxy's address, and a ban written for it could shut the proxy, and every client behind it, out of the SMTP, POP3, IMAP and ManageSieve listeners (<a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.8/hmailserver/docs/AutoBan.md" rel="nofollow ugc">AutoBan.md</a>).</li>
</ul>
<p dir="auto"><strong>Passkeys (since 6.3.4).</strong> By default the relying party id is the <code>Host</code> header, which behind a TLS-terminating proxy is still what the browser sent, so the check holds. <code>X-Forwarded-Proto</code> is not consulted, which is why the origin check accepts <code>https</code> at the page's host and plain <code>http</code> only on a loopback name. A server reached at several names needs <code>passkey_relying_party</code> and <code>passkey_allowed_origins</code> together, the origins written as the browser writes them, port included; <a href="/topic/28253">the topic on signing in</a> has the rest.</p>
<p dir="auto"><strong>The address people use.</strong> The server cannot learn it from the proxy. The links in a message that expires, a password-protected message and a password reset use <code>confidential_base_url</code> (then <code>quarantine_digest_base_url</code>, then <code>import_oauth_redirect_base_url</code>); the quarantine digest's links use <code>quarantine_digest_base_url</code> alone, a mailing list's use <code>list_base_url</code>, and single sign-on (since 6.3.4) uses <code>oidc_redirect_base_url</code>. Which paths to publish is in <a href="/topic/28191">The webmail portal at /portal</a>.</p>
<h3><a class="anchor-offset" name="compression-let-one-side-do-it-since-6.3.4"></a>Compression: let one side do it (since 6.3.4)</h3>
<p dir="auto">Both listeners compress when the client asks, and there is no setting.</p>
<ul>
<li><strong>Negotiation.</strong> <code>Accept-Encoding</code> is the whole of it: <code>gzip</code> or <code>deflate</code>, <code>gzip</code> where both are acceptable, never <code>br</code>. <code>deflate</code> is the zlib format of RFC 1950, which a raw inflater fails on; ask for <code>gzip</code>.</li>
<li><strong>What.</strong> Text, JSON, XML, a manifest, <code>message/rfc822</code> and an icon, between 1,024 bytes and 4 MB. An image, a PDF or a zip goes as it is, and a download (<code>/api/v1/me/messages/{id}/attachments/{index}</code>, <code>/files/{token}</code>) is never compressed.</li>
<li><strong>Headers.</strong> <code>Content-Length</code> is the bytes sent; no chunked transfer encoding, no byte ranges. <code>Vary: Accept-Encoding</code> is on every answer of a type it would compress, which matters for the web-services listener, whose answers may be cached; the webmail and the API are <code>Cache-Control: no-store</code>.</li>
</ul>
<p dir="auto"><strong>Behind a reverse proxy</strong>, either leave <code>Accept-Encoding</code> alone and pass the answer through (the server will not encode twice, and the proxy must not either), or strip <code>Accept-Encoding</code> from the request and compress at the proxy. What does not is forwarding <code>Accept-Encoding: gzip</code>, receiving <code>Content-Encoding: gzip</code>, and handing the bytes to a client that did not ask.</p>
<h3><a class="anchor-offset" name="what-it-does-not-do"></a>What it does not do</h3>
<ul>
<li><strong>It reads no forwarded-for header.</strong> XCLIENT is an SMTP setting only; since 6.3.7 the PROXY protocol is taken on the IMAP and POP3 listeners too, each from its own list of peers.</li>
<li><strong>A listed gateway turns off the external-sender tag</strong>, the first-contact note and impersonation protection for what it hands over.</li>
<li><strong>Compression has no switch.</strong> A client that wants none sends no <code>Accept-Encoding</code>, or <code>Accept-Encoding: identity</code>.</li>
<li><strong>A second machine behind a balancer</strong> is <a href="/topic/28232">the warm standby and high availability topic</a>.</li>
</ul>
<h3><a class="anchor-offset" name="where-to-read-more"></a>Where to read more</h3>
<ul>
<li>Wiki: <a href="https://gitlab.com/hmailserver/hmailserver/-/wikis/Routes-and-Relays" rel="nofollow ugc">Routes and Relays</a> §14.3, <a href="https://gitlab.com/hmailserver/hmailserver/-/wikis/Security-Hardening" rel="nofollow ugc">Security Hardening</a> §17.8, <a href="https://gitlab.com/hmailserver/hmailserver/-/wikis/Stopping-Spam" rel="nofollow ugc">Stopping Spam</a> §10.1, <a href="https://gitlab.com/hmailserver/hmailserver/-/wikis/Settings-Overview" rel="nofollow ugc">Settings Overview</a>, and <a href="https://www.progressiverobot.com/hmailserver-documentation/#143-incoming-relays" rel="nofollow ugc">chapter 14.3</a> of the documentation page.</li>
<li>Documents at the 6.3.4 tag: <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/Profiles.md" rel="nofollow ugc">Profiles.md</a>, <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/ResponseCompression.md" rel="nofollow ugc">ResponseCompression.md</a>, <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/DomainTransforms.md" rel="nofollow ugc">DomainTransforms.md</a>, <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/PasskeysAndSingleSignOn.md" rel="nofollow ugc">PasskeysAndSingleSignOn.md</a>, <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/DevicesAndSessions.md" rel="nofollow ugc">DevicesAndSessions.md</a>, <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/AccountRecovery.md" rel="nofollow ugc">AccountRecovery.md</a>, <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/CountryBlocking.md" rel="nofollow ugc">CountryBlocking.md</a>, <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/SettingsApply.md" rel="nofollow ugc">SettingsApply.md</a>, <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/RoomsAndEquipment.md" rel="nofollow ugc">RoomsAndEquipment.md</a>, and <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/README.md" rel="nofollow ugc">README.md</a> for the <code>[Settings]</code> notes on PROXY, XCLIENT and the web services.</li>
<li>On this forum: <a href="/topic/28191">The webmail portal at /portal</a>, <a href="/topic/28192">The Control Deck</a>, <a href="/topic/28248">the anti-spam stack end to end</a>, <a href="/topic/28239">IP ranges, auto-ban, lockout and tarpits</a> and <a href="/topic/28256">TLS on the listeners</a>.</li>
</ul>
<p dir="auto">A way past one of these trust lists is a vulnerability: report it by a <a href="https://gitlab.com/hmailserver/hmailserver/-/issues/new?issue%5Bconfidential%5D=true" rel="nofollow ugc">confidential GitLab issue</a> or by email to the project's Service Desk address, <a href="mailto:contact-project+hmailserver-hmailserver-86730559-issue-@incoming.gitlab.com" rel="nofollow ugc">contact-project+hmailserver-hmailserver-86730559-issue-@incoming.gitlab.com</a>, which GitLab files as a confidential issue, and not in a forum post.</p>
]]></description><link>https://www.hmailserver.co.uk/topic/28240/behind-a-gateway-load-balancer-or-reverse-proxy-relays-proxy-xclient-and-https</link><generator>RSS for Node</generator><lastBuildDate>Fri, 06 Nov 2026 09:05:51 GMT</lastBuildDate><atom:link href="https://www.hmailserver.co.uk/topic/28240.rss" rel="self" type="application/rss+xml"/><pubDate>Sun, 27 Sep 2026 19:22:13 GMT</pubDate><ttl>60</ttl></channel></rss>