Own solution at the of the question.

I am using a HAProxy (on a rented virtual machine) to be able to connect to some applications I am running at home. This works perfectly fine for almost all of my backends. What doesn't work very well is the following setup: HAProxy running on port 443 in mode http having a backend with server port 10000 (Webmin) because connection works but after logging in I am being forwarded to port 10000 and after changing the port back to 443 I can use Webmin. This is not the expected behaviour.

HAProxy defaults

    mode                    http
    log                     global
    log /dev/log local0 info
    option                  httplog
    option                  dontlognull
    option http-server-close
    option forwardfor       except
    #option forwardfor
    option                  redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    balance                 leastconn

    stats enable
    stats hide-version
    stats uri /haproxy/stats
    stats refresh 10s
    stats show-node

HAProxy frontend definition This is a catchall frontend because I only have one IP on the rented virtual machine and I am using different backends depending on the host header.

frontend catchall_http
    bind *:80
    bind *:443 ssl crt MY_CERT
    acl letsencrypt path_beg /.well-known/acme-challenge/
    acl app_ns1 req.hdr(host) -i ns1.example.com
    http-response set-header Strict-Transport-Security max-age=31536000;\ includeSubDomains;\ preload; if { ssl_fc }
    use_backend ns1.home.example.com if app_ns1
    default_backend backend-not-found

HAProxy backend definition

http-request set-header X-Forwarded-Port %[dst_port] is commented in because I tested with and without.

backend ns1.home.example.com
    acl valid_http_method method GET HEAD POST
    http-request deny unless valid_http_method
    #http-request set-header X-Forwarded-Port %[dst_port]
    redirect scheme https code 301 if !{ ssl_fc }
    server ns1.home.example.com ns1.home.example.com:10000 ssl check check-ssl verify required ca-file CA_CERT

# just to get the initial necessary cookies for login
curl --request GET --cookie-jar webmin_curl_cookies --cookie webmin_curl_cookies https://ns1.example.com/
curl --request POST --data @webmin_request_payload --cookie-jar webmin_curl_cookies --cookie webmin_curl_cookies https://ns1.example.com/session_login.cgi

The result is:

Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying HAProxyIP:443...
* Connected to ns1.example.com (HAProxyIP) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* 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=ns1.example.com
*  start date: Aug 14 10:55:38 2020 GMT
*  expire date: Nov 12 10:55:38 2020 GMT
*  subjectAltName: host "ns1.example.com" matched cert's "ns1.example.com"
*  issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
*  SSL certificate verify ok.
> POST /session_login.cgi HTTP/1.1
> Host: ns1.example.com
> User-Agent: curl/7.69.1
> Accept: */*
> Cookie: redirect=1; testing=1; sid=SESS_ID
> Content-Length: 31
> Content-Type: application/x-www-form-urlencoded
* upload completely sent off: 31 out of 31 bytes
* 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 302 Moved Temporarily
< Date: Mon, 17 Aug 2020 09:40:48 GMT
< Server: MiniServ/1.953
* Replaced cookie sid="SESS_ID" for domain ns1.example.com, path /, expire 0
< Set-Cookie: sid=SESS_ID; path=/; secure; httpOnly
< Location: https://ns1.example.com:10000/
< Strict-Transport-Security: max-age=31536000; includeSubDomains; preload;
* TLSv1.3 (IN), TLS alert, close notify (256):
* Closing connection 0
* TLSv1.3 (OUT), TLS alert, close notify (256):

I think the main cause for the unwanted behaviour is the Location header in the response. How can I resolve this behaviour?

Own answer to my question:

In the backend add

http-response replace-value Location ^https://ns1.example.com:10000/$ https://ns1.example.com/

and it works. I don't know if this is a best practice solution and I'd definitely like to know that but it works for me.

  • 2
    Answers go below in the answer box. People will think your question is unanswered. – Michael Hampton Aug 17 '20 at 10:27

Answering my own question here.

I had to add the following line to the backend

http-response replace-value Location ^https://ns1.example.com:10000/$ https://ns1.example.com/

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.