A proper way to do SSL health check?

Hello, so I can’t figure out a proper way to do the SSL check, I am not using certificates, just need to check against a HTTPS websites url (google.com/ for example)
Trying multiple combinations at a time, without success. Maybe someone has a similar configuration,

backends using -
> check-sni google.com sni ssl_fc_sni

    returns - reason: Layer7 wrong status, code: 301, info: "Moved Permanently"

check port 80 check-ssl -

reason: Layer6 invalid response, info: “SSL handshake failure”

All others just timing out. Here’s the complete configuration file-

global
        log /dev/log    local0
        log /dev/log    local1 notice
        chroot /var/lib/haproxy
        stats socket /run/haproxy/admin.sock mode 660 level admin
        stats timeout 30s
        user haproxy
        group haproxy
        daemon

        # Default SSL material locations
        ca-base /etc/ssl/certs
        crt-base /etc/ssl/private
        ssl-server-verify none
        # Default ciphers to use on SSL-enabled listening sockets.
        # For more information, see ciphers(1SSL). This list is from:
        #  https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
        # An alternative list with additional directives can be obtained from
        #  https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=haproxy
        ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
        ssl-default-bind-options no-sslv3

defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        timeout connect 5000
        timeout client  50000
        timeout server  50000
        errorfile 400 /etc/haproxy/errors/400.http
        errorfile 403 /etc/haproxy/errors/403.http
        errorfile 408 /etc/haproxy/errors/408.http
        errorfile 500 /etc/haproxy/errors/500.http
        errorfile 502 /etc/haproxy/errors/502.http
        errorfile 503 /etc/haproxy/errors/503.http
        errorfile 504 /etc/haproxy/errors/504.http



frontend myfront
bind *:8000
mode tcp
        tcp-request inspect-delay 5s

default_backend backend1



listen stats
bind :444
stats enable
stats uri /
stats hide-version
stats auth test:test

backend Backends
balance roundrobin
option forwardfor

option httpchk

  http-check send hdr host google.com meth GET uri /

 http-check expect status 200
#http-check connect
#http-check send meth GET uri / ver HTTP/1.1 hdr host haproxy.1wt.eu
#http-check expect status 200-399
#http-check connect port 443 ssl sni haproxy.1wt.eu
#http-check send meth GET uri / ver HTTP/1.1 hdr host haproxy.1wt.eu
#http-check expect status 200-399
#http-check connect port 443 ssl sni google.com
#http-check send meth GET uri / ver HTTP/1.1 hdr host google.com


   default-server fall 10 rise 1




 server Node1011 192.168.0.2:1011 check inter 15s check-ssl check port 443
 server Node1012 192.168.0.2:1012 check inter 15s check-ssl check port 443
 server Node1015 192.168.0.2:1015 check inter 15s check port 443
 server Node1017 192.168.0.2:1017 check inter 15s check-ssl check-sni google.com sni ssl_fc_sni
 server Node1018 192.168.0.2:1018 check inter 15s check-ssl check-sni google.com sni ssl_fc_sni
 server Node1019 192.168.0.2:1019 check inter 15s check-sni google.com sni ssl_fc_sni
 server Node1020 192.168.0.2:1020 check inter 15s check port 443 check-ssl
 server Node1021 192.168.0.2:1021 check inter 15s check port 443 check-ssl

 server Node1027 192.168.0.2:1027 check inter 15s check port 80
 server Node1028 192.168.0.2:1028 check inter 15s check port 80
 server Node1029 192.168.0.2:1029 check inter 15s check port 80
 server Node1030 192.168.0.2:1030 check inter 15s check port 80 check-ssl
 server Node1031 192.168.0.2:1031 check inter 15s check port 80 check-ssl

 server Node1033 192.168.0.2:1033 check inter 15s check port 80 check-ssl verify none
 server Node1034 192.168.0.2:1034 check inter 15s check port 80 check-ssl verify none
 server Node1035 192.168.0.2:1035 check inter 15s check-ssl
 server Node1036 192.168.0.2:1036 check inter 15s check-ssl

 server Node1048 192.168.0.2:1048 check inter 15s check-ssl verify none
 server Node1049 192.168.0.2:1049 check inter 15s check-ssl verify none

