HAProxy config tutorials

DNS resolution

A resolvers section lists DNS nameservers that the load balancer will query when it needs to resolve a hostname to an IP address. A resolvers section is followed by a label, such as mynameservers, to differentiate it from others.

haproxy
resolvers mynameservers
nameserver ns1 192.168.2.10:53
nameserver ns2 192.168.3.10:53
haproxy
resolvers mynameservers
nameserver ns1 192.168.2.10:53
nameserver ns2 192.168.3.10:53

Each nameserver line indicates the IP address and port of a DNS nameserver. The load balancer sends a query to all of the nameservers and uses the first, valid response that it receives.

Resolve server hostnames Jump to heading

The most common way to use this feature is to configure backend servers with hostnames instead of IP addresses.

In the following configuration sample, each server defined in the backend webservers is using the resolvers argument to reference the resolvers section named mynameservers:

haproxy
resolvers mynameservers
nameserver ns1 192.168.2.10:53
nameserver ns2 192.168.3.10:53
backend webservers
server s1 hostname1.example.com:80 check resolvers mynameservers
server s2 hostname2.example.com:8080 check resolvers mynameservers
server s3 hostname3.example.com:8080 check resolvers mynameservers
haproxy
resolvers mynameservers
nameserver ns1 192.168.2.10:53
nameserver ns2 192.168.3.10:53
backend webservers
server s1 hostname1.example.com:80 check resolvers mynameservers
server s2 hostname2.example.com:8080 check resolvers mynameservers
server s3 hostname3.example.com:8080 check resolvers mynameservers

Adjust DNS resolver settings Jump to heading

Various options in the resolvers section exist to adjust how the load balancer queries nameservers and caches the responses.

The following sample configuration contains a resolvers section with all available options configured. The parse-resolv-conf directive became available in HAProxy version 1.8.

haproxy
resolvers mynameservers
nameserver ns1 192.168.2.10:53
nameserver ns2 192.168.3.10:53
# Maximum size of a DNS answer allowed, in bytes
accepted_payload_size 512
# Whether to add nameservers found in /etc/resolv.conf
parse-resolv-conf
# How long to "hold" a backend server's up/down status depending on the name resolution status.
# For example, if an NXDOMAIN response is returned, keep the backend server in its current state (up) for
# at least another 30 seconds before marking it as down due to DNS not having a record for it.
hold valid 10s
hold other 30s
hold refused 30s
hold nx 30s
hold timeout 30s
hold obsolete 30s
# How many times to retry a query
resolve_retries 3
# How long to wait between retries when no valid response has been received
timeout retry 1s
# How long to wait for a successful resolution
timeout resolve 1s
haproxy
resolvers mynameservers
nameserver ns1 192.168.2.10:53
nameserver ns2 192.168.3.10:53
# Maximum size of a DNS answer allowed, in bytes
accepted_payload_size 512
# Whether to add nameservers found in /etc/resolv.conf
parse-resolv-conf
# How long to "hold" a backend server's up/down status depending on the name resolution status.
# For example, if an NXDOMAIN response is returned, keep the backend server in its current state (up) for
# at least another 30 seconds before marking it as down due to DNS not having a record for it.
hold valid 10s
hold other 30s
hold refused 30s
hold nx 30s
hold timeout 30s
hold obsolete 30s
# How many times to retry a query
resolve_retries 3
# How long to wait between retries when no valid response has been received
timeout retry 1s
# How long to wait for a successful resolution
timeout resolve 1s

Delay DNS resolution with init-addr Jump to heading

Available since

  • HAProxy 1.7
  • HAProxy Enterprise 1.7r1
  • HAProxy ALOHA 9.0

Resolution happens when the load balancer starts or reloads. However, in some cases, the DNS records may not be available yet, such as in dynamic environments that leverage DNS-based service discovery for populating DNS records. This would result in the load balancer failing to start since failure to resolve an address is fatal.

To control this behavior, use the init-addr argument on the server line, followed by comma-separated resolution methods:

haproxy
backend webservers
server s1 hostname1.example.com:80 check resolvers mynameservers init-addr last,libc,none
haproxy
backend webservers
server s1 hostname1.example.com:80 check resolvers mynameservers init-addr last,libc,none

In this example:

  • By setting the first method to last, the process first tries to get the IP address from a state file (set with the server-state-file directive).
  • Next, it tries to resolve the DNS name by using its internal libc resolver.
  • If that fails, it moves on to the none method, which indicates that the load balancer can start without resolving the name with the expectation that the name will be resolved later at runtime.

