Letsencrypt - HTTP to HTTPS

Hey guys,

Ive used Haproxy for several years now, and its been working amazing!
Normally all it was used for, was to redirect requests from HTTP to HTTPS, and to different backends if the host header matched.

Recently we started moving servers with Letsencrypt behind the Haproxy servers, and realised that it couldnt renew the certificate.
Im 99,9% sure its because, im redirecting everything from HTTP to HTTPS, and then check for a backend that matches the host header (correct me if im wrong).

What i want to accomplish is:
I want to have be able to connect to the servers directly through HTTP, without being forwarded to HTTPS.
But only if a host header matches the given domain.
If there isnt any HTTP backends, then forward all requests to HTTPS and look for a backend there to use.
If there is a better way to accomplish this, please let me know - but the haproxy servers should not handle any form of SSL certificates (renewals or termination).

Ive attached the part of the config, that i believe is important in this case.
So to summarize - i want to be able to connect to BCK_Repo1_HTTP and BCK_Nextcloud_HTTP directly on HTTP - they redirect to HTTPS themself, and requires port 80 for Letsencrypt
But i only want to connect to the BCK_Exchange_HTTPS on HTTPS - so if i connect to http://mail.domain.dk, it should (and does) redirect me to HTTPS.

Ive tried everything in the FT_HTTP_IN with mapfiles, hdr acl, etc - but cant seem to find a proper solution.

Any help would be very much appreciated!

#Config:

frontend FT_HTTP_IN
mode tcp
bind *:80
redirect scheme https if !{ ssl_fc }

frontend FT_HTTPS_IN
mode tcp
bind *:443
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
use_backend BCK_Repo1_HTTPS if { req_ssl_sni -i repo1.domain.dk }
use_backend BCK_Exchange_HTTPS if { req_ssl_sni -i mail.domain.dk }
use_backend BCK_Nextcloud_HTTPS if { req_ssl_sni -i nc.domain.dk }
option tcp-smart-accept

###################################################################################################

BACKEND - BACKEND - BACKEND - BACKEND - BACKEND - BACKEND - BACKEND - BACKEND - BACKEND - BACKEND

###################################################################################################

backend BCK_Repo1_HTTP
mode tcp
retries 3
timeout server 300s
timeout connect 10s
server s1dck04 192.168.60.62:80 check

backend BCK_Repo1_HTTPS
mode tcp
retries 3
timeout server 300s
timeout connect 10s
server s1dck04 192.168.60.62:443 check

backend BCK_Nextcloud_HTTP
mode tcp
retries 3
timeout server 300s
timeout connect 10s
server nc1 192.168.61.60:80 check

backend BCK_Nextcloud_HTTPS
mode tcp
retries 3
timeout server 300s
timeout connect 10s
server nc1 192.168.61.60:443 check

backend BCK_Exchange_HTTPS
mode tcp
retries 3
timeout server 300s
timeout connect 10s
server EXCH02 192.168.62.85:443 check

First post here, so apologies in advance if I get the wrong drift in your question.

I believe you’re on track to not having haproxy redirect because you think you need the HTTP connection with no SSL reaching your web servers in order for LetsEncrypt to verify the challenge.

If this is the case, then why not keep the actual configuration instead (having haproxy do the redirect) with just a rule intercepting the /.well-known/acme-challenge/ path and passing it to the relevant backend?

This way you could get best of both worlds.

I’ve applied the above thoughts to a possible configuration and, while I didn’t have a chance to test it, I believe it might put you on the right track. I changed all {front|back}ends in http instead of tcp except FT_HTTPS_IN as you’re only dealing with HTTP in the first place and we need tcp on the 443 listener in order to decode SSL SNI.

frontend FT_HTTP_IN
	mode http
	bind *:80
	option forwardfor
	http-request set-header	X-Forwarded-Proto http if !https
	http-request set-header	X-Forwarded-Proto https if https
	http-request set-var(txn.txnhost) hdr(host)
	acl letsencrypt_acl path_beg /.well-known/acme-challenge/
	acl	letsencrypt_Repo1 var(txn.txnhost) -m str -i repo1.domain.dk
	acl	letsencrypt_Nextcloud var(txn.txnhost) -m str -i nc.domain.dk
	use_backend BCK_Repo1_HTTP if  letsencrypt_Repo1
	use_backend BCK_Nextcloud_HTTP if  letsencrypt_Nextcloud
	redirect scheme https if !{ ssl_fc } AND !{ letsencrypt_acl }

frontend FT_HTTPS_IN
	mode tcp
	bind *:443
	tcp-request inspect-delay 5s
	tcp-request content accept if { req_ssl_hello_type 1 }
	use_backend BCK_Repo1_HTTPS if { req_ssl_sni -i repo1.domain.dk }
	use_backend BCK_Exchange_HTTPS if { req_ssl_sni -i mail.domain.dk }
	use_backend BCK_Nextcloud_HTTPS if { req_ssl_sni -i nc.domain.dk }
	option tcp-smart-accept

backend BCK_Repo1_HTTP
	mode http
	retries 3
	timeout server 300s
	timeout connect 10s
	server s1dck04 192.168.60.62:80 check

backend BCK_Repo1_HTTPS
	mode http
	retries 3
	timeout server 300s
	timeout connect 10s
	server s1dck04 192.168.60.62:443 check

backend BCK_Nextcloud_HTTP
	mode http
	retries 3
	timeout server 300s
	timeout connect 10s
	server nc1 192.168.61.60:80 check

backend BCK_Nextcloud_HTTPS
	mode http
	retries 3
	timeout server 300s
	timeout connect 10s
	server nc1 192.168.61.60:443 check

backend BCK_Exchange_HTTPS
	mode http
	retries 3
	timeout server 300s
	timeout connect 10s
	server EXCH02 192.168.62.85:443 check
1 Like