Thank you!

The SSL connection establishes successfully and the Google server responds with a HTTP redirect to somewhere else.

With this configuration:

http-check expect status 200

you specifically told Haproxy to reject all HTTP responses other than 200. By default, Haproxy would consider response statuses 2xx and 3xx as valid.

Remove http-check expect status 200 from the configuration.

Just like in a Browser, when you connect HTTPS to port 80, the handshake will fail, because Google and everybody else is not terminating SSL on port 80.

1 Like

Thank you for your input, and indeed It was redirecting because I did not have the www. in front,
now I have added it to my configuration, and it looks like this -

  http-check send hdr host www.google.com meth GET uri /
 server Node1001 192.168.0.2:1001 check inter 25s check-sni www.google.com sni ssl_fc_sni

But in my logs I can see that haproxy is still not connecting to HTTPS, but trying to access-
http://www.google.com/

I have tried adding the check-ssl option like this -
server Node1001 192.168.0.2:1001 check inter 25s check-sni www.google.com sni ssl_fc_sni check-ssl verify none
but it’s just causing timeouts in logs

Any idea on how could I force haproxy to use HTTPS? Thank you!

You do need the ssl keyword, for HTTPS. I don’t see it anywhere in your configuration.

I am not looking to terminate SSL, that’s why I tried using the check-ssl option, or that’s not a correct assumption? That’s how my current server link looks -

server Node1001 192.168.0.2:1001 check inter 25s check-sni www.google.com sni ssl_fc_sni check-ssl verify none

sorry if this looks stupid, but it can be very confusing…

Right, if you want to pass SSL from frontend to the backend transparently, then you don’t need the ssl keyword.

I don’t what that means. What EXACTLY are you seeing where EXACTLY? How do you come to this conclusion?

Your frontend refers to backend1 which is non-existent, while your real backend is called Backends.

I knew you’d be confused about that part, and please let me elaborate.

I messed up the backend name when trying to hide some sensitive information, here’s how my configuration looks EXACTLY -

global
        log /dev/log    local0
        log /dev/log    local1 notice
        chroot /var/lib/haproxy
        stats socket /run/haproxy/admin.sock mode 660 level admin
        stats timeout 30s
        user haproxy
        group haproxy
        daemon

        # Default SSL material locations
        ca-base /etc/ssl/certs
        crt-base /etc/ssl/private
        ssl-server-verify none
        # Default ciphers to use on SSL-enabled listening sockets.
        # For more information, see ciphers(1SSL). This list is from:
        #  https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
        # An alternative list with additional directives can be obtained from
        #  https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=haproxy
        ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
        ssl-default-bind-options no-sslv3

defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        timeout connect 5000
        timeout client  50000
        timeout server  50000
        errorfile 400 /etc/haproxy/errors/400.http
        errorfile 403 /etc/haproxy/errors/403.http
        errorfile 408 /etc/haproxy/errors/408.http
        errorfile 500 /etc/haproxy/errors/500.http
        errorfile 502 /etc/haproxy/errors/502.http
        errorfile 503 /etc/haproxy/errors/503.http
        errorfile 504 /etc/haproxy/errors/504.http



frontend myfront
bind *:8000
mode tcp
        tcp-request inspect-delay 5s

default_backend backend1



listen stats
bind :444
stats enable
stats uri /
stats hide-version
stats auth test:test

backend backend1
balance roundrobin
option forwardfor

option httpchk

  http-check send hdr host www.instagram.com meth GET uri /

 http-check expect status 200
