Haproxy mixing ssl

Please fill out the fields below so we can help you better. Note: you must provide your domain name to get help. Domain names for issued certificates are all made public in Certificate Transparency logs (e.g. crt.sh | skgo.org ), so withholding your domain name here does not increase secrecy, but only makes it harder for us to provide help.

My domain is:skgo.org ,www.skgo,org, diferent server elearning.skgo.org the problem is that when i cjeck sertificates with ssl chekre it kinda rotates answers of thee ssl sertificate which has has been made with Lets Enrypt terminated in backend and frontend

Ii have setuo ha proxy with this conf

cat /etc/haproxy/haproxy.cfg
global
    maxconn 4096
    user haproxy
    group haproxy
    daemon
    log 127.0.0.1 local0
    log 127.0.0.1 local1 notice
    stats socket /var/run/haproxy.stat mode 600 level operator
    ssl-server-verify none
    ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets
    ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384
    
defaults
    log global
    mode http
    option httplog
    option dontlognull
    option forwardfor
    timeout connect 10s
    timeout client 60s
    timeout server 60s
    timeout http-request 15s
    timeout http-keep-alive 15s

    # Enable statistics and monitoring
    stats enable
    stats uri /stats
    stats realm "HAProxy Statistics"
    stats auth redacted:redacted
    monitor-uri /monitor

# Rate limiting for DDoS protection
frontend http_frontend
    bind *:80
    stick-table type ip size 1m expire 600s store gpc0,http_req_rate(10s)
    tcp-request connection accept if { src -f /etc/haproxy/whitelist.lst }
    tcp-request connection track-sc1 src if ! { src_get_gpc0 gt 40 }
    tcp-request connection reject if { src_get_gpc0 gt 40 }
    http-request add-header X-Forwarded-Proto http

    # Routing rules for HTTP
    acl skgoapp hdr_end(host) -i php52-test.skgo.local php53-test.skgo.local skgo.hostts.net exchange.org.rs skgo.org skgo.rs ivanjica.rs vladicinhan.org.rs becej.rs tutin.rs cuprija.rs knjazevac.rs vlasotince.org.rs kovin.rs kanjiza.rs bajinabasta.rs kontrolafinansija.skgo.org upitnici.mos.gov.rs kalkulator.doprinosa.skgo.org fotografije.skgo.org upitnik.skgo.org
    use_backend backend if skgoapp
    acl elearapp hdr_end(host) -i elearning.skgo.org
    use_backend elear if elearapp
    acl kandidatureapp hdr_end(host) -i e-izbori.skgo.org
    use_backend kandidature if kandidatureapp
    acl pifls hdr_end(host) -i pifls.skgo.org
    use_backend pifls if pifls
    acl is_secure hdr(host) -i www.skgo.org skgo.org
    acl is_elearning hdr(host) -i elearning.skgo.org
    http-request redirect scheme https if is_secure
    use_backend local_app if !is_secure

    default_backend default_backend

frontend httpswww_skgofrontend
    #bind *:443 ssl crt /etc/haproxy/certs/skgo.org.pem
    bind *:443 ssl crt /etc/haproxy/certs/skgo.org.pem ca-file /etc/haproxy/ca/skgo.org.ca.pem verify optional
    http-request add-header X-Forwarded-Proto https
    http-response set-header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"

    # Routing rules for HTTPS www.skgo.org
    acl is_skgo hdr_dom(host) -i skgo.org www.skgo.org
    use_backend backend_skgo if is_skgo

    default_backend default_backend


frontend elearninghttps_frontend
    bind *:443 ssl crt /etc/haproxy/certs/elearning.skgo.org.pem ca-file /etc/haproxy/ca/elearning.skgo.org.ca.pem verify optional
    http-request add-header X-Forwarded-Proto https
    http-response set-header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"

    # Routing rules for HTTPS elearning.skgo.org
    acl is_elearning hdr_dom(host) -i elearning.skgo.org
    use_backend backend_elearning if is_elearning

    default_backend default_backend

