SSL Termination Error on HAProxy: Fix for Backend Failures
This error pops up when HAProxy can't verify the backend server's SSL cert. Usually happens after a cert renewal or config change. The fix is straightforward.
When This Error Hits
You're running HAProxy 2.4 or later on RHEL 8 or Ubuntu 20.04. Your frontend terminates SSL fine. But the backend servers — Apache or Nginx — start returning 503 errors. The HAProxy logs show SSL handshake failure. This usually happens right after you renew the SSL cert on the backend server, or change the CA bundle. Maybe you pushed a new cert via Ansible and forgot to update the chain. The load balancer suddenly can't trust the backend.
Why It Breaks
The culprit here is almost always a mismatch between the backend's SSL certificate and what HAProxy expects. HAProxy by default validates the backend server's certificate when you set ssl verify required. If the cert's issuer isn't in the CA file HAProxy uses, or the chain is incomplete, the handshake dies. Another common cause: the backend server's IP changed but the cert doesn't match the new IP or hostname. I've seen this a dozen times after someone forgot to update server-template configs.
Don't bother checking the frontend SSL settings first. That's not the problem. The error is at the backend layer. Start with the backend server's cert.
The Fix: 4 Steps
- Check the backend server's cert chain
Run this on the backend server to see if the cert chain is complete:
Look for a full chain from server cert to root CA. If you see just one cert, the chain is broken. You need to concatenate the server cert, intermediate certs, and root CA into one PEM file.openssl s_client -connect backend-server-ip:443 -showcerts - Update the CA bundle HAProxy uses
On the HAProxy server, the default CA bundle path is often/etc/ssl/certs/ca-bundle.crtor/etc/haproxy/ca.crt. Check which one your config references:
If the backend server's issuer changed, add the new CA to that file. Or point to a custom bundle that includes it.grep -R 'ca-file' /etc/haproxy/ - Verify the backend server's hostname or IP matches the cert
Use openssl again to check the Subject Alternative Names (SANs):
If the backend server's DNS or IP in HAProxy config doesn't match what's in the cert, update the config or the cert. You can't bypass this if you haveopenssl x509 -in /path/to/server.crt -text -noout | grep -A1 'Subject Alternative Name'ssl verify required. - Restart HAProxy gracefully
After fixing the cert or CA bundle, reload HAProxy without dropping connections:
Check the logs immediately:haproxy -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid -sf $(cat /var/run/haproxy.pid)journalctl -u haproxy -n 20. You should seeServer is UPlines.
What to Check If It Still Fails
If the error persists after the steps above, here's what I've seen go wrong:
- Cipher mismatch — The backend server might use a cipher HAProxy doesn't support. On older backend servers (e.g., Apache 2.4 with OpenSSL 1.0.2), you might need to relax the cipher list in HAProxy with
ssl-default-bind-ciphers. - OCSP stapling — If HAProxy is set to enforce OCSP stapling on the backend (rare but possible), the backend server might not support it. Disable it in the backend config with
verify nonetemporarily to test. - Firewall or SNAT — The backend server might see the HAProxy IP as the client IP. If your firewall drops packets from HAProxy to the backend on port 443, you'll get timeouts that look like SSL errors. Check
tcpdumpon the backend for incoming SYN packets.
One more thing: if you're using self-signed certs on the backend, you must add them to the HAProxy CA bundle. No exceptions. That trips up a lot of people.
Real example: last month a client had a dev environment where the backend cert expired overnight. HAProxy rejected every connection. They spent an hour checking HAProxy config before I told them to check the backend server's cert. Renewed it, fixed the chain, reloaded HAProxy — problem gone.
Was this solution helpful?