You can also set a hardcoded IP address as a fallback:

haproxy
backend webservers
server s1 hostname1.example.com:80 check resolvers mynameservers init-addr last,libc,192.168.1.25
haproxy
backend webservers
server s1 hostname1.example.com:80 check resolvers mynameservers init-addr last,libc,192.168.1.25

DNS service discovery Jump to heading

You can populate server addresses and ports in your configuration by querying your DNS server.

Service discovery with A records Jump to heading

DNS A records map hostnames to IP addresses. You can configure the load balancer to query for these records and populate server lines from the information that returns.

DNS A records

To configure service discovery:

  1. Update your DNS nameserver to resolve a hostname, such as myservice.example.local, to one or more IP addresses using A records.

    You can then query the nameserver directly, for example with the dig tool, to ensure that it returns the correct records:

    nix
    dig @192.168.50.30 -p 53 A myservice.example.local
    nix
    dig @192.168.50.30 -p 53 A myservice.example.local
    output
    text
    ;; QUESTION SECTION:
    ;myservice.example.local. IN A
    ;; ANSWER SECTION:
    myservice.example.local. 90 IN A 192.168.50.31
    myservice.example.local. 90 IN A 192.168.50.32
    myservice.example.local. 90 IN A 192.168.50.33
    output
    text
    ;; QUESTION SECTION:
    ;myservice.example.local. IN A
    ;; ANSWER SECTION:
    myservice.example.local. 90 IN A 192.168.50.31
    myservice.example.local. 90 IN A 192.168.50.32
    myservice.example.local. 90 IN A 192.168.50.33

    If you configured multiple A records, multiple IP addresses should return for the same hostname.

  2. In your load balancer configuration, add a resolvers section.

    • Add one or more nameserver lines to specify the IP addresses and ports of your DNS nameservers.
    • Set the accepted_payload_size to 8192 to allow larger DNS payloads, which is required to receive more server IP addresses within a single DNS response.

    For example:

    haproxy
    resolvers mydns
    nameserver dns1 192.168.50.30:53
    accepted_payload_size 8192
    haproxy
    resolvers mydns
    nameserver dns1 192.168.50.30:53
    accepted_payload_size 8192
  3. Use a server-template in a backend to set the template for the server lines. When the load balancer queries your DNS servers, these will be populated with IP addresses.

    haproxy
    backend webservers
    balance roundrobin
    server-template web 5 myservice.example.local:80 check resolvers mydns init-addr none
    haproxy
    backend webservers
    balance roundrobin
    server-template web 5 myservice.example.local:80 check resolvers mydns init-addr none

    In this example, the server-template directive:

    • Adds the specified number of servers (5) to the backend.
    • Their names will have web as a prefix.
    • The hostname myservice.example.local is queried.
    • Port 80 is hardcoded.
    • The resolvers section mydns is specified.
    • The init-addr none argument means that the load balancer can initialize without having to resolve the IP addresses at startup. They can be resolved during runtime.
    How it works: Server templates

    Using DNS service discovery with server-template is equivalent to defining a backend that looks like this:

    haproxy
    backend webservers
    balance roundrobin
    server web1 192.168.50.31:80 check
    server web2 192.168.50.32:80 check
    server web3 192.168.50.33:80 check
    server web4 192.168.50.34:80 check disabled
    server web5 192.168.50.35:80 check disabled
    haproxy
    backend webservers
    balance roundrobin
    server web1 192.168.50.31:80 check
    server web2 192.168.50.32:80 check
    server web3 192.168.50.33:80 check
    server web4 192.168.50.34:80 check disabled
    server web5 192.168.50.35:80 check disabled

    When you add more DNS records to your nameserver, they will automatically go into the backend to fill in the web4 and web5 slots.

Service discovery with SRV records Jump to heading

DNS SRV records specify the host and port that a service listens on. You can configure the load balancer to query for these records and populate the IP addresses and ports of server lines in a backend section.

DNS A records

DNS SRV records are resources used to identify computers that host specific services. They are contained in the ANSWER section of DNS responses and have the following structure:

text
_service._proto.name. TTL class SRV priority weight port target
text
_service._proto.name. TTL class SRV priority weight port target

