AWS - Network Load Balancer - HAProxy. Redirect to 443 port

Hi.

  1. Network Load Balancer is configured on AWS and listens to ports 80 and 443. Through TargetGroup, packets are sent to EC2-instance via the 443 TLS port. The domain’s SSL certificate is attached to it. HAProxy is installed and configured on EC2-instance. HAproxy forwards requests to backend servers with nginx. If you type in the browser https://example.com or http://example.com then everything works. If you configure the http->https redirect in the HAProxy configuration, the site falls into the ERR_TOO_MANY_REDIRECTS error. This was the first configuration.
  2. Changed the configuration. I removed the certificate from NLB in AWS and registered in Listener port 443 in TCP, not in TLS. Then the situation is - https://example.com works, and http://example.com it doesn’t work by falling into an error.
  3. Then I configured NLB that HealthCheck for Target Group goes on TCP port 80, and not on 443. And to my surprise, the site started to fall into the error ERR_SSL_PROTOCOL_ERROR (redirect from http to https works).
    How do I correctly configure a redirect to SSL on NLB via HAProxy?

HAProxy config:

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 30s
user haproxy
group haproxy
daemon

# 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 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 www-http
bind *:80
reqadd X-Forwarded-Proto:\ http
default_backend www-backend

frontend www-https
bind *:443 ssl crt /etc/ssl/private/example.pem
reqadd X-Forwarded-Proto:\ https
default_backend www-backend

backend www-backend
redirect scheme https if !{ ssl_fc }
server www-1 IP:443 check ssl verify none

Thank You.

Instruct AWS to forward traffic on port 80 to port 80, and traffic on port 443 to port 443. If that is happening, your configuration will work just fine.

That said, I can can simplify your configuration by moving the redirect to www frontend, remove the acl and the default_backend instruction, since on port 80 all you want to do is redirect to https.

frontend www-http
bind *:80
redirect scheme https

frontend www-https
bind *:443 ssl crt /etc/ssl/private/example.pem
reqadd X-Forwarded-Proto:\ https
default_backend www-backend

backend www-backend
server www-1 IP:443 check ssl verify none

Thank you for the answer, but unfortunately it didn’t help.

Changed the haproxy configuration and the error is the same - ERR_SSL_PROTOCOL_ERROR. I think your comment about AWS was about Classic Load Balancer (where you can specify which port to send packets from). But I have configured Network Load Balancer there are specified only ports on which traffic arrives. Classic Load Balancer doesn’t suit me - I can’t assign Elastic IP on it.

My NLB configuration are attached in screenshots.
Снимок экрана от 2020-12-03 12-42-55

I don’t know what you configured on the Amazon LB, but clearly it’s wrong.

I also don’t know what your intended configuration will look like.

Do you want to terminate SSL on the Amazon Load-balancer, or do you just want to forward TCP traffic and terminate SSL only on haproxy? I know your tried both for troubleshooting, but I don’t know what it is that you actually want.

The simplest configuration would be to make Amazon just forward traffic on a TCP level, port 80 to port 80, and port 443 to port 443, however you must not specify “SSL” anywhere at Amazon, otherwise it will reencrypt traffic that is already encrypted.

AWS has 3 types of load balancers: Classic Load Balancer, Network Load Balancer, and Application Load Balancer. Classic and Application don’t suit me because in the first one I can’t push real IP users through the load balancer, and in the second one I can’t bind Elastic IP. Network Load Balancer can do everything you need, but it doesn’t work with the usual redirect from http to https. I don’t care where the SSL certificate is located. And I already realized that the certificate should not be on Amazon, but on HAProxy. And now it is set up exactly like this. LB just throws lets packets, HAPRoxy with pem certificates, the configuration that you suggested to me is configured. And the browser opens the error ERR_SSL_PROTOCOL_ERROR.
Amazon LB is set up simply. 80 and 443 ports. Available from 0.0.0.0/0. Thas all.
Thank you for your feedback.

Then how are you able to get the client source IP? Did you enable the proxy protocol on NLB?

HAProxy config:
option forwardfor header X-Real-IP

NGINX config:
set_real_ip_from HAPROXY-IP-ADDRESS;
real_ip_header X-Real-IP;

Proxy protocol on NLB is disabled.

Exclude NLB and try directly. If that works, than NLB is missconfigured. If it doesn’t change anything (still doesn’t work with a ERR_SSL_PROTOCOL_ERROR), then there is an issue probably with the SSL configuration on haproxy.

I tried it. Everything works well without NLB. But I do not understand that there can be configured incorrectly if there is nothing special to configure. There are almost no settings there. :slight_smile:

Why do the two listeners have the same default action, when they should do something different?

I don’t know anything about this NLB, but I think they should have different actions?

1 Like

Hi, if I may, I think the suggestion from Lukas is the correct one.
You should define 2 target groups:

  • http_tg, on port 80
  • https_tg, on port 443
    They can (and should) target the same autoscaling group.

That way, the ssl traffic will correctly be sent to the ssl port on haproxy. (I guess you are only forwarding traffic to TCP/80 with you current setup).

1 Like

Sorry, I haven’t had time to check the last few days. Yes, you were right. I created 2 Target groups - for port 80, for port 443. And everything worked. Thank you very much.
PS: However, for some reason, redirection from www to non-www does not work.
In Route 53 (DNS) create a CNAME www.example.com leading to example.com.

Without NLB only with HAProxy this works:
httprequest redirect prefix https://%[hdr(host),regsub(^www.,i)] code 301 if { her_big(host) -i www. }

Entered this

http-request redirect prefix https://%[hdr(host),regsub(^www.,i)] code 301 if { her_big(host) -i www. }

in frontend www-http and everything worked.

Thank you very much for your help! Everything works!
@lukastribus @baptiste64, unfortunately I can’t choose 2 answers as solution. You both helped.

1 Like