{"id":3905,"date":"2020-08-18T16:22:58","date_gmt":"2020-08-18T10:52:58","guid":{"rendered":"https:\/\/opstree.com\/blog\/\/?p=3905"},"modified":"2020-08-25T11:40:41","modified_gmt":"2020-08-25T06:10:41","slug":"haproxy-hurdles-walkthrough","status":"publish","type":"post","link":"https:\/\/opstree.com\/blog\/2020\/08\/18\/haproxy-hurdles-walkthrough\/","title":{"rendered":"HAProxy Hurdles Walkthrough"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"945\" height=\"630\" src=\"https:\/\/opstree.com\/blog\/\/wp-content\/uploads\/2020\/08\/jumping_hurdles.gif?w=945\" alt=\"\" class=\"wp-image-3943\" \/><\/figure>\n\n\n<p class=\"has-text-align-justify\">HAProxy is one of the most frequently used and efficient tools out there for load-balancing. It is highly configurable and can handle almost all of one\u2019s needs to set up a HA, scalable infrastructure in both, HTTP and TCP. Its clientele is a testament to that as it is used and recommended by various heavy-hitters in the industry like Airbnb, Github, instagram, reddit, etc.\u00a0<\/p>\n<p><!--more--><\/p>\n<p class=\"has-text-align-justify\">With this scale of usage, naturally, there\u2019s a lot of help available in different communities if someone runs into a configuration problem. Especially when StackOverflow itself uses HAProxy extensively. That being said, in my experience, sometimes, it becomes a difficult and time-consuming process to troubleshoot HAProxy configuration issues when one is not well-versed in it. For this reason, we are going to discuss a few problems that we frequently encountered in our HAProxy setup and how we mitigated them.<\/p>\n<h5 class=\"has-text-align-justify\"><strong>Order of rules<\/strong><\/h5>\n\n\n<p class=\"has-text-align-justify\">HAProxy, like any other load-balancer, prioritises the rules that are written first in its configuration. That makes sense but sometimes, in path-based routing, one path could be a substring of the other path, for example,&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code\">acl is_kitchen_mapping_ui path_beg \/kitchen\nuse_backend dev_kitchen_mapping_ui if is_kitchen_mapping_ui\n\nacl is_kitchen_mapping_api path_beg \/kitchen-api\nuse_backend dev_kitchen_mapping_api if is_kitchen_mapping_api<\/pre>\n\n\n\n<p class=\"has-text-align-justify\">Here, all the requests for \/kitchen-api are most likely to go to \/kitchen as \/kitchen is written first and is a substring of \/kitchen-api. Therefore, any request in the form of <strong>www.mapmykitchen.com\/kitchen-api\/?token=spoons<\/strong> is likely to go to <strong>www.mapmykitchen.com\/kitchen\/?token=spoons<\/strong> as it will be matched first.<\/p>\n\n\n\n<p class=\"has-text-align-justify\">This problem could be avoided by simply moving acl configuration for \/kitchen-api above the one for \/kitchen. All requests for \/kitchen would still be routed to the correct path as they won\u2019t be matched with \/kitchen-api.<\/p>\n\n\n\n<p class=\"has-medium-font-size\"><strong>Redirect<\/strong><\/p>\n\n\n\n<p class=\"has-text-align-justify\">Sometimes we have to move our endpoint to a new name. It could be due to any reason but it requires a change in the pathname for HTTP requests. In such cases, we have to redirect all requests directed at the old path to the new one. It could be configured in the HAProxy configuration like below,<\/p>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code\">acl old_kitchen_url path_beg \/kitchen-king\nacl is_kitchen_mapping_ui path_beg \/kitchen\nhttp-request redirect location \/kitchen\/ code 301 if old_kitchen_url\nuse_backend dev_kitchen_mapping_ui if is_kitchen_mapping_ui<\/pre>\n\n\n\n<p class=\"has-text-align-justify\">This would do the job but there\u2019s an issue, it will not forward the whole request URL to the redirected endpoint as in <strong>www.mapmykitchen.com\/kitchen-king\/kitchen-api\/?token=spoons<\/strong> will just become <strong>www.mapmykitchen.com\/kitchen\/<\/strong>. To redirect the whole request, we need to change the target string with regsub in captured request URL,<\/p>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code\">http-request redirect code 301 location \/\/%[req.hdr(Host)]%[capture.req.uri,regsub(\"\/kitchen-king\/\",\"\/kitchen\")] if old_kitchen_url<\/pre>\n\n\n\n<p>So the configuration becomes,<\/p>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code\">acl old_kitchen_url path_beg \/kitchen-king\nacl is_kitchen_mapping_ui path_beg \/kitchen\nhttp-request redirect code 301 location \/\/%[req.hdr(Host)]%[capture.req.uri,regsub(\"\/kitchen-king\/\",\"\/kitchen\")] if old_kitechen_url\nuse_backend dev_kitchen_mapping_ui if is_kitchen_mapping_ui<\/pre>\n\n\n\n<p class=\"has-medium-font-size\"><strong>Conditions<\/strong><\/p>\n\n\n\n<p class=\"has-text-align-justify\">We put a lot of conditions in our acl\u2019s. Sometimes due to a miscalculation in logic, we might end up with an error or wrong path. Therefore, let\u2019s get this concept straight once and for all. We work with three logical operators, AND, OR, and, NOT. The statements where we use these operators are if and unless.<\/p>\n\n\n\n<p>Consider this example where we need to add a header called X-Datatype and route request on the basis of path and another header called X-Utensil-Category,<\/p>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code\">acl datatype_exists req.hdr(X-Datatype) -m found<\/pre>\n\n\n\n<p>This checks if X-Datatype header already exists.<\/p>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code\">http-request add-header X-Datatype \u201cutensils\u201d unless datatype_exists<\/pre>\n\n\n\n<p>This adds X-Datatype header if not already present.<\/p>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code\">acl is_spoons hdr(X-Utensil-Category) -i spoons<\/pre>\n\n\n\n<p>This does a case sensitive match on the value of header X-Utensil-Category.<\/p>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code\">acl is_kitchen_mapping_ui path_beg \/kitchen\nuse_backend dev_kitchen_mapping_ui if is_kitchen_mapping_ui is_spoons<\/pre>\n\n\n\n<p>Now, the request is routed to backend only when both is_kitchen_mapping_ui and is_spoons exist because the default operator is AND.<\/p>\n\n\n\n<p>If we want to use backend when either of them exists, we can write,<\/p>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code\">use_backend dev_kitchen_mapping_ui if is_kitchen_mapping_ui or is_spoons<\/pre>\n\n\n\n<p>If we want to throw X-Datatype in the mix and as well and make it a required acl, we can write,<\/p>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code\">use_backend dev_kitchen_mapping_ui if is_kitchen_mapping_ui and datatype_exists or is_spoons and datatype_exists<\/pre>\n\n\n\n<p>Easily enough, we can put &#8216;!&#8217; in front of an acl name to put a NOT condition,<\/p>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code\">use_backend dev_kitchen_mapping_ui if is_kitchen_mapping_ui !is_spoons<\/pre>\n\n\n\n<p>Here, the request will be routed to the backend when path \/kitchen exists and header X-Utensil-Category does not exist.<\/p>\n\n\n\n<p class=\"has-medium-font-size\"><strong>Some useful points<\/strong><\/p>\n\n\n\n<ol><li>Sometimes we start getting 503 for the particular backend. We go to the servers and investigate. The application is working fine, listening to port\/socket, ports are open, etc. In such cases make sure that if there\u2019s a health check configured, it is working fine. If healthcheck fails, the request won\u2019t go to the backend even if the backend is up.<\/li><li>HAProxy provides a stats page where we can see the status of all backends. It gives detailed insight into live status of all the backends. It\u2019s quite helpful if you have several backends configured. Read more about it <a href=\"https:\/\/www.haproxy.com\/blog\/exploring-the-haproxy-stats-page\/\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/www.haproxy.com\/blog\/exploring-the-haproxy-stats-page\/<\/a><\/li><li>HAProxy acl allows us to route requests based on a ton of conditions. The level of configuration it allows is quite interesting. Read more about it <a href=\"https:\/\/www.haproxy.com\/blog\/introduction-to-haproxy-acls\/\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/www.haproxy.com\/blog\/introduction-to-haproxy-acls\/<\/a><\/li><\/ol>\n\n\n\n<p class=\"has-text-align-justify\">In this blog, we mostly discussed issues and tips related to acl configuration. There\u2019s a ton of things to talk about backend configuration as well. Backends also support regular expressions which can be used to redirect or edit requests, we can configure active\/passive servers for our backends, configure healthchecks as mentioned above, configure consecutive healthchecks to mark a backend up or down, set or delete the header, load-balancing policy, and a lot of other things. We may cover those in another blog. Thanks for reading.<\/p>\n\n\n\n<p>Image Source: <a href=\"https:\/\/www.nytimes.com\/guides\/working-womans-handbook\/how-to-overcome-failure\" target=\"_blank\" rel=\"noopener\">NYTimes<\/a><br><br><\/p>\n\n\n\n<div class=\"wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button\">\r\n<p>Opstree is an End to End DevOps solution provider<\/p>\r\n<p>\n\n\n\n<div class=\"wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link\" title=\"https:\/\/www.opstree.com\/contact-us\" href=\"https:\/\/www.opstree.com\/contact-us\" target=\"_blank\" rel=\"noopener\">contact us<\/a><\/div>\r\n<\/div>\r\n<\/div>\r\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>HAProxy is one of the most frequently used and efficient tools out there for load-balancing. It is highly configurable and can handle almost all of one\u2019s needs to set up a HA, scalable infrastructure in both, HTTP and TCP. Its clientele is a testament to that as it is used and recommended by various heavy-hitters &hellip; <a href=\"https:\/\/opstree.com\/blog\/2020\/08\/18\/haproxy-hurdles-walkthrough\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;HAProxy Hurdles Walkthrough&#8221;<\/span><\/a><\/p>\n","protected":false},"author":155574231,"featured_media":29900,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_coblocks_attr":"","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":"","jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[28070474],"tags":[6987670,4914082,9628],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/opstree.com\/blog\/wp-content\/uploads\/2025\/11\/DevSecOps-1.jpg","jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pfDBOm-10Z","jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts\/3905"}],"collection":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/users\/155574231"}],"replies":[{"embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/comments?post=3905"}],"version-history":[{"count":24,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts\/3905\/revisions"}],"predecessor-version":[{"id":3964,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts\/3905\/revisions\/3964"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/media\/29900"}],"wp:attachment":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/media?parent=3905"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/categories?post=3905"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/tags?post=3905"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}