where:

  • _service is the standard network service name (taken from /etc/services) or a port number
  • _proto is the standard protocol name (tcp or udp)
  • name is the name of the service, i.e. the name used in the query
  • TTL is the validity period for the response (the load balancer ignores this field because it maintains its own expiry data defined in the configuration)
  • class is the DNS class (IN)
  • SRV is the DNS record type (SRV)
  • priority is the priority of the target host. Lower value = higher preference (the load balancer ignores this field but may use it later to indicate active / backup state)
  • weight is the relative weight in case of records with the same priority. Higher number = higher preference
  • port is the port where the service is configured
  • target is the hostname of the machine providing the service, ending in a dot

Configure service discovery Jump to heading

  1. Update your DNS nameserver to resolve a service name, such as myservice.example.local, to one or more hostnames and ports via SRV records. Those hostnames should resolve to IP addresses using A records.

    • Add DNS A records that resolve multiple hostnames, such as host1, host2 and host3, to different IP addresses.
    • Add the same number of SRV records that resolve a service name, such as _myservice._tcp.example.local, to the hostnames you defined and the port on the host where the service listens.

    You can query the nameserver directly with the dig tool to ensure that it returns the correct records.

    For example:

    nix
    dig @192.168.50.30 -p 53 SRV _myservice._tcp.example.local
    nix
    dig @192.168.50.30 -p 53 SRV _myservice._tcp.example.local
    output
    text
    ;; QUESTION SECTION:
    ;_myservice._tcp.example.local. IN
    ;; ANSWER SECTION:
    _myservice._tcp.example.local. 0 IN SRV 0 0 8080 host1.
    _myservice._tcp.example.local. 0 IN SRV 0 0 8081 host2.
    _myservice._tcp.example.local. 0 IN SRV 0 0 8082 h
    ;; ADDITIONAL SECTION:
    host1. 0 IN A 192.168.50.31
    host2. 0 IN A 192.168.50.32
    host3. 0 IN A 192.168.50.33
    output
    text
    ;; QUESTION SECTION:
    ;_myservice._tcp.example.local. IN
    ;; ANSWER SECTION:
    _myservice._tcp.example.local. 0 IN SRV 0 0 8080 host1.
    _myservice._tcp.example.local. 0 IN SRV 0 0 8081 host2.
    _myservice._tcp.example.local. 0 IN SRV 0 0 8082 h
    ;; ADDITIONAL SECTION:
    host1. 0 IN A 192.168.50.31
    host2. 0 IN A 192.168.50.32
    host3. 0 IN A 192.168.50.33
  2. Add a resolvers section in your configuration file to set the DNS nameservers to watch for changes.

    • Add one or more nameserver lines to specify the IP addresses and ports of your DNS nameservers.
    • Set the accepted_payload_size to 8192 to allow larger DNS payloads, which is required to receive more server IPs within a single DNS result.

    For example:

    haproxy
    resolvers mydns
    nameserver dns1 192.168.50.30:53
    accepted_payload_size 8192
    haproxy
    resolvers mydns
    nameserver dns1 192.168.50.30:53
    accepted_payload_size 8192
  3. Use a server-template in a backend to set the template for the server lines:

    haproxy
    backend webservers
    balance roundrobin
    server-template web 5 _myservice._tcp.example.local resolvers mydns check init-addr none
    haproxy
    backend webservers
    balance roundrobin
    server-template web 5 _myservice._tcp.example.local resolvers mydns check init-addr none

    In this example, the server-template directive:

    • Adds the specified number of servers (5) to the backend.
    • Appends web as a prefix to their names.
    • Queries the service name _myservice._tcp.example.local.
    • Have the SRV records fill in the ports.
    • Specifies the resolvers section mydns
    • The init-addr none argument means that the load balancer can initialize without having to resolve the IP addresses at startup. It can resolve them during runtime.
    How it works: Server templates

    This is equivalent to adding a backend that looks like this:

    haproxy
    backend webservers
    balance roundrobin
    server web1 192.168.50.31:8080 check
    server web2 192.168.50.32:8081 check
    server web3 192.168.50.33:8082 check
    server web4 192.168.50.34:80 check disabled
    server web5 192.168.50.35:80 check disabled
    haproxy
    backend webservers
    balance roundrobin
    server web1 192.168.50.31:8080 check
    server web2 192.168.50.32:8081 check
    server web3 192.168.50.33:8082 check
    server web4 192.168.50.34:80 check disabled
    server web5 192.168.50.35:80 check disabled

    When you add more records to your nameserver, they will automatically go into the backend to fill in the web4 and web5 slots.

See also Jump to heading

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