#http-check connect
#http-check send meth GET uri / ver HTTP/1.1 hdr host haproxy.1wt.eu
#http-check expect status 200-399
#http-check connect port 443 ssl sni haproxy.1wt.eu
#http-check send meth GET uri / ver HTTP/1.1 hdr host haproxy.1wt.eu
#http-check expect status 200-399
#http-check connect port 443 ssl sni google.com
#http-check send meth GET uri / ver HTTP/1.1 hdr host google.com


   default-server fall 10 rise 1





 server Node1002 192.168.0.2:1002 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl verify none
 server Node1003 192.168.0.2:1003 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl verify none
 server Node1004 192.168.0.2:1004 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl verify none
 server Node1005 192.168.0.2:1005 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl verify none
 server Node1006 192.168.0.2:1006 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl verify none
 server Node1007 192.168.0.2:1007 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl verify none
 server Node1008 192.168.0.2:1008 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl verify none
 server Node1009 192.168.0.2:1009 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl
 server Node1010 192.168.0.2:1010 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl verify none
 server Node1011 192.168.0.2:1011 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl verify none
 server Node1012 192.168.0.2:1012 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl verify none
 server Node1013 192.168.0.2:1013 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl verify none
 server Node1014 192.168.0.2:1014 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl verify none
 server Node1015 192.168.0.2:1015 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl verify none
 server Node1016 192.168.0.2:1016 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl verify none
 server Node1017 192.168.0.2:1017 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl verify none
 server Node1018 192.168.0.2:1018 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl verify none
 server Node1023 192.168.0.2:1023 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl verify none
 server Node1024 192.168.0.2:1024 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl verify none
 server Node1025 192.168.0.2:1025 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl verify none
 server Node1026 192.168.0.2:1026 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl verify none
 server Node1027 192.168.0.2:1027 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl verify none
 server Node1028 192.168.0.2:1028 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl verify none
 server Node1029 192.168.0.2:1029 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl verify none
 server Node1030 192.168.0.2:1030 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl verify none
 server Node1031 192.168.0.2:1031 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl verify none
 server Node1032 192.168.0.2:1032 check inter 25s check-sni instagram.com sni ssl_fc_sni check-ssl verify none

my backends are squid proxies running on the same machine, and that’s why I can see exactly what requests haproxy is making for live checks, hope it makes things more clear.

As for the logs coming from haproxy health checks I’m not even sure…, looks pretty empty,
Line1 - I’m manually doing a curl command -
curl https://instagram.com --proxy 192.168.0.2:1001
Comes up in logs as expected, and all further commands are coming from haproxy health checks

23 00:39:39 10.10.1.100 1001 CONNECT_instagram.com:443_HTTP/1.1 149.28.95.10:52028 3.224.133.228:443 253
23 00:39:39 0.0.0.0 1025 ____ 149.28.95.10:44248 0.0.0.0:0 770
23 00:39:40 0.0.0.0 1026 ____ 149.28.95.10:46218 0.0.0.0:0 662
23 00:39:41 0.0.0.0 1027 ____ 149.28.95.10:48108 0.0.0.0:0 557
23 00:39:42 0.0.0.0 1028 ____ 149.28.95.10:43786 0.0.0.0:0 448
23 00:39:43 0.0.0.0 1029 ____ 149.28.95.10:41128 0.0.0.0:0 343

Haproxy is a reverse proxy and load-balancer, not a forward proxy. I have no idea what you are trying to achieve here, but this is not the way to do it.

If you doubt that the haproxy health check is actually SSL, please capture it with tcpdump and actually look at it. You will see that it is exactly as you configured it (a SSL client hello with the instagramm SNI).

1 Like

Haproxy just happens to be a perfect solution for my proxy servers balancing needs, even though it’s not meant to be used in such way, but you are right, it’s possible that the issue is elsewhere, just wanted to make sure I got the haproxy configuration part right, if you think it should work I will move on an examine further, thank you.

No, this should definitely NOT work.

Haproxy won’t behave the way you just used the curl command, these are simply two fundamentally different things.

The curl call means connect to 192.168.0.2:1001 in PLAINTEXT HTTP and then use a HTTP CONNECT METHOD to request a transparent 443 tunnel to instagram.com for the HTTPS traffic through Squid.

Haproxy will send a SSL handshake to Squid, not a SSL handshake encapsulated in a HTTP CONNECT tunnel, requesting via plaintext HTTP.

1 Like