Blue-green cutovers become risky when HAProxy can reach both application versions but the release operator has no single traffic switch or rollback proof. A map-backed route gives the release window one active backend name, so normal requests stay on blue until the runtime map is moved to green.
HAProxy map files can return the backend name used by use_backend, and the Runtime API can change one map entry in running memory with set map. Health checks on both backend pools keep the switch tied to application readiness instead of only proving that a TCP port accepts connections.
Runtime API changes do not update the map file on disk, so persistence is a separate action after smoke tests pass. Keep the disk map pointed at blue during the first green check when a reload-based rollback is acceptable, then write green to disk only after the release owner accepts the cutover.
$ sudo apt install socat
$ sudo install -d -m 0755 /etc/haproxy/maps
active backend_blue
The key can be any fixed value. The backend name on the right side is the part HAProxy will route to.
global stats socket /run/haproxy/admin.sock mode 660 level admin defaults mode http timeout connect 5s timeout client 30s timeout server 30s default-server inter 5s fall 3 rise 2 frontend fe_http bind :80 use_backend %[str(active),map(/etc/haproxy/maps/bluegreen.map,backend_blue)] backend backend_blue option httpchk GET /healthz http-check expect status 200 server blue1 10.10.10.11:8080 check server blue2 10.10.10.12:8080 check backend backend_green option httpchk GET /healthz http-check expect status 200 server green1 10.10.20.11:8080 check server green2 10.10.20.12:8080 check
Replace the backend addresses, ports, and health URI with the real application endpoints. The runtime socket uses level admin because set map changes live routing state.
$ sudo haproxy -c -V -f /etc/haproxy/haproxy.cfg Configuration file is valid
$ sudo systemctl reload haproxy
Related: How to reload HAProxy gracefully
$ echo "show map /etc/haproxy/maps/bluegreen.map" | sudo socat stdio unix-connect:/run/haproxy/admin.sock 0x55d0b5e8d4b0 active backend_blue
$ echo "show stat backend_green 4 -1" | sudo socat stdio unix-connect:/run/haproxy/admin.sock # pxname,svname,qcur,qmax,scur,smax,slim,stot,bin,bout,dreq,dresp,ereq,econ,eresp,wretr,wredis,status,weight,act,bck,chkfail,chkdown,lastchg,downtime,qlimit,pid,iid,sid,throttle,lbtot,tracked,type,rate,rate_lim,rate_max,check_status,check_code,check_duration ##### snipped ##### backend_green,green1,0,0,0,0,,0,0,0,,0,,0,0,0,0,UP,1,1,0,0,0,2,0,,1,4,1,,0,,2,0,,0,L7OK,200,0 backend_green,green2,0,0,0,0,,0,0,0,,0,,0,0,0,0,UP,1,1,0,0,0,2,0,,1,4,2,,0,,2,0,,0,L7OK,200,0 ##### snipped #####
Do not cut over while a green server row is DOWN, MAINT, DRAIN, or still waiting for the required rise count.
$ curl http://www.example.com/release version=blue
$ echo "set map /etc/haproxy/maps/bluegreen.map active backend_green" | sudo socat stdio unix-connect:/run/haproxy/admin.sock
A successful set map command can return no text. The next step checks the runtime state instead of relying on command output.
$ echo "show map /etc/haproxy/maps/bluegreen.map" | sudo socat stdio unix-connect:/run/haproxy/admin.sock 0x55d0b5e8d4b0 active backend_green
$ curl http://www.example.com/release version=green
active backend_green
The Runtime API update is in memory only. A reload or restart will read this file again, so leaving it on backend_blue turns the next reload into a rollback.
$ echo "set map /etc/haproxy/maps/bluegreen.map active backend_blue" | sudo socat stdio unix-connect:/run/haproxy/admin.sock
$ curl http://www.example.com/release version=blue
active backend_blue