Core concepts

Map files

A map file contains a list of keys and values. From you load balancer configuration, you can look up a key to get its associated value. For example, you could look up which URL to use in a redirect or look up which backend to send a request to.

Map files are read at startup. After making a change to the map file, reload your load balancer configuration to put the changes into effect.

Map files for host-based routing Jump to heading

Map files help simplify complex configurations. A common example is host-based routing. In host-based routing, you choose which backend to send a request to based on the requested hostname. For example, the load balancer would relay requests for api.example.com to the backend named apiservers.

Here’s how it would work:

  1. Create a map file on the load balancer, such as hostnames.map. Add keys and values, which in this case indicate the hostname and the name of the backend to use:

    hostnames.map
    txt
    www.example.com webservers
    api.example.com apiservers
    static.example.com cacheservers
    hostnames.map
    txt
    www.example.com webservers
    api.example.com apiservers
    static.example.com cacheservers
  2. In the load balancer configuration, use a map converter to look up a value by its key.

    In this example we use the req.hdr fetch method to get the Host request header and then pass it to the map converter to look up the matching key in the file hostnames.map. If a matching key exists in the file, the converter returns its value (such as apiservers). Otherwise, it uses the default value, webservers.

    haproxy
    frontend www
    bind :80
    # Choose which backend depending on the Host header
    use_backend %[req.hdr(host),map(/hostnames.map,webservers)]
    backend webservers
    server s1 192.168.1.10:80 check
    backend apiservers
    server s1 192.168.1.20:80 check
    backend cacheservers
    server s1 192.168.1.30:80 check
    haproxy
    frontend www
    bind :80
    # Choose which backend depending on the Host header
    use_backend %[req.hdr(host),map(/hostnames.map,webservers)]
    backend webservers
    server s1 192.168.1.10:80 check
    backend apiservers
    server s1 192.168.1.20:80 check
    backend cacheservers
    server s1 192.168.1.30:80 check

Map files for path-based routing Jump to heading

Another common use case for map files is path-based routing. In path-based routing, you choose which backend to send a request to based on the requested URL path. For example, requests to the path /cart would go to the backend named cartservers, while requests to /reviews would go to the backend named reviewservers.

Here’s how it would work:

  1. Create a map file on the load balancer, such as paths.map. Add keys and values, which in this case indicate the URL path and the name of the backend to use:

    paths.map
    txt
    /cart/ cartservers
    /review/ reviewservers
    paths.map
    txt
    /cart/ cartservers
    /review/ reviewservers
  2. In the load balancer configuration, use a map_beg converter to lookup a value by its key. A key that begins with the requested value will match.

    Below, we first get the requested URL path to use as the value. We do a lookup by using the map_beg converter, which passes the value into the given map file and looks for a matching key that begins with the value. If there is no matching key found in the map file, it uses the default value webservers:

    haproxy
    frontend www
    bind :80
    # Choose which backend depending on the URL path
    use_backend %[path,map_beg(/paths.map,webservers)]
    backend webservers
    server s1 192.168.1.10:80 check
    backend cartservers
    server s1 192.168.1.20:80 check
    backend reviewservers
    server s1 192.168.1.30:80 check
    haproxy
    frontend www
    bind :80
    # Choose which backend depending on the URL path
    use_backend %[path,map_beg(/paths.map,webservers)]
    backend webservers
    server s1 192.168.1.10:80 check
    backend cartservers
    server s1 192.168.1.20:80 check
    backend reviewservers
    server s1 192.168.1.30:80 check

Map files for blue-green deployments Jump to heading

Limitations

This feature requires the HAProxy Runtime API, which is not available with HAProxy ALOHA.

