Redirect based on virtual host

Hello, I have a question.

I use HAProxy to redirect incomming traffic on post 80, 443 and 8000 and use a lot of different virtual hosts.

All incomming traffic on 443 is decrypted and forwared on port 80 to the web-servers on a closed network (using private IP addresses). Port 8000 is forwarded as is to the same internal web-servers. The web-servers have docker containers forwarding port 8000 to 443 inside the docker container.

I want to get rid of the port 8000 by replacing it by a new virtual host , lets call it foobar.mydomain.com. So in stead of calling existing-virtual-host.mydomain.com:8000 using SSL, the client will call foobar.mydomain.com

Can HAProxy be configured to handle traffic to foobar.mydomain.com (on 443) by forwarding it directly to the internal web-servers on port 8000?

Absolutely, you just set the port on the server line.

backend exampleback
 server srv1 192.168.1.55:8000

I know, but in this case we normally send all traffic to 192.1.2.3:80 except that traffic to foobar.mydomain.com that shall be sent to 192.1.2.3:8000.
The config line above do sent everything to port 8000

Ok, use a default backend for port 80 and a more specific backend for port 8000 and content switch in the frontend based on the host header.

frontend bla
 bind :443 ssl crt /etc/bla/bla.pem
 use_backend exampleBack8000 if { hdr(host) -i foobar.mydomain.com }
 default_backend exampleback

backend exampleback
 server srv1 192.168.1.55:80

backend exampleBack8000 
 server srv1 192.168.1.55:8000

It did not work. HAProxy failed to start with the use_backend command:

Logs begin at Fri 2016-10-28 04:34:09 CEST, end at Tue 2018-02-13 10:05:45 CET. –
Feb 13 10:05:35 proxy1 systemd[1]: haproxy.service start request repeated too quickly, refusing to start.
Feb 13 10:05:35 proxy1 systemd[1]: Failed to start HAProxy Load Balancer.
Subject: Unit haproxy.service has failed
Defined-By: systemd
Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel

Unit haproxy.service has failed.

The result is failed.
Feb 13 10:05:35 proxy1 systemd[1]: Unit haproxy.service entered failed state.

I got the following config:

frontend localhost
    bind <my public ip>:80
    bind <my pyblic ip>:443 ssl crt ....
    redirect scheme https if { hdr_dom(host) -m end .mydomain.com } !{ ssl_fc }
    redirect schema https if { hdr_dom(host) -m end .anotherdomain.com } !{ ssl_fc }
    use_backend nodes8 if { hdr_dom(host) -i foobar.mydomain.com }
    mode http
    default_backend nodes

I also tried the following config after readaing this page:

acl is_foobar hdr_dom(host) -i foobar.mydomain.com
use_backend nodes8 if is_foobar

but with the same result. It is the use_backend line that seem to cause the problem. The acl line is OK and does not cause any problems.

Check the config with haproxy -f /path/to/haproxy.cfg -c

Thanks. It say

[ALERT] 043/104735 (3700) : Unable to use proxy 'nodes8' with wrong mode, required: http, has: tcp.
[ALERT] 043/104735 (3700) : You may want to use 'mode http'.
[ALERT] 043/104735 (3700) : Proxy 'localhost': unable to find required use_backend: 'nodes8'.

The nodes8 configuration is:
backend nodes8
mode tcp
stats enable
stats auth haproxy:
balance roundrobin
cookie JSESSIONID prefix
option httpclose
option forwardfor
option httpchk HEAD /check.txt HTTP/1.0
server webA 192.168.1.1:8000 cookie A check port 80
server webB 192.168.1.2:8000 cookie B check port 80

There you go, you need to replace “mode tcp” with “mode http”. Your configuration does not make sense at all, you are using a lot of HTTP features with a TCP backend.

I see. The problem is that the port 8000 goes into a docker container with the port setting “0.0.0.0:8000->443/tcp” so we need to keep the https on. If I understand correctly setting mode http will force haproxy to decrypt the traffic before sending it to port 8000 on the backend servers?

Your frontend already has either plaintext traffic (port 80), or is decrypting SSL on port 443. What you are saying doesn’t make any sense. I assume this configuration is not in production and does not work (not even before the redirect based on vhost).

If you need SSL encryption on port 8000, you would add the ssl keyword on the server line and depending on your requirements verify none.

Thanks for your help.

This config IS in production and we serve http for some customers while other are forced to use SSL.

The problem is that the main web application use port 8000 to communicate with a sub-system (running in a docker container on the web servers) over SSL. But some customers do not allow other ports than 80 and 443. So we try to replace the traffic over 8000 with SSL to use a virtual host.

That impossibile because the haproxy configuration you have shown here cannot possibily work. Like I said, configure ssl on the backend server to make this happen.

Tried this today, but it does not seem to work. Haproxy forward it on port 80, not port 8000

The current config for the backend node is

backend nodes8
    mode http
    stats enable
    stats auth haproxy:secretworkshere
    balance roundrobin
    cookie JSESSIONID prefix
    option httpclose
    option forwardfor
    option httpchk HEAD /check.txt HTTP/1.0
    server webA 192.168.1.1:8000 ssl verify none cookie A check port 80
    server webB 192.158.1.2:8000 ssl verify none cookie B check port 80

Can you remove “port 80” from the configuration please.

You mean like this:

server webA 192.168.1.1:8000 ssl verify none cookie A check
server webB 192.158.1.2:8000 ssl verify none cookie B check

That did not change the behaviour. Still got it on port 80.

That’s not what haproxy does with this configuration.

I assume old haproxy instances are still running. Please kill all haproxy processes and start it again, so you are sure no old processes are still handling traffic with an obsolete configuration.

I have restarted it, but it still behave like this. I’ll look into this tomorrow.

I think the problem is in the frontend localhost config. While trying this 192.168.1.2 has been disabled. Then I tried to change the IP-address of webA to a different host, but still 192.168.1.1 get the request.

frontend localhost
    bind our-public-ip:80
    bind our-public-ip:443 ssl a-pem-file another-pem-file

    redirect scheme https if { hdr_dom(host) -m end .mydomain.com } !{ ssl_fc }
    redirect scheme https if { hdr_dom(host) -m end .anotherdomail.com } !{ ssl_fc }

    # Forward to docker containers.
    use_backend nodes8ssl if { hdr_dom(host) -m beg foobar.mydomain }

    mode http
    default_backend nodes

BTW, we use HA-Proxy version 1.5.8

It turned out that the proxy server I have been testing on was not the one that actually received the traffic from internet. For some reason the other proxy server handled it (turning it of did stopped everything).

So when I tried the config on the other proxy server, it worked.

Thanks to lukastribus for your help.