HTTPS redirect does not work

Hi

I’m trying to do a very simple HTTP to HTTPS redirect. I’ve been able to do this with Traefik, so I know what I am trying is possible, but I cannot get HAProxy to do it.

I want to accept connections on port 8443, using SSL with a self signed cert, and forward to a backend on port 8000. This works if I use https://localhost:8443.

I have attempted to set up the redirects in several different ways to redirect http://localhost:8443 to https. This never works.

HAProxy 2.9.6 running in docker.

Here is my config:

# haproxy.cfg
global
  log stderr format raw local0

defaults
  log global
  option httplog
  mode http
  timeout client 10s
  timeout connect 5s
  timeout server 10s 
  timeout http-request 10s

frontend http
  mode http
  bind :8443 ssl crt /certs/server.pem
  http-request redirect scheme https code 301 if !{ ssl_fc }
  # http-request redirect scheme https if !{ ssl_fc }
  use_backend myservers


backend myservers
  mode http
  server server1 host.docker.internal:8000

I have searched high and low, and tried multiple difference constructions of the http-request redirect. I’m using curl for testing: curl -vvk http://localhost:8443

HAProxy logs an SSL error:
haproxy | 172.21.0.1:52172 [06/Mar/2024:18:20:13.511] http/1: SSL handshake failure (error:0A00009C:SSL routines::http request)

And curl response is:

*   Trying 127.0.0.1:8443...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8443 (#0)
> GET / HTTP/1.1
> Host: localhost:8443
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Empty reply from server
* Connection #0 to host localhost left intact
curl: (52) Empty reply from server

I have spent hours trying to figure this out, and it just doesn’t work. My other server using Traefik does this with no problems, so I know that a basic http to https redirect should work in theory.

What am I missing here? It doesn’t seem like it should be this difficult, but I’m 4 hours in and can’t get this to work.

Frankly, I find Traefik to be very fussy and difficult to configure, and I don’t really need the dynamic configuration so much that it is worth dealing with it. It was looking like HAProxy might be easier overall to deal with, but now I’m not so sure. Traefik may be fussy, but it can do an http to https redirect.

I cannot imagine this is an actual bug. But how do you actually get this to work?

Hi,

I have the exact same problem. Have you find any solution?

The issue described in the HAProxy community post revolves around an attempt to redirect HTTP traffic to HTTPS on port 8443 using HAProxy. The user has configured HAProxy to listen on port 8443 with SSL enabled and expects that HTTP requests to this port will be redirected to HTTPS. However, they encounter SSL handshake failures when testing with curl over HTTP.(HAProxy community, HAProxy Technologies)

Understanding the Problem:

The core of the problem lies in the configuration:

frontend http
  mode http
  bind :8443 ssl crt /certs/server.pem
  http-request redirect scheme https code 301 if !{ ssl_fc }
  use_backend myservers

Here, HAProxy is set to listen on port 8443 with SSL enabled (bind :8443 ssl crt /certs/server.pem). This means HAProxy expects SSL/TLS-encrypted connections on this port. However, when a client sends an unencrypted HTTP request to port 8443, HAProxy attempts to perform an SSL handshake, which fails because the client isn’t initiating an SSL/TLS connection. This results in the observed SSL handshake failure.(HAProxy community)

Solution:

To properly handle both HTTP and HTTPS traffic, you should configure HAProxy to listen on separate ports for each protocol:

  1. HTTP on Port 8080 (or 80): This will handle unencrypted HTTP traffic and redirect it to HTTPS.

  2. HTTPS on Port 8443 (or 443): This will handle encrypted HTTPS traffic.

Here’s how you can adjust your HAProxy configuration:(Netgate Forum)

frontend http_in
  bind *:8080
  mode http
  http-request redirect scheme https code 301

frontend https_in
  bind *:8443 ssl crt /certs/server.pem
  mode http
  default_backend myservers

backend myservers
  mode http
  server server1 host.docker.internal:8000

Explanation:

  • frontend http_in: Listens on port 8080 for HTTP traffic and redirects all requests to HTTPS on the same host.

  • frontend https_in: Listens on port 8443 for HTTPS traffic using the specified SSL certificate.

  • backend myservers: Forwards the decrypted HTTPS requests to the backend server running on port 8000.(HAProxy community)

Testing:

After updating the configuration:(HAProxy community)

  • Accessing http://localhost:8080 should redirect you to https://localhost:8443.(HAProxy community)

  • Accessing https://localhost:8443 should successfully connect to your backend server.

Additional Notes:

  • Ensure that both ports 8080 and 8443 are open and not blocked by any firewall rules.

  • If you prefer to use the standard HTTP and HTTPS ports (80 and 443), you can adjust the bind directives accordingly.

  • Remember that clients must initiate HTTPS connections on the port where SSL is enabled; HAProxy cannot perform SSL negotiation on behalf of the client if the client doesn’t initiate it.(OPNsense Forum)

By separating the HTTP and HTTPS traffic onto different ports and configuring HAProxy to handle each appropriately, you should achieve the desired redirection behavior without encountering SSL handshake errors.

ChatGPT can explain this better than I can. But this should help.

To add, you cannot run non ssl and ssl traffic on the same receiving port.(which is what you seem to be trying to do).