In the blue-green deployment release model, you transfer traffic from a production backend, referred to as blue, to a new release, referred to as green. Use a map file and the Runtime API to manage this type of deployment.

  1. Create a text file at /bluegreen.map with a single entry:

    bluegreen.map
    text
    active backend_blue
    bluegreen.map
    text
    active backend_blue
  2. Modify your configuration to include both a blue and a green backend and add a use_backend directive to your frontend to reference the map file. Whichever backend you set in the map file will be selected for all traffic.

    haproxy
    frontend fe_main
    bind :80
    use_backend %[str(active),map(/bluegreen.map)]
    backend backend_blue
    server server1 10.0.0.3:80 check
    server server2 10.0.0.4:80 check
    backend backend_green
    server server1 10.0.0.5:80 check
    server server2 10.0.0.6:80 check
    haproxy
    frontend fe_main
    bind :80
    use_backend %[str(active),map(/bluegreen.map)]
    backend backend_blue
    server server1 10.0.0.3:80 check
    server server2 10.0.0.4:80 check
    backend backend_green
    server server1 10.0.0.5:80 check
    server server2 10.0.0.6:80 check
  3. Use the Runtime API to modify the map to move traffic from blue to green as open connections to backend_blue close:

    nix
    echo "set map /bluegreen.map active backend_green" | socat stdio unix-connect:/var/run/hapee-3.0/hapee-lb.sock
    nix
    echo "set map /bluegreen.map active backend_green" | socat stdio unix-connect:/var/run/hapee-3.0/hapee-lb.sock

Virtual and optional files Jump to heading

Available since

  • HAProxy 3.0
  • HAProxy ALOHA 16.5
  • HAProxy Enterprise 3.0r1

The examples so far show how to define a map file that you save to your server’s filesystem. But you can also use virtual and optional map files, which can exist in memory.

  • A virtual file does not exist on disk and exists only in memory. The load balancer creates it as an in-memory representation during startup. Virtual files will not persist after restarting the load balancer.

  • When you mark a file as optional, the load balancer will check for it on the filesystem, but if it doesn’t find it, it will assume that the file is virtual. Optional files are useful for allowing startup without a file on disk, but saving the file to disk at a later time for long-term persistence.

To create a virtual file:

  1. Prefix the filename with virt@. Here, we define a virtual map file named hostnames.map where the keys are hostnames and the values are the backends to route requests to for each hostname. The virtual file will exist only in memory:

    haproxy
    frontend www
    bind :80
    # Choose which backend depending on the Host header
    use_backend %[req.hdr(host),map(virt@hostnames.map)]
    haproxy
    frontend www
    bind :80
    # Choose which backend depending on the Host header
    use_backend %[req.hdr(host),map(virt@hostnames.map)]
  2. Use the Runtime API commands add map and del map to add or remove values from the virtual file.

    In this example, we add the key-value pair www.example.com webservers to the virtual map file hostnames.map:

    nix
    echo "add map virt@hostnames.map www.example.com webservers" | sudo socat stdio tcp4-connect:127.0.0.1:9999
    nix
    echo "add map virt@hostnames.map www.example.com webservers" | sudo socat stdio tcp4-connect:127.0.0.1:9999

To create an optional file:

  1. Prefix the filename with opt@. Here, we define the same hostnames.map file to route requests by hostname, but this time the file is optional. It can exist on the filesystem, but if not found will be loaded as a virtual, in-memory file:

    haproxy
    frontend www
    bind :80
    # Choose which backend depending on the Host header
    use_backend %[req.hdr(host),map(opt@hostnames.map)]
    haproxy
    frontend www
    bind :80
    # Choose which backend depending on the Host header
    use_backend %[req.hdr(host),map(opt@hostnames.map)]
  2. Use the Runtime API commands add map and del map to add or remove values from the optional file. Note that you should not include the opt@ prefix when updating optional files with the Runtime API.

    In this example, we add the key-value pair www.example.com webservers to the optional map file hostnames.map:

    nix
    echo "add map hostnames.map www.example.com webservers" | sudo socat stdio tcp4-connect:127.0.0.1:9999
    nix
    echo "add map hostnames.map www.example.com webservers" | sudo socat stdio tcp4-connect:127.0.0.1:9999
  3. Use the Runtime API to save the optional file to disk before reloading or restarting the load balancer. You can use the show map command. This command returns multiple columns, but you can use awk to get only the columns you want. Then direct the output to a file.

    In this example, we get the contents of the hostnames.map optional file with the show map command, use awk to get only the second and third columns of the output, and then write the result to the file hostnames.map:

    nix
    echo "show map hostnames.map" | sudo socat stdio tcp4-connect:127.0.0.1:9999 | awk '{print $2,$3}' > hostnames.map
    nix
    echo "show map hostnames.map" | sudo socat stdio tcp4-connect:127.0.0.1:9999 | awk '{print $2,$3}' > hostnames.map
    hostnames.map
    text
    www.example.com webservers
    api.example.com apiservers
    static.example.com cacheservers
    hostnames.map
    text
    www.example.com webservers
    api.example.com apiservers
    static.example.com cacheservers