# Backends for applications
backend local_app
    mode http
    server local 127.0.0.1:8080 check

backend backend
    mode http
    balance roundrobin
    option httpchk GET /
    http-check expect status 200
    server app1 app1:80 cookie LB01 check inter 5000 fastinter 1000 fall 3 rise 2 weight 2 observe layer7

backend elear
    mode http
    balance roundrobin
    option httpchk GET /
    http-check expect status 200
    server app1 192.168.40.86:80 cookie LB01 check inter 5000 fastinter 1000 fall 3 rise 2 weight 2 observe layer7

backend kandidature
    mode http
    balance roundrobin
    option httpchk GET /
    http-check expect status 200
    server 192.168.40.224 192.168.40.224:80 cookie LB01 check inter 5000 fastinter 1000 fall 3 rise 2 weight 2 observe layer7

backend pifls
    mode http
    balance roundrobin
    option httpchk GET /
    #http-check expect status 200
    server 192.168.40.129 192.168.40.129:80 cookie LB01 check inter 5000 fastinter 1000 fall 3 rise 2 weight 2 observe layer7

backend backend_skgo
    mode http
    balance roundrobin
    option httpchk GET /
    http-check expect status 200
    cookie SERVERID insert indirect nocache
    server skgo1 192.168.40.209:443 ssl verify none check

backend backend_elearning
    mode http
    balance roundrobin
    option httpchk GET /
    http-check expect status 200
    cookie SERVERID insert indirect nocache
    server elearning1 192.168.40.86:443 ssl verify none check
#    server elearning  192.168.40.86:80 cookie LB01 check inter 5000 fastinter 1000 fall 3 rise 2 weight 2 observe layer7

backend default_backend
    mode http
    balance roundrobin
    option httpchk GET /
    http-check expect status 200
    server default 127.0.0.1:8080 check

# Error handling for DDoS and maintenance
backend limit_ddos
    mode http
    errorfile 503 /etc/haproxy/errors/503rate.http

backend maintenance
    mode http
    errorfile 503 /etc/haproxy/errors/503main.http

# SSH Listeners for Applications
listen app_ssh
    bind *:2201-2204
    mode tcp
    option tcpka
    timeout connect 5s
    timeout client 1h
    timeout server 1h
    option tcplog
    server app1_ssh app1:22 check
    server app2_ssh app2:22 check
    server app3_ssh 192.168.40.209:22 check
    server app4_ssh 192.168.40.138:22 check

There is only one public IP address for each of your two domains (the www. is a NXDOMAIN), so the issue must be happening within your network.

A possible cause is that you have legacy worker processes still active that have not picked up the new certificates. A potential fix for that is doing a hard restart of your processes (a full stop & start, not a graceful restart).

2 Likes

No i have different publick for both
And dns shows corrextly amd dofff internal for
Both

The two domains are each on different IPs, but the Public DNS for each domain only has one IP configured.

2 Likes

???? Meanining and

ns1.mediaworks.rs. For CNAME skgo.org.

1h
ns2.mediaworks.rs. For CNAME skgo.org.
elearning A record 178.254.148.153 ... so both sites have A records .... I don think this is the issue
the public ip Adresssed go throu FW and the to haproxy which again has 2 different back end sites which are configured properly .... ths SSL Query engine all come out ok bu SSLABS ... the thing is sometimes i need to reffresh when i vie the cert In IE or FF OR any other broweser certificate info is correct

I am no haproxy expert (by far) but would hdr(host) be better than hdr_dom(host)? You just need to do SNI matching of the inbound request.

By the way, I can easily reproduce your cert "rotation" problem just by repeating below command. I somewhat randomly get a www.skgo cert or the elearning one. This suggests haproxy acl statement is not working properly.

 echo | openssl s_client -connect skgo.org:443 | head
3 Likes

Here are the mods you sugested SNI on the incoming ... so far this solves the problem i will see when i add HTTP of other sites ...
BUT this is a solution :slight_smile:

