Hi Olivier.

On 2025-07-09 (Mi.) 12:44, Olivier D wrote:
Hello everyone,

I'm currently troubleshooting intermittent 520 errors returned by Cloudflare in front of an HAProxy-based load balancing infrastructure.

These errors are rare—affecting about 0.001% of requests—which makes them especially tricky to diagnose. According to Cloudflare, a 520 indicates the origin server (HAProxy, in this case) unexpectedly closed the connection or returned an empty response.

Key Observations
- it happens on several frontends and on different haproxy instances.
- The issue only occurs when the client request protocol is HTTP/2 (http/3 is disabled on our side at the moment).
- Disabling Cloudflare's "HTTP/2 to origin" option completely eliminates the 
issue.
This strongly suggests the problem lies in the interaction between Cloudflare's HTTP/2 implementation and HAProxy's HTTP/2 support.

Cloudflare Logs for 520 Events
"OriginSSLProtocol": "unknown",
"OriginTCPHandshakeDurationMs": 11,
"OriginTLSHandshakeDurationMs": 12,
"OriginRequestHeaderSendDurationMs": 0,
"OriginResponseDurationMs": 0,
"ClientSSLCipher": "AEAD-AES128-GCM-SHA256",
"ClientSSLProtocol": "TLSv1.3"

To me, this implies:
- Cloudflare successfully opens a TCP connection to HAProxy (OriginTCPHandshakeDurationMs is non-zero), - But fails during the TLS handshake, as evidenced by "OriginSSLProtocol": "unknown".

HAProxy version 2.8.15 (issue also present on 2.8.11)

Relevant global settings:
    ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256     ssl-default-bind-client-sigalgs rsa_pkcs1_sha256:rsa_pkcs1_sha384:rsa_pkcs1_sha512:ecdsa_secp256r1_sha256:ecdsa_secp384r1_sha384:ecdsa_secp521r1_sha512:rsa_pss_rsae_sha256:rsa_pss_rsae_sha384:rsa_pss_rsae_sha512:ed25519:ed448:rsa_pss_pss_sha256:rsa_pss_pss_sha384:rsa_pss_pss_sha512
     option tcp-smart-accept
     option tcp-smart-connect

Frontend configuration (abridged):
     mode http
    bind xxxxx:443 ssl crt-list /folder/redacted.txt ssl-min-ver TLSv1.2 tls- ticket-keys /var/run/tls_ticket_keys


I've tried enabling debug-style logging using:
     option log-separate-errors
     option logasap
    error-log-format '%ci:%cp -> %fi:%fp %b/%s | Tq=%Tq Tw=%Tw Tc=%Tc Tr=%Tr Ta=%Ta Tt=%Tt TR=%TR HTTP=%ST (%hrl) B=%B | TLS=%sslv/%sslc SNI=%[ssl_fc_sni] %HM %HP'

Unfortunately, these logs don't show any detail about the failed TLS handshakes.

Questions
- have anyone experienced this issue ? If you have a small amount of 520 it may not been printed on the interface, but it is there. Just go the following URL : https://dash.cloudflare.com/[accountID]/mydomain.com/analytics/traffic?status- code=520 <https://dash.cloudflare.com/[accountID]/mydomain.com/analytics/ traffic?status-code=520>
- Are there any known issues with HAProxy and HTTP/2 in TLS termination 
scenarios ?
- Is there any way to increase logging detail specifically for failed TLS handshakes? tcpdump is a no go in this case due to the heavy trafic and the minimal occurrence of the issue.

Because the issue is so rare (under 100 requests/day), every test takes time to yield results. Any insights or ideas would be greatly appreciated.

You can try to increase the `tune.maxrewrite` to `2048` and see if the issue is fixed.

Thanks in advance!
Olivier

Regards
Aleks


Reply via email to