Map converters Jump to heading

You access map files using the map family of converters. A converter’s first argument is the path to the map file. Its second argument is optional and sets a default value. Variants of the map converter allow a partial match of a key.

Match the beginning of a sample Jump to heading

The map_beg converter matches the key against the beginning of the input sample. For instance, a requested URL path of /api/weather/midwest would match the key /api/ in the map file.

routes.map
txt
/api/ apiservers
/static/ cacheservers
routes.map
txt
/api/ apiservers
/static/ cacheservers

Use the map_beg converter in your configuration:

haproxy
frontend www
bind :80
use_backend %[path,map_beg(/routes.map)]
haproxy
frontend www
bind :80
use_backend %[path,map_beg(/routes.map)]

Match the end of a sample Jump to heading

The map_end converter matches the key against the end of the input sample. For instance, a URL path /images/image.jpg would match the key .jpg in the map file.

filetypes.map
txt
.jpg cacheservers
.png cacheservers
filetypes.map
txt
.jpg cacheservers
.png cacheservers

Use the map_end converter in your configuration:

haproxy
frontend www
bind :80
use_backend %[path,map_end(/filetypes.map)]
haproxy
frontend www
bind :80
use_backend %[path,map_end(/filetypes.map)]

Match a substring of a sample Jump to heading

The map_sub converter matches a substring in the input sample. For instance, a URL path /shop/shirts/sale/ would match the key /shirts/ in the map file.

routes.map
txt
/shirts/ webservers1
/pants/ webservers2
routes.map
txt
/shirts/ webservers1
/pants/ webservers2

Use the map_sub converter in your configuration:

haproxy
frontend www
bind :80
use_backend %[path,map_sub(/routes.map)]
haproxy
frontend www
bind :80
use_backend %[path,map_sub(/routes.map)]

Match an IP address Jump to heading

The map_ip converter matches an IP address. If a key in the map file has a netmask (e.g. 192.168.0.0/16), then the IP matches if it falls within the IP range.

ipranges.map
txt
10.0.0.0/16 eastcoast
10.1.0.0/16 westcoast
ipranges.map
txt
10.0.0.0/16 eastcoast
10.1.0.0/16 westcoast

Use the map_ip converter in your configuration:

haproxy
frontend www
bind :80
use_backend %[src,map_ip(/ipranges.map)]
haproxy
frontend www
bind :80
use_backend %[src,map_ip(/ipranges.map)]

Match a domain Jump to heading

The map_dom converter matches a domain or a part of a domain against a key. For instance, the key example.com would match input samples example.com, www.example.com, or demo.example.com.

domains.map
txt
example.com webservers1
test.com webservers2
domains.map
txt
example.com webservers1
test.com webservers2

Use the map_dom converter in your configuration:

haproxy
frontend www
bind :80
use_backend %[req.hdr(host),map_dom(/domains.map)]
haproxy
frontend www
bind :80
use_backend %[req.hdr(host),map_dom(/domains.map)]

Match a regular expression Jump to heading

The map_reg converter matches the input sample based on a regular expression. For instance, the regular expression ^(\/sale\/).*(\.jpg)$ would match a URL that begins with /sale/ and ends with .jpg.

patterns.map
txt
^(\/sale\/).*(\.jpg)$ cacheservers
patterns.map
txt
^(\/sale\/).*(\.jpg)$ cacheservers

Use the map_reg converter in your configuration:

haproxy
frontend www
bind :80
use_backend %[path,map_reg(/patterns.map)]
haproxy
frontend www
bind :80
use_backend %[path,map_reg(/patterns.map)]

See also Jump to heading

Do you have any suggestions on how we can improve the content of this page?