global
    maxconn 4096
    user haproxy
    group haproxy
    daemon
    log 127.0.0.1 local0
    log 127.0.0.1 local1 notice
    stats socket /var/run/haproxy.stat mode 600 level operator
    ssl-server-verify none
    ssl-default-bind-ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
    ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets

defaults
    log global
    mode tcp
    option tcplog
    timeout connect 10s
    timeout client 60s
    timeout server 60s

frontend https_in
    bind *:443
    mode tcp
    tcp-request inspect-delay 5s
    tcp-request content accept if { req_ssl_hello_type 1 }

    # SNI-based routing
    use_backend backend_skgo if { req_ssl_sni -i skgo.org www.skgo.org }
    use_backend backend_elearning if { req_ssl_sni -i elearning.skgo.org }
    default_backend backend_default

# Backends for applications
backend backend_skgo
    mode tcp
    server skgo1 192.168.40.209:443 check

backend backend_elearning
    mode tcp
    server elearning1 192.168.40.86:443 check


backend backend_default
    mode tcp
    server default 127.0.0.1:80 check
1 Like

Glad you found something that worked. You still may want to review your method. The docs say that option is deprecated. In either case, these are better questions for HAProxy support and forum :slight_smile:

See about req_ssl_sni here:
https://cbonte.github.io/haproxy-dconv/2.0/configuration.html#7.3.5-req.ssl_sni

1 Like

I did and i have made ajustments

1 Like

Here is another option you could consider, which is the way I've been approaching it for many years now; it may or may not be correct, but it works.

Using your most recent config file:

global
    maxconn 4096
    user haproxy
    group haproxy
    daemon
    log 127.0.0.1 local0
    log 127.0.0.1 local1 notice
    stats socket /var/run/haproxy.stat mode 600 level operator
    ssl-server-verify none
    ssl-default-bind-ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
    ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets

defaults
    log global
    mode tcp
    option tcplog
    timeout connect 10s
    timeout client 60s
    timeout server 60s

# Frontends 
frontend https_in
    bind *:443 ssl crt /etc/haproxy/certs

# Hosts
acl host_www        hdr(host) -i skgo.org www.skgo.org
acl host_elearning  hdr(host) -i elearning.skgo.org

# Backend rules
use_backend backend_skgo if host_www
use_backend backend_elearning if host_elearning
default_backend backend_default

# Backends
backend backend_skgo
    server skgo1 192.168.40.209:443 check

backend backend_elearning
    server elearning1 192.168.40.86:443 check

backend backend_default
    server default 127.0.0.1:80 check

This approach requires that you provide HAProxy with a single .pem file, which I create with something like

mkdir -p /etc/haproxy/certs

cat /etc/letsencrypt/live/skgo.org/privkey.pem /etc/letsencrypt/live/skgo.org/fullchain.pem > /etc/haproxy/certs/skgo.org.pem

If you don't have multiple certificates you could just point to the single file instead of using a directory.

I use a script to check each of the certificates in /etc/haproxy/certs for updated versions in /etc/letsencrypt/live and update the files, if indicated:

#!/usr/bin/env bash

RESTART_SERVICE_FLAG=false
CERT_DIR="/etc/haproxy/certs/*"
LE_DIR="/etc/letsencrypt/live"
LE_CHECK_FILE="fullchain.pem"

for cert in $CERT_DIR
do
     cert_base="${cert##*/}"
     cert_base="${cert_base%.*}"
     source_dir="$LE_DIR/$cert_base"
     source_file="$source_dir/$LE_CHECK_FILE"

     if [ "$source_file" -nt "$cert" ]
     then
         cat "$source_dir/privkey.pem" "$source_dir/fullchain.pem" > "$cert"
         RESTART_SERVICE_FLAG=true
     fi
done

if [ "$RESTART_SERVICE_FLAG" = true ]
then
    systemctl restart haproxy
fi

# Optional: ping HealthChecks.io instance
curl -m 15 --retry 3 -o /dev/null https://hc.your.domain/ping/a12345678-9012-2345-abcd-123456789098 &> /dev/null
1 Like

I did … just like that expet I needed to use tcp mode otherwise it doesn't work