What ca-file will facilitate an actual SSL Handschake to a remote Nginx server?

HaProxy is public facing. It has its own cert from Lets Encrypt that seems ok. Actually there are two such servers sharing a floating IP connected by Keepalived. All of that works. HaProxy is supposed to be proxying to a couple of backend servers running Nginx. Everything works fine with no certificates, but I get an SSL handshake failure when I try to pass to a secure Nginx connection. The HaProxy cert is concatenated from the priv.pem and fullchain.pem The ca-file for the back end servers that I’m trying to use is just the fullchain.pem.

Would be grateful for any advice.

If I curl -v I get this:

* Trying 5.161.23.35:443...

* TCP_NODELAY set

* Connected to taroaro42791.com (5.161.23.35) port 443 (#0)

* ALPN, offering h2

* ALPN, offering http/1.1

* successfully set certificate verify locations:

* CAfile: /etc/ssl/certs/ca-certificates.crt

CApath: /etc/ssl/certs

* TLSv1.3 (OUT), TLS handshake, Client hello (1):

* TLSv1.3 (IN), TLS handshake, Server hello (2):

* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):

* TLSv1.3 (IN), TLS handshake, Certificate (11):

* TLSv1.3 (IN), TLS handshake, CERT verify (15):

* TLSv1.3 (IN), TLS handshake, Finished (20):

* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):

* TLSv1.3 (OUT), TLS handshake, Finished (20):

* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384

* ALPN, server did not agree to a protocol

* Server certificate:

* subject: CN=taroaro42791.com

* start date: Jun 27 00:51:38 2022 GMT

* expire date: Sep 25 00:51:37 2022 GMT

* subjectAltName: host "taroaro42791.com" matched cert's "taroaro42791.com"

* issuer: C=US; O=Let's Encrypt; CN=R3

* SSL certificate verify ok.

> GET / HTTP/1.1

> Host: taroaro42791.com

> User-Agent: curl/7.68.0

