When using HAProxy (particularly version 1.5.8), you might encounter a common infrastructure headache: backend servers specified by hostnames get resolved only once during startup. This becomes problematic when third-party services change their IP addresses without notice - exactly the scenario described by our user who proxies requests to external services.
The default behavior creates a single point of failure in your infrastructure. If the backend server's IP changes due to:
- Cloud provider maintenance
- Auto-scaling events
- DNS failover mechanisms
- CDN IP rotations
Your HAProxy instance will continue sending traffic to the stale IP address until manually reloaded.
For newer HAProxy versions, the solution is straightforward:
backend external_services
server srv1 api.example.com:80 check resolvers mydns
resolvers mydns
nameserver dns1 8.8.8.8:53
hold valid 10s
For those stuck with older versions, we need to get creative. Here's a solution using a cron job:
#!/bin/bash
# /etc/cron.d/haproxy-dns-refresh
*/5 * * * * root current_ip=$(getent hosts api.example.com | awk '{ print $1 }') && sed -i "s/server srv1.*/server srv1 ${current_ip}:80/" /etc/haproxy/haproxy.cfg && service haproxy reload
Another approach uses template files and environment variables:
# haproxy-template.cfg
backend dynamic_backend
server srv1 ${BACKEND_IP}:80
# refresh.sh
export BACKEND_IP=$(dig +short api.example.com)
envsubst < haproxy-template.cfg > haproxy.cfg
haproxy -f haproxy.cfg -sf $(cat /var/run/haproxy.pid)
While these workarounds function, they introduce complexity. Modern HAProxy versions offer superior solutions:
- Built-in DNS resolution (1.6+)
- Server templates (1.8+)
- Dynamic server API (1.9+)
The upgrade path might ultimately be the most maintainable solution.
When working with HAProxy (particularly version 1.5.8), one frustrating limitation is its default behavior of resolving backend server hostnames only during startup. This becomes problematic when:
- Deploying with cloud providers that change IP addresses
- Using DNS-based load balancing
- Working with third-party services that rotate IPs
Unlike Nginx which allows DNS caching through variables, HAProxy traditionally maintains a static resolution. Here's what happens under the hood:
# Traditional HAProxy backend configuration
backend static_backend
server thirdparty example.com:80 check
# ^ Resolves only at startup
While HAProxy 1.5.8 doesn't have native DNS TTL support, these approaches work:
Option 1: Runtime DNS Resolution with resolvers
Available in HAProxy 1.6+, but can be backported to 1.5.8 with some tweaks:
resolvers mydns
nameserver dns1 8.8.8.8:53
hold valid 10s
backend dynamic_backend
server thirdparty example.com:80 check resolvers mydns resolve-prefer ipv4
Option 2: External DNS Watcher Script
Create a watchdog script that:
#!/bin/bash
while true; do
new_ip=$(dig +short example.com | head -1)
if [ "$new_ip" != "$current_ip" ]; then
echo "set server dynamic_backend/thirdparty addr $new_ip" | socat stdio /var/run/haproxy.sock
current_ip=$new_ip
fi
sleep 30
done
Option 3: Upgrade Path Considerations
For production environments, consider upgrading to modern HAProxy versions (2.0+) that include:
- Native DNS service discovery
- Runtime API for dynamic configuration
- Built-in health checks with DNS re-resolution
When implementing dynamic DNS:
# Always include:
timeout connect 5s
timeout server 30s
timeout client 30s
# For resolver configuration:
defaults
log global
mode http
timeout connect 5s
timeout client 30s
timeout server 30s
option dontlognull
Monitor your HAProxy stats page closely after implementation to verify proper DNS rotation.