HAProxy Dynamic Socket: Runtime Backend Management via Stats Socket
HAProxy Dynamic Socket: Runtime Backend Management via Stats Socket
haproxy-dynamic-socket provides shell scripts for dynamically managing HAProxy configuration at runtime through the stats socket — adding/removing servers, draining backends, and changing weights without reloading HAProxy.
HAProxy Stats Socket
HAProxy exposes a Unix socket (or TCP socket) for runtime management. Commands sent to it take effect immediately without a reload.
Enable it in haproxy.cfg:
global
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
stats timeout 30sCore Interface
All interaction goes through socat (or nc):
haproxy_cmd() {
echo "$1" | socat stdio /run/haproxy/admin.sock
}Server Management Scripts
Add a Server to a Backend
#!/bin/bash
# add-server.sh <backend> <name> <host:port>
BACKEND="$1"
SERVER_NAME="$2"
SERVER_ADDR="$3"
if [[ -z "$BACKEND" || -z "$SERVER_NAME" || -z "$SERVER_ADDR" ]]; then
echo "Usage: $0 <backend> <name> <host:port>"
exit 1
fi
echo "add server ${BACKEND}/${SERVER_NAME} ${SERVER_ADDR}" \
| socat stdio /run/haproxy/admin.sock
echo "enable server ${BACKEND}/${SERVER_NAME}" \
| socat stdio /run/haproxy/admin.sock
echo "Server ${SERVER_NAME} added to backend ${BACKEND}"Drain and Remove a Server
#!/bin/bash
# drain-server.sh <backend> <name>
BACKEND="$1"
SERVER_NAME="$2"
DRAIN_WAIT="${3:-30}"
# Set to drain mode — no new connections
echo "set server ${BACKEND}/${SERVER_NAME} state drain" \
| socat stdio /run/haproxy/admin.sock
echo "Draining ${SERVER_NAME} (waiting ${DRAIN_WAIT}s)..."
sleep "$DRAIN_WAIT"
# Check current sessions
SESSIONS=$(echo "show servers conn ${BACKEND}" \
| socat stdio /run/haproxy/admin.sock \
| awk -v srv="${SERVER_NAME}" '$1==srv {print $NF}')
if [[ "${SESSIONS:-0}" -gt 0 ]]; then
echo "Warning: ${SESSIONS} sessions still active on ${SERVER_NAME}"
fi
# Remove the server
echo "del server ${BACKEND}/${SERVER_NAME}" \
| socat stdio /run/haproxy/admin.sock
echo "Server ${SERVER_NAME} removed from backend ${BACKEND}"Adjust Server Weight
#!/bin/bash
# set-weight.sh <backend> <name> <weight>
BACKEND="$1"
SERVER_NAME="$2"
WEIGHT="$3"
echo "set server ${BACKEND}/${SERVER_NAME} weight ${WEIGHT}" \
| socat stdio /run/haproxy/admin.sockStatus and Monitoring
#!/bin/bash
# show-backend.sh <backend>
BACKEND="${1:-}"
if [[ -n "$BACKEND" ]]; then
echo "show servers state ${BACKEND}" | socat stdio /run/haproxy/admin.sock
else
echo "show stat" | socat stdio /run/haproxy/admin.sock | column -t -s ','
fiHealth Check Override
Temporarily disable/enable health checks without removing a server:
# Disable health checks (manual state management)
echo "disable health ${BACKEND}/${SERVER_NAME}" | socat stdio /run/haproxy/admin.sock
# Force server into UP state regardless of health check
echo "set server ${BACKEND}/${SERVER_NAME} health up" | socat stdio /run/haproxy/admin.sock
# Re-enable automatic health checks
echo "enable health ${BACKEND}/${SERVER_NAME}" | socat stdio /run/haproxy/admin.sockUse Case: Zero-Downtime Deployment
#!/bin/bash
# rolling-deploy.sh — replace servers one at a time
BACKEND="web_backend"
NEW_SERVERS=("web3:8080" "web4:8080")
OLD_SERVERS=("web1" "web2")
for i in "${!OLD_SERVERS[@]}"; do
OLD="${OLD_SERVERS[$i]}"
NEW_NAME="new_web$((i+1))"
NEW_ADDR="${NEW_SERVERS[$i]}"
# Add new server
bash add-server.sh "$BACKEND" "$NEW_NAME" "$NEW_ADDR"
# Drain and remove old
bash drain-server.sh "$BACKEND" "$OLD" 60
echo "Rotated $OLD → $NEW_NAME"
doneConclusion
HAProxy’s stats socket provides a powerful, zero-downtime management interface. These scripts wrap the raw socket commands into reusable tools for common operations like rolling deployments, weight adjustments, and backend health overrides — all without touching HAProxy’s config file or triggering a reload.
Source: GitHub