> Accept: */*

>

* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):

* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):

* old SSL session ID is stale, removing

* Mark bundle as not supporting multiuse

* HTTP 1.0, assume close after body

< HTTP/1.0 503 Service Unavailable

< cache-control: no-cache

< content-type: text/html

<

<html><body><h1>503 Service Unavailable</h1>

No server is available to handle this request.

</body></html>

* TLSv1.3 (IN), TLS alert, close notify (256):

* Closing connection 0

* TLSv1.3 (OUT), TLS alert, close notify (256):

haproxy.config is this:

global
        log /dev/log    local0
        log /dev/log    local1 notice
        chroot /var/lib/haproxy
        stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
        stats timeout 10s
        user haproxy
        group haproxy
        daemon
        maxconn 10000

        # Default SSL material locations
        ca-base /etc/ssl/certs
        crt-base /etc/ssl/private

        # 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  10000
        timeout server  10000
        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 front-end
  mode http
  bind *:80
  bind *:443 ssl crt /etc/haproxy/certs/combined.pem
  http-request redirect scheme https unless { ssl_fc }
  option httplog
  default_backend back-end

backend back-end
  mode http
  balance roundrobin
  option log-health-checks
  server app-1 backServeroneUrl.com:443 ssl verify required ca-file /etc/haproxy/certs/fullchain-anc.pem send-proxy-v2 check
                # check-sni www.artandnewscorp.com
  server app-2 backServerTwo.com:443 ssl verify required ca-file /etc/haproxy/certs/fullchain-ltj.pem send-proxy-v2 check

** EDIT: The request goes through if I change the backend binding for the servers from

ssl verify required ca-file [ca-file path] 

to

ssl verify none

But why can’t I verify the ca-file ?

haproxy -vv gives the following:

HAProxy version 2.4.17-1ppa1~focal 2022/05/14 - https://haproxy.org/
Status: long-term supported branch - will stop receiving fixes around Q2 2026.
Known bugs: http://www.haproxy.org/bugs/bugs-2.4.17.html
Running on: Linux 5.4.0-121-generic #137-Ubuntu SMP Wed Jun 15 13:33:07 UTC 2022 x86_64
Build options :
  TARGET  = linux-glibc
  CPU     = generic
  CC      = cc
  CFLAGS  = -O2 -g -O2 -fdebug-prefix-map=/build/haproxy-ngwd1k/haproxy-2.4.17=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -Wall -Wextra -Wdeclaration-after-statement -fwrapv -Wno-address-of-packed-member -Wno-unused-label -Wno-sign-compare -Wno-unused-parameter -Wno-clobbered -Wno-missing-field-initializers -Wno-cast-function-type -Wtype-limits -Wshift-negative-value -Wshift-overflow=2 -Wduplicated-cond -Wnull-dereference
  OPTIONS = USE_PCRE2=1 USE_PCRE2_JIT=1 USE_OPENSSL=1 USE_LUA=1 USE_SLZ=1 USE_SYSTEMD=1 USE_PROMEX=1
  DEBUG   = 

Feature list : +EPOLL -KQUEUE +NETFILTER -PCRE -PCRE_JIT +PCRE2 +PCRE2_JIT +POLL -PRIVATE_CACHE +THREAD -PTHREAD_PSHARED +BACKTRACE -STATIC_PCRE -STATIC_PCRE2 +TPROXY +LINUX_TPROXY +LINUX_SPLICE +LIBCRYPT +CRYPT_H +GETADDRINFO +OPENSSL +LUA +FUTEX +ACCEPT4 -CLOSEFROM -ZLIB +SLZ +CPU_AFFINITY +TFO +NS +DL +RT -DEVICEATLAS -51DEGREES -WURFL +SYSTEMD -OBSOLETE_LINKER +PRCTL -PROCCTL +THREAD_DUMP -EVPORTS -OT -QUIC +PROMEX -MEMORY_PROFILING

Default settings :
  bufsize = 16384, maxrewrite = 1024, maxpollevents = 200

Built with multi-threading support (MAX_THREADS=64, default=2).
Built with OpenSSL version : OpenSSL 1.1.1f  31 Mar 2020
Running on OpenSSL version : OpenSSL 1.1.1f  31 Mar 2020
OpenSSL library supports TLS extensions : yes
OpenSSL library supports SNI : yes
OpenSSL library supports : TLSv1.0 TLSv1.1 TLSv1.2 TLSv1.3
Built with Lua version : Lua 5.3.3
Built with the Prometheus exporter as a service
Built with network namespace support.
Built with libslz for stateless compression.
Compression algorithms supported : identity("identity"), deflate("deflate"), raw-deflate("deflate"), gzip("gzip")
Built with transparent proxy support using: IP_TRANSPARENT IPV6_TRANSPARENT IP_FREEBIND
Built with PCRE2 version : 10.34 2019-11-21
PCRE2 library supports JIT : yes
Encrypted password support via crypt(3): yes
Built with gcc compiler version 9.4.0

Available polling systems :
      epoll : pref=300,  test result OK
       poll : pref=200,  test result OK
     select : pref=150,  test result OK
Total: 3 (3 usable), will use epoll.

Available multiplexer protocols :
(protocols marked as <default> cannot be specified using 'proto' keyword)
              h2 : mode=HTTP       side=FE|BE     mux=H2       flags=HTX|CLEAN_ABRT|HOL_RISK|NO_UPG
            fcgi : mode=HTTP       side=BE        mux=FCGI     flags=HTX|HOL_RISK|NO_UPG
       <default> : mode=HTTP       side=FE|BE     mux=H1       flags=HTX
              h1 : mode=HTTP       side=FE|BE     mux=H1       flags=HTX|NO_UPG
       <default> : mode=TCP        side=FE|BE     mux=PASS     flags=
            none : mode=TCP        side=FE|BE     mux=PASS     flags=NO_UPG

Available services : prometheus-exporter
Available filters :
	[SPOE] spoe
	[CACHE] cache
	[FCGI] fcgi-app
	[COMP] compression
	[TRACE] trace

For what it’s worth, the Nginx back is like this for both back ends:

server{
    server_name backEndServerUrl.com www.backEndServerUrl.com;
    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    add_header X-Frame-Options sameorigin;
    add_header X-Content-Type-Options nosniff;
    add_header X-Xss-Protection "1; mode=block";

    listen 443 ssl http2 proxy_protocol; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/artandnewscorp.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/artandnewscorp.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}
server{
    if ($host = www.backEndServerUrl.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    if ($host = backEndServerUrl.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    listen 80 proxy_protocol;
    server_name backEndServerUrl.com www.backEndServerUrl.com;
    return 404; # managed by Certbot
}

Solved. My lack of knowledge re: certs and how they operate on the internet was the culprit. The answer was to point to Linux /etc/ssl/certs ca-bundle.crt file rather than trying to use a cert I’d made on the remote backend via LetsEncrypt. End to end encryption seems to be achieved now, with cert checks both ways.