You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Allow dynamic use-server rules in defaults sections (for backends created with add backend ... from) #3535
Allow use-server in a named defaults section, at least when the server name is a log-format expression, so that backends created at runtime with add backend <name> from <defaults> can pin a request to a server.
Today it is rejected. Reproduced with an unmodified 3.4.6 build, and the same check is still in master (3.5-dev8):
defaults tpl
mode http
balance roundrobin
timeout connect 5s
timeout client 30s
timeout server 30s
http-request set-timeout server 10s
use-server %[req.hdr(x-pin-server)] if { req.hdr(x-pin-server) -m found }
frontend fe
bind 127.0.0.1:18080
use_backend %[req.hdr(x-be)]
[ALERT] config : parsing [repro.cfg:8] : 'use-server' not allowed in 'defaults' section.
A runtime backend has no rules of its own and gets everything from the defaults it references, so there is currently no way to give it a use-server rule.
From a quick look at the code, a possible approach:
Accept use-server in defaults only with a dynamic (log-format) name. Static names are resolved to a server per proxy at config check time, which cannot be shared, while dynamic names are already looked up in s->be for each stream.
In process_server_rules(), evaluate px->defpx->server_rules before px->server_rules, as http_process_req_common() does for http-request rules.
Count server_rules as rules in proxy_ref_defaults(), so the existing restriction on sharing a defaults section with rules between frontends and backends applies.
Set AN_REQ_SRV_RULES on backends that reference such a defaults section.
What are you trying to do?
We create backends at runtime with add backend ... from <template> followed by add server, using one named defaults section per application type. All of our backends built from configuration files carry a header-based override that pins a request to one server for deployment tests:
use-server %[req.hdr(x-pin-server)] if { req.hdr(x-pin-server) -m found }
It is the only line of our backend template that cannot move to a defaults section. Backends created at runtime lose it until a reload rebuilds them from the configuration.
We also considered routing pinned requests to a separate backend holding only the target server, but it does not fit well:
Every server needs a twin backend, which roughly doubles the number of proxies, and creating one application backend at runtime becomes 1+N add backend/publish operations with no atomicity between them.
The twin servers need their own health checks, because track cannot reference a dynamic server ("unable to use ... for tracking as it is a dynamic server"). This doubles check traffic to the origins, and the two copies can briefly disagree on state.
Every runtime change (add/del server, weight, maint, drain) has to be applied to both copies.
maxconn, queues, idle connection pools and counters are per server object, so pinned traffic bypasses the main server's limits and does not reuse its connections.
use-server falls back to load balancing when the pinned server is down. A twin backend needs extra frontend rules (e.g. the srv_is_up converter) to do the same.
use-server only looks up servers of the backend already chosen by host/path routing. Building a backend name from a request header in the frontend has to be restricted carefully so that a client cannot reach another application's backend.
Output of haproxy -vv
HAProxy version 3.4.6-56332c5 2026/09/28 - https://haproxy.org/
Status: long-term supported branch - will stop receiving fixes around Q2 2031.
Known bugs: http://www.haproxy.org/bugs/bugs-3.4.6.html
Build options :
TARGET = linux-glibc
CC = cc
CFLAGS = -O2 -g -fwrapv -fvect-cost-model=very-cheap
OPTIONS =
DEBUG =
Feature list : -51DEGREES +ACCEPT4 +BACKTRACE -CLOSEFROM +CPU_AFFINITY +CRYPT_H -DEVICEATLAS +DL -ECH -ENGINE +EPOLL -EVPORTS +GETADDRINFO +HAVE_TCP_MD5SIG -KQUEUE +KTLS -LIBATOMIC +LIBCRYPT +LINUX_CAP +LINUX_SPLICE +LINUX_TPROXY -LUA -MATH -MEMORY_PROFILING +NETFILTER +NS -OBSOLETE_LINKER -OPENSSL -OPENSSL_AWSLC -OPENSSL_WOLFSSL -OT -PCRE -PCRE2 -PCRE2_JIT -PCRE_JIT +POLL +PRCTL -PROCCTL -PROMEX -PTHREAD_EMULATION -QUIC -QUIC_OPENSSL_COMPAT +RT +SHM_OPEN +SLZ -SSL -STATIC_PCRE -STATIC_PCRE2 +TFO +THREAD +THREAD_DUMP +TPROXY +TRACE -WURFL -ZLIB
Detected feature list : +HAVE_WORKING_TCP_MD5SIG
Default settings :
bufsize = 16384, maxrewrite = 1024, maxpollevents = 200
Built with multi-threading support (MAX_TGROUPS=32, MAX_THREADS=1024, default=8).
Built with network namespace support.
Built with libslz for stateless compression.
Compression algorithms supported : identity("identity"), deflate("deflate"), raw-deflate("deflate"), gzip("gzip")
Built with transparent proxy support using: IP_TRANSPARENT IPV6_TRANSPARENT IP_FREEBIND
Built without PCRE or PCRE2 support (using libc's regex instead)
Encrypted password support via crypt(3): yes
Built with gcc compiler version 11.5.0 20240719 (Red Hat 11.5.0-14)
Available polling systems :
epoll : pref=300, test result OK
poll : pref=200, test result OK
select : pref=150, test result OK
Total: 3 (3 usable), will use epoll.
Available multiplexer protocols :
(protocols marked as <default> cannot be specified using 'proto' keyword)
h2 : mode=HTTP side=FE|BE mux=H2 flags=HTX|HOL_RISK|NO_UPG
<default> : mode=HTTP side=FE|BE mux=H1 flags=HTX
h1 : mode=HTTP side=FE|BE mux=H1 flags=HTX|NO_UPG
fcgi : mode=HTTP side=BE mux=FCGI flags=HTX|HOL_RISK|NO_UPG
<default> : mode=SPOP side=BE mux=SPOP flags=HOL_RISK|NO_UPG
spop : mode=SPOP side=BE mux=SPOP flags=HOL_RISK|NO_UPG
<default> : mode=TCP side=FE|BE mux=PASS flags=
none : mode=TCP side=FE|BE mux=PASS flags=NO_UPG
Available services : none
Available filters :
[BWLIM] bwlim-in
[BWLIM] bwlim-out
[CACHE] cache
[COMP] comp-req
[COMP] comp-res
[COMP] compression
[FCGI] fcgi-app
[SPOE] spoe
[TRACE] trace
Activity