Header RSS Feed
 
If you only want to see the articles of a certain category, please click on the desired category below:
ALL Android Backup BSD Database Hacks Hardware Internet Linux Mail MySQL Monitoring Network Personal PHP Proxy Shell Solaris Unix Virtualization VMware Windows Wyse

HAProxy: Forward based on string in url combined with existing acl
Friday - May 22nd 2015 - by - (1 comments)

I got a special request to configure a HAProxy load balancer to use a different backend when a certain string was found in the URL.
There are already some very good answers how to do that (for example http://serverfault.com/questions/127491/haproxy-forward-to-a-different-web-server-based-on-uri) but I had to adapt the config for my environment which includes a combination of already existing acl's.

To show the current architecture:

test.example.com -> backend1 -> internalserver1:8888
stage.example.com -> backend2 -> internalserver2:8888

Because the HAProxy listens on the same IP address, both domains test.example.com and stage.example.com are handled by the same HAProxy. But depending on which domain was called, the requests should be forwarded to a different backend.
To be able to handle different domains, an acl which checks the requested host address does the job:

frontend main_http
    bind *:80

    # Define ACL based on host names
    acl test_host hdr(host) -i test.example.com
    acl stage_host hdr(host) -i stage.example.com

    # Default Route to normal backends
    use_backend backend_test_8888 if test_host
    use_backend backend_stage_8888 if stage_host

The ACL's "test_host" and "stage_host" check which host name was requested by using hdr(host). If it matches test.example.com, the acl "test_host" is set to true.
Depending which ACL is true (e.g. which host name was requested), a different backend is used (backend_test_8888 or backend_stage_8888).

Now I need an additional ACL which handles a special string (blog) in the requested URL. These requests should be sent to another backend.

test.example.com -> backend1 -> internalserver1:8888
test.example.com/bla/blog/page3 -> backend3 -> internalserver1:8889
stage.example.com -> backend2 -> internalserver2:8888
stage.example.com/bla/blog/page3 -> backend4 -> internalserver2:8889

In the serverfault.com example from above the answer was to use "path_beg" but that doesn't work for my case because I need to make sure that the string is not only at the beginning of the URI, it could appear literally anywhere in the whole URI.

To solve this, I created the following ACL which uses the sub(-string) rather than beg lookup method:

    # Define ACL based on string in URI
    acl blog_in_uri path_sub blog

So the ACL "blog_in_uri" is set to true, as soon as the string "blog" appears in the requested URI.

How to combine these two ACL's now? First I needed to create separate backends to handle the different destination ports:

#---------------------------------------------------------------------
# backend_test_8889
#---------------------------------------------------------------------
backend backend_test_8889
    balance     source
    server      intenralserver1 192.168.44.10:8889 check inter 2000 fall 1 rise 3
    server      intenralserver11 192.168.44.11:8889 check inter 2000 fall 1 rise 3

#---------------------------------------------------------------------
# backend_stage_8889
#---------------------------------------------------------------------
backend backend_stage_8889
    balance     source
    server      intenralserver2 192.168.44.20:8889 check inter 2000 fall 1 rise 3
    server      intenralserver22 192.168.44.22:8889 check inter 2000 fall 1 rise 3

Then I combined the ACL's in the "use_backend" syntax. Important is the following information from the HAProxy config documentation:

There may be as many "use_backend" rules as desired. All of these rules are evaluated in their declaration order, and the first one which matches will assign the backend.

This means that in my scenario I have to use the ACL combination (hostname + blog in uri) first. If it doesn't match, it will use the second ACL (hostname only).
To combine two or more ACL's just write both one after another. HAProxy will understand this as logical AND (do not add the word ADD into the config, this is considered a syntax error!):

frontend main_http
    bind *:80

    # Define ACL based on host names
    acl test_host hdr(host) -i test.example.com
    acl stage_host hdr(host) -i stage.example.com

    # Define ACL based on string in URI
    acl blog_in_uri path_sub blog

    # Special route which matches both hostname and string acl
    use_backend backend_test_8889 if test_host blog_in_uri
    use_backend backend_stage_8889 if stage_host blog_in_uri

    # Default Route to normal backends
    use_backend backend_test_8888 if test_host
    use_backend backend_stage_8888 if stage_host

Now all the requests which contain the string "blog" in the URI will be forwarded to a different backend rather than using the default backend for the requested domain.

 

Add a comment

Show form to leave a comment

Comments (newest first):

Rodolfo from Portugal wrote on Feb 7th, 2017:
Amazing Solution!

Thank you!


Go to Homepage home
Linux Howtos how to's
Nagios Plugins nagios plugins
Links links

Valid HTML 4.01 Transitional
Valid CSS!
[Valid RSS]

7633 Days
until Death of Computers
Why?