Using different backend based on Path

Hi,
I am new to HAProxy and struggling to configure my path based routing correctly.
I am using consul discovery and load-balance consul service through HAProxy.
Here is my haproxy.cfg

defaults
   mode http

frontend stats
   bind *:1936
   stats uri /
   stats show-legends
   no log

frontend http_front
   bind *:80
   default_backend emailHandler
   acl emailservice path_beg /email
   use_backend emailHandler if emailservice

backend emailHandler
    balance roundrobin
    server-template emailhandler-api 10 _emailhandler-api._tcp.service.consul resolvers consul resolve-opts allow-dup-ip resolve-prefer ipv4 check

resolvers consul
    nameserver consul 127.0.0.1:8600
    accepted_payload_size 8192
    hold valid 5s

When I try to visit http://localhost/email, I get 404. When I remove acl, my service works on http://localhost

I will be registering lot more service with consul and I want to use just one common entrypoint with different url paths for different service. Can someone please help me figure this out?

Can someone please help me? I might be missing very small thing that prevents me from implementing my solution further.
Thanks

Please be patient. Pretty sure most here are volunteers (I know I am).

What do HAProxy logs say? Was the 404 returned by a different backend than what was expected, or did HAProxy return is directly?

Also, for use_backend statements, order matters. The same might apply to default_backend, but I’m not sure. Try moving default_backend to the end of the frontend section so that your rules are in the order you intend them to execute.

frontend http_front
   bind *:80
   acl emailservice path_beg /email
   use_backend emailHandler if emailservice
   default_backend emailHandler

@stormrover,
How can I access HAProxy Logs? I am running as a Nomad system job.

I tried moving default_backend down but that didn’t help.
While I was struggling with it from last couple of weeks, I tried following in my act of desperation and that seems to be working but I don’t know if this is a correct approach.

frontend http_front
   bind *:80
   default_backend emailHandler 
   use_backend emailHandler if { path /email } || { path_beg /email/ }

backend emailHandler
    http-request replace-path /email(/)?(.*) /\2
    balance roundrobin
    server-template emailhandler-api 10 _emailhandler-api._tcp.service.consul resolvers consul resolve-opts allow-dup-ip resolve-prefer ipv4 check

I am just removing the prefix that is being passed by frontend since my app is not expecting /email

Am I doing the right thing OR there are some better approach?

Thanks for your assistance. I appreciate that.

I don’t know anything about Nomad. Wherever HAProxy is running, it should produce logs if configured to do so.

Okay, so the path of /email is only for HAProxy to route with? In that case, you need to remove it from the http-request (as you have done), but you would also have to add it back somehow in the http-response, and I don’t see an easy way of accomplishing that unless the application supports it.

A better solution would be to give this application its own hostname or subdomain. That way you can route based on the host that’s desired without messing with paths that the application depends on.

Here’s an example that assumes your subdomain is something like email.example.com:

frontend http_front
   bind *:80
   default_backend emailHandler
   acl emailservice hdr_beg(host) -i email.
   use_backend emailHandler if emailservice

backend emailHandler
    balance roundrobin
    server-template emailhandler-api 10 _emailhandler-api._tcp.service.consul resolvers consul resolve-opts allow-dup-ip resolve-prefer ipv4 check

Edit: If you only have one backend, what are you trying to route? Maybe I’m missing something…

@stormrover,
Let me first apologize for a late response. I was out sick for few days.
Reason, I want to use path to differentiate different apps in contrast to using different domain is that, traffic hist another load balancer (F5) first and I would not like to create different profile in F5 for different host. So here is what it looks like.

all requests from service1, service2, service 3 goes to F5 which routes requests to one of the HAProxy hosts from the pool and then HAProxy will route that traffic to one of the API instance registered.

Please let me know if I need to clarify more.

This is just one backend I started with in HaProxy. I will have lot more services running in HaProxy once I figure out the right approach.

You can totally use a custom path for HAProxy to route with, but your backend API or application has to support it too. If you remove the path as part of the routing within HAProxy, subsequent requests will not have that path to route with. If you leave it in, each backend has to support using that path as a “base URL” and know to return that in the body of responses. To my knowledge, HAProxy cannot modify the body of responses in such a way as to insert a base path to make up for an app not supporting it.