本文档涵盖了上述版本中实现的配置语言。它不提供任何提示、示例或建议。有关此类文档,请参阅参考手册或架构手册。下面的摘要旨在帮助您按名称搜索章节并在文档中导航。致文档贡献者:本文档每行格式化为 80 列,使用偶数个空格进行缩进,不使用制表符。请严格遵守这些规则,以便于在任何地方打印。如果某行需要逐字打印且不适合,请在每行末尾加上反斜杠 ('\') 并在下一行继续,缩进两个字符。有时,在所有输出行(日志、控制台输出)前加上 3 个闭合尖括号 ('>>>') 也很有用,以便在可能变得模糊时帮助区分输入和输出。如果添加章节,请更新下面的摘要以便于搜索。| 1. | 关于 HTTP 的快速提醒 | |
| 1.1. | ||
| 1.2. | ||
| 1.2.1. | ||
| 1.2.2. | ||
| 1.3. | ||
| 1.3.1. | ||
| 1.3.2. | ||
2. |
配置 HAProxy | |
| 2.1. | ||
| 2.2. | ||
| 2.3. | ||
| 2.4. | ||
| 2.5. | ||
3. |
全局参数 | |
| 3.1. | ||
| 3.2. | ||
| 3.3. | ||
| 3.4. | ||
| 3.5. | ||
| 3.6. | ||
4. |
代理 | |
| 4.1. | ||
| 4.2. | ||
5. |
绑定和服务端选项 | |
| 5.1. | ||
| 5.2. | ||
| 5.3. | ||
| 5.3.1. | ||
| 5.3.2. | ||
6. |
HTTP 标头操作 | |
7. |
使用 ACL 和获取样本 | |
| 7.1. | ||
| 7.1.1. | ||
| 7.1.2. | ||
| 7.1.3. | ||
| 7.1.4. | ||
| 7.1.5. | ||
| 7.1.6. | ||
| 7.2. | ||
| 7.3. | ||
| 7.3.1. | ||
| 7.3.2. | ||
| 7.3.3. | ||
| 7.3.4. | ||
| 7.3.5. | ||
| 7.3.6. | ||
| 7.4. | ||
8. |
日志 | |
| 8.1. | ||
| 8.2. | ||
| 8.2.1. | ||
| 8.2.2. | ||
| 8.2.3. | ||
| 8.2.4. | ||
| 8.2.5. | ||
| 8.3. | ||
| 8.3.1. | ||
| 8.3.2. | ||
| 8.3.3. | ||
| 8.3.4. | ||
| 8.4. | ||
| 8.5. | ||
| 8.6. | ||
| 8.7. | ||
| 8.8. | ||
| 8.9. |
当 haproxy 在 HTTP 模式下运行时,请求和响应都会被完全分析和索引,因此可以基于内容中找到的几乎任何东西建立匹配标准。然而,重要的是要了解 HTTP 请求和响应是如何构成的,以及 HAProxy 是如何分解它们的。这样,编写正确的规则和调试现有配置就会变得更容易。
HTTP 协议是事务驱动的。这意味着每个请求都将导致一个且仅一个响应。传统上,客户端与服务器建立 TCP 连接,客户端在连接上发送请求,服务器响应后连接关闭。新的请求将涉及新的连接:[CON1] [REQ1] ... [RESP1] [CLO1] [CON2] [REQ2] ... [RESP2] [CLO2] ... 在这种模式下,称为“HTTP 关闭”模式,HTTP 事务的数量与连接建立的数量相同。由于连接在响应后由服务器关闭,客户端不需要知道内容长度。由于协议的事务性质,可以对其进行改进,以避免在两个后续事务之间关闭连接。然而,在这种模式下,服务器必须为每个响应指示内容长度,以便客户端不会无限期等待。为此,使用了一个特殊的标头:“Content-length”。此模式称为“keep-alive”模式:[CON] [REQ1] ... [RESP1] [REQ2] ... [RESP2] [CLO] ... 其优点是事务之间的延迟减少,并且服务器端所需的处理能力更少。它通常优于关闭模式,但并非总是如此,因为客户端通常将其并发连接限制在一个较小的值。通信的最后一个改进是流水线模式。它仍然使用 keep-alive,但客户端不会等待第一个响应就发送第二个请求。这对于获取构成页面的大量图像很有用:[CON] [REQ1] [REQ2] ... [RESP1] [RESP2] [CLO] ... 这显然对性能有巨大的好处,因为后续请求之间的网络延迟被消除了。许多 HTTP 代理不正确地支持流水线,因为在 HTTP 中没有办法将响应与相应的请求关联起来。因此,服务器必须按照接收请求的完全相同的顺序进行回复。默认情况下,HAProxy 在持久连接方面以 keep-alive 模式运行:对于每个连接,它处理每个请求和响应,并在响应结束和新请求开始之间将连接在两端保持空闲状态。HAProxy 支持 5 种连接模式:- keep alive:处理所有请求和响应(默认)- tunnel:只处理第一个请求和响应,其余所有内容都直接转发,不进行分析。- passive close:隧道模式,但在两个方向上都添加“Connection: close”。- server close:面向服务器的连接在响应后关闭。- forced close:响应结束后主动关闭连接。
首先,让我们考虑这个 HTTP 请求: 行号 内容 1 GET /serv/login.php?lang=en&profile=2 HTTP/1.1 2 Host: www.mydomain.com 3 User-agent: my small browser 4 Accept: image/jpeg, image/gif 5 Accept: image/png
第 1 行是“请求行”。它总是由 3 个字段组成:- 一个方法 (METHOD):GET - 一个 URI:/serv/login.php?lang=en&profile=2 - 一个版本标签 (version tag):HTTP/1.1 所有这些都由标准所谓的 LWS(线性空白)分隔,通常是空格,但也可以是制表符或换行符/回车符后跟空格/制表符。方法本身不能包含任何冒号(':'),并且仅限于字母。所有这些不同的组合使得 HAProxy 最好自己进行拆分,而不是让用户编写复杂或不准确的正则表达式。URI 本身可以有几种形式:- “相对 URI” (relative URI):/serv/login.php?lang=en&profile=2 这是一个没有主机部分的完整 URL。这通常是服务器、反向代理和透明代理接收到的内容。- “绝对 URI” (absolute URI),也称为“URL”:http://192.168.0.12:8080/serv/login.php?lang=en&profile=2 它由一个“方案”(协议名称后跟 '://')、一个主机名或地址、可选的冒号(':')后跟一个端口号,然后是一个从地址部分后的第一个斜杠('/')开始的相对 URI 组成。这通常是代理接收到的内容,但支持 HTTP/1.1 的服务器也必须接受这种形式。- 一个星号 ('*'):这种形式只在与 OPTIONS 方法关联时被接受,并且是不可转发的。它用于查询下一跳的功能。- 一个地址:端口组合:192.168.0.12:80 这与 CONNECT 方法一起使用,该方法用于通过 HTTP 代理建立 TCP 隧道,通常用于 HTTPS,但有时也用于其他协议。在相对 URI 中,标识了两个子部分。问号之前的部分称为“路径”。它通常是服务器上静态对象的相对路径。问号之后的部分称为“查询字符串”。它主要用于发送给动态脚本的 GET 请求,并且非常特定于所使用的语言、框架或应用程序。标头从第二行开始。它们由行首的名称和紧随其后的冒号(':')组成。传统上,冒号后会添加一个 LWS(线性空白),但这不是必需的。然后是值。多个相同的标头可以合并到一行中,用逗号分隔值,前提是它们的顺序得到尊重。这在“Cookie:”字段中很常见。如果后续行以 LWS 开头,则一个标头可以跨越多行。在 1.2 的示例中,第 4 行和第 5 行总共为“Accept:”标头定义了 3 个值。与一个常见的误解相反,标头名称不区分大小写,如果它们引用其他标头名称(例如“Connection:”标头),其值也不区分大小写。标头的结束由第一个空行表示。人们常说这是一个双换行符,这并不准确,即使双换行符是空行的一种有效形式。幸运的是,HAProxy 在索引标头、检查值和计数时会处理所有这些复杂的组合,因此无需担心它们的书写方式,但重要的是不要因为一个应用程序做了不寻常但有效的操作而指责它有错误。重要说明:根据 RFC7231 的建议,HAProxy 通过将标头中间的换行符替换为 LWS 来规范化标头,以便连接多行标头。这对于正确的分析是必要的,并有助于功能较差的 HTTP 解析器正确工作,而不会被这种复杂的结构所迷惑。
HTTP 响应与 HTTP 请求非常相似。两者都称为 HTTP 消息。让我们看一个 HTTP 响应:行号 内容 1 HTTP/1.1 200 OK 2 Content-length: 350 3 Content-Type: text/html 作为特例,HTTP 支持所谓的“信息性响应”,状态码为 1xx。这些消息的特殊之处在于它们不传达响应的任何部分,它们只是用作一种信号消息,例如请求客户端继续发送其请求。在状态 100 响应的情况下,请求的信息将由信息性响应之后的下一个非 100 响应消息携带。这意味着可以向单个请求发送多个响应,并且这仅在启用 keep-alive 时有效(1xx 消息仅限于 HTTP/1.1)。HAProxy 处理这些消息,并能够正确地转发和跳过它们,只处理下一个非 100 响应。因此,除非明确说明,否则这些消息既不被记录也不被转换。状态 101 消息表示协议正在通过同一连接更改,并且 haproxy 必须切换到隧道模式,就像发生了 CONNECT 一样。然后 Upgrade 标头将包含有关连接正在切换到的协议类型的附加信息。
第 1 行是“响应行”。它总是由 3 个字段组成:- 一个版本标签:HTTP/1.1 - 一个状态码:200 - 一个原因:OK 状态码总是 3 位数。第一位数字表示一个总体状态:- 1xx = 要跳过的信息性消息(例如:100, 101)- 2xx = OK,内容紧随其后(例如:200, 206)- 3xx = OK,没有内容(例如:302, 304)- 4xx = 由客户端引起的错误(例如:401, 403, 404)- 5xx = 由服务器引起的错误(例如:500, 502, 503)请参阅 RFC7231 以了解所有这些代码的详细含义。“原因”字段只是一个提示,但不会被客户端解析。那里可以找到任何内容,但通常的做法是尊重公认的消息。它可以由一个或多个单词组成,例如“OK”、“Found”或“Authentication Required”。Haproxy 可能会自行发出以下状态码:代码 何时/原因 200 访问统计页面,以及回复监控请求时 301 执行重定向时,取决于配置的代码 302 执行重定向时,取决于配置的代码 303 执行重定向时,取决于配置的代码 307 执行重定向时,取决于配置的代码 308 执行重定向时,取决于配置的代码 400 请求无效或过大 401 执行操作需要身份验证时(访问统计页面时) 403 当请求被“block” ACL 或“reqdeny”过滤器禁止时 408 当请求在完成前超时时 500 当 haproxy 遇到不可恢复的内部错误时,例如内存分配失败,这应该永远不会发生 502 当服务器返回空、无效或不完整的响应时,或当“rspdeny”过滤器阻止响应时。 503 当没有服务器可用于处理请求时,或响应匹配“monitor fail”条件的监控请求时 504 当响应在服务器响应前超时时 上述 4xx 和 5xx 错误代码可以自定义(请参阅第 4.2 节中的“errorloc”)。
响应头的处理方式与请求头完全相同,因此 HAProxy 对两者使用相同的解析函数。更多详情请参考 1.2.2 段。
HAProxy 的配置过程涉及 3 个主要的参数来源: - 命令行参数,它们总是优先 - “global”部分,设置进程范围的参数 - 代理部分,可以采用“defaults”、“listen”、“frontend”和“backend”的形式。配置文件语法由以本手册中引用的关键字开头的行组成,后面可以选择性地跟一个或多个由空格分隔的参数。
HAProxy 的配置引入了一个类似于许多编程语言的引用和转义系统。配置文件支持 3 种类型:使用反斜杠转义、使用双引号的弱引用以及使用单引号的强引用。如果字符串中必须输入空格,则必须通过在其前面加上反斜杠 ('\') 或将其引起来进行转义。反斜杠也必须通过双写或强引用进行转义。转义是通过在特殊字符前加上反斜杠 ('\') 来实现的:\ 用于标记空格并将其与分隔符区分开来 \# 用于标记井号并将其与注释区分开来 \\ 用于使用反斜杠 \' 用于使用单引号并将其与强引用区分开来 \" 用于使用双引号并将其与弱引用区分开来 弱引用是通过使用双引号 ("") 实现的。弱引用阻止了以下内容的解释:空格作为参数分隔符 ' 单引号作为强引用分隔符 # 井号作为注释开始 弱引用允许解释变量,如果要在双引号字符串中使用未解释的美元符号,应使用反斜杠("\$")进行转义,它在弱引用之外不起作用。弱引用不阻止转义和特殊字符的解释。强引用是通过使用单引号 ('') 实现的。在单引号内,任何内容都不会被解释,这是引用正则表达式的有效方式。被引用和转义的字符串在内存中被其解释后的等效内容替换,这允许您执行连接操作。# 以下是等价的: log-format %{+Q}o\ %t\ %s\ %{-Q}r log-format "%{+Q}o %t %s %{-Q}r" log-format '%{+Q}o %t %s %{-Q}r' log-format "%{+Q}o %t"' %s %{-Q}r' log-format "%{+Q}o %t"' %s'\ %{-Q}r # 以下是等价的: reqrep "^([^\ :]*)\ /static/(.*)" \1\ /\2 reqrep "^([^ :]*)\ /static/(.*)" '\1 /\2' reqrep "^([^ :]*)\ /static/(.*)" "\1 /\2" reqrep "^([^ :]*)\ /static/(.*)" "\1\ /\2"
HAProxy 的配置支持环境变量。这些变量仅在双引号内被解释。变量在配置解析期间展开。变量名前必须加上美元符号("$"),并可选地用大括号("{}")括起来,类似于 Bourne shell 中的做法。变量名可以包含字母数字字符或下划线("_"),但不应以数字开头。bind "fd@${FD_APP1}" log "${LOCAL_SYSLOG}:514" local0 notice # 发送到本地服务器 user "$HAPROXY_USER"
一些参数涉及表示时间的值,例如超时。这些值通常以毫秒表示(除非另有明确说明),但也可以通过在数值后附加单位来以任何其他单位表示。考虑这一点很重要,因为每个关键字都不会重复说明。支持的单位有:- us:微秒。1 微秒 = 1/1000000 秒 - ms:毫秒。1 毫秒 = 1/1000 秒。这是默认单位。 - s:秒。1s = 1000ms - m:分钟。1m = 60s = 60000ms - h:小时。1h = 60m = 3600s = 3600000ms - d:天。1d = 24h = 1440m = 86400s = 86400000ms
# 一个简单的 HTTP 代理配置,在所有接口的 80 端口上监听,# 并将请求转发到名为 "servers" 的单个后端,该后端有一个名为 "server1" 的服务器,# 监听于 127.0.0.1:8000 global daemon maxconn 256 defaults mode http timeout connect 5000ms timeout client 50000ms timeout server 50000ms frontend http-in bind *:80 default_backend servers backend servers server server1 127.0.0.1:8000 maxconn 32 # 使用单个 listen 块定义的相同配置。更短但表达力较差,尤其是在 HTTP 模式下。 global daemon maxconn 256 defaults mode http timeout connect 5000ms timeout client 50000ms timeout server 50000ms listen http-in bind *:80 server server1 127.0.0.1:8000 maxconn 32 假设 haproxy 在 $PATH 中,请在 shell 中使用以下命令测试这些配置:$ sudo haproxy -f configuration.conf -c
"global" 部分的参数是进程范围的,并且通常是特定于操作系统的。它们通常一次性设置好,一旦正确就无需更改。其中一些有等效的命令行选项。在 "global" 部分支持以下关键字:* 进程管理与安全 - ca-base - chroot - crt-base - cpu-map - daemon - description - deviceatlas-json-file - deviceatlas-log-level - deviceatlas-separator - deviceatlas-properties-cookie - external-check - gid - group - log - log-tag - log-send-hostname - lua-load - nbproc - node - pidfile - uid - ulimit-n - user - stats - ssl-default-bind-ciphers - ssl-default-bind-options - ssl-default-server-ciphers - ssl-default-server-options - ssl-dh-param-file - ssl-server-verify - unix-bind - 51degrees-data-file - 51degrees-property-name-list - 51degrees-property-separator - 51degrees-cache-size * 性能调优 - max-spread-checks - maxconn - maxconnrate - maxcomprate - maxcompcpuusage - maxpipes - maxsessrate - maxsslconn - maxsslrate - maxzlibmem - noepoll - nokqueue - nopoll - nosplice - nogetaddrinfo - noreuseport - spread-checks - server-state-base - server-state-file - tune.buffers.limit - tune.buffers.reserve - tune.bufsize - tune.chksize - tune.comp.maxlevel - tune.http.cookielen - tune.http.maxhdr - tune.idletimer - tune.lua.forced-yield - tune.lua.maxmem - tune.lua.session-timeout - tune.lua.task-timeout - tune.lua.service-timeout - tune.maxaccept - tune.maxpollevents - tune.maxrewrite - tune.pattern.cache-size - tune.pipesize - tune.rcvbuf.client - tune.rcvbuf.server - tune.sndbuf.client - tune.sndbuf.server - tune.ssl.cachesize - tune.ssl.lifetime - tune.ssl.force-private-cache - tune.ssl.maxrecord - tune.ssl.default-dh-param - tune.ssl.ssl-ctx-cache-size - tune.vars.global-max-size - tune.vars.reqres-max-size - tune.vars.sess-max-size - tune.vars.txn-max-size - tune.zlib.memlevel - tune.zlib.windowsize * 调试 - debug - quiet
当使用相对路径与 "ca-file" 或 "crl-file" 指令时,分配一个用于获取 SSL CA 证书和 CRL 的默认目录。在 "ca-file" 和 "crl-file" 中指定的绝对位置优先,并忽略 "ca-base"。
在降低权限之前,将当前目录更改为 <jail dir> 并在那里执行 chroot()。这在未知漏洞被利用的情况下提高了安全级别,因为它会使攻击者很难利用系统。这仅在进程以超级用户权限启动时有效。确保 <jail_dir> 为空且对任何人都是不可写的,这很重要。
在 Linux 2.6 及更高版本上,可以将进程绑定到特定的 CPU 集。这意味着该进程将永远不会在其他 CPU 上运行。“cpu-map” 指令为进程集指定 CPU 集。第一个参数是要绑定的进程号。此进程号必须在 1 到 32 或 64 之间,具体取决于机器的字长,任何高于 nbproc 的进程 ID 都将被忽略。可以使用 "all" 一次性指定所有进程,使用 "odd" 仅指定奇数进程,或使用 "even" 指定偶数进程,就像使用 "bind-process" 指令一样。第二个及后续参数是 CPU 集。每个 CPU 集要么是 0 到 31 或 63 之间的唯一数字,要么是由短划线 ('-') 分隔的两个此类数字的范围。可以指定多个 CPU 号码或范围,进程将被允许绑定到所有这些 CPU 上。显然,可以指定多个 "cpu-map" 指令。每个 "cpu-map" 指令在重叠时将替换之前的指令。
当使用 "crtfile" 指令的相对路径时,分配一个用于获取 SSL 证书的默认目录。"crtfile" 后面指定的绝对位置优先,并忽略 "crt-base"。
使进程 fork 到后台运行。这是推荐的操作模式。它等同于命令行参数 "-D"。它可以通过命令行参数 "-db" 禁用。
设置要由 API 加载的 DeviceAtlas JSON 数据文件的路径。该路径必须是一个有效的 JSON 数据文件,并且 Haproxy 进程可以访问。
设置 API 返回的信息级别。此指令是可选的,如果未设置,则默认为 0。
设置 API 属性结果的字符分隔符。此指令是可选的,如果未设置,则默认为 |。
设置用于检测请求期间是否使用了 DeviceAtlas 客户端组件的客户端 cookie 名称。此指令是可选的,如果未设置,则默认为 DAPROPS。
允许使用外部代理执行健康检查。作为安全预防措施,此功能默认禁用。请参阅 "option external-check"。
将进程的组 ID 更改为 <number>。建议该组 ID 专用于 HAProxy 或一小组类似的守护进程。HAProxy 必须以属于该组的用户或以超级用户权限启动。请注意,如果 haproxy 从具有附加组的用户启动,它只有在以超级用户权限启动时才能放弃这些组。另请参阅 "group" 和 "uid"。
与 "gid" 类似,但使用 /etc/group 中组名 <group name> 的 GID。另请参阅 "gid" 和 "user"。
添加一个全局 syslog 服务器。可以定义多个全局服务器。它们将接收启动和退出的日志,以及所有配置了 "log global" 的代理的日志。<address> 可以是以下之一: - 一个 IPv4 地址,后面可选地跟一个冒号和一个 UDP 端口。如果未指定端口,则默认使用 514(标准 syslog 端口)。 - 一个 IPv6 地址,后面跟一个冒号和可选的 UDP 端口。如果未指定端口,则默认使用 514(标准 syslog 端口)。 - 一个指向 UNIX 域套接字的文件系统路径,同时要考虑 chroot 的情况(确保路径在 chroot 内可访问)和 uid/gid(确保路径具有适当的写权限)。您可能希望在地址参数中引用一些环境变量,请参阅关于环境变量的 第 2.3 节。<length> 是可选的最大行长度。大于此值的日志行在发送前将被截断。原因是不同的 syslog 服务器对日志行长度的处理方式不同。所有服务器都支持默认值 1024,但一些服务器会简单地丢弃更长的行,而另一些则会记录它们。如果服务器支持长行,那么在此处设置此值以避免截断长行可能是有意义的。类似地,如果服务器丢弃长行,最好在发送前截断它们。可接受的值为 80 到 65535(含)。对于所有标准用法,默认值 1024 通常是合适的。某些特定情况下的长捕获或 JSON 格式的日志可能需要更大的值。<format> 是生成 syslog 消息时使用的日志格式。它可以是以下之一:rfc3164 RFC3164 syslog 消息格式。这是默认值。(https://tools.ietf.org/html/rfc3164) rfc5424 RFC5424 syslog 消息格式。(https://tools.ietf.org/html/rfc5424) <facility> 必须是 24 个标准 syslog 设施之一:kern user mail daemon auth syslog lpr news uucp cron auth2 ftp ntp audit alert cron2 local0 local1 local2 local3 local4 local5 local6 local7 可以指定一个可选的级别来过滤传出的消息。默认情况下,所有消息都会被发送。如果指定了最高级别,则只有严重性至少与此级别一样重要的消息才会被发送。可以指定一个可选的最低级别。如果设置了它,那么比这个级别更严重级别发出的日志将被限制到这个级别。这用于避免在某些默认 syslog 配置中在所有终端上发送 "emerg" 消息。已知的八个级别是:emerg alert crit err warning notice info debug
设置 syslog 报头中的 hostname 字段。如果设置了可选的 "string" 参数,则报头将设置为该字符串内容,否则使用系统的主机名。通常在不通过中间 syslog 服务器中继日志或仅为自定义日志中打印的主机名时使用。
将 syslog 报头中的 tag 字段设置为此字符串。它默认为从命令行启动的程序名,通常是 "haproxy"。有时,区分同一主机上运行的多个进程会很有用。另请参阅每个代理的 "log-tag" 指令。此全局指令加载并执行一个 Lua 文件。此指令可以多次使用。
在进入守护进程模式时创建 <number> 个进程。这需要 "daemon" 模式。默认情况下,只创建一个进程,这是推荐的操作模式。对于每个进程文件描述符数量受限的系统,可能需要 fork 多个守护进程。使用多个进程更难调试,强烈不推荐。另请参阅 "daemon"。
将所有守护进程的 pid 写入文件 <pidfile>。此选项等同于 "-p" 命令行参数。该文件必须对启动进程的用户可访问。另请参阅 "daemon"。
将统计套接字限制在一组特定的进程号上。默认情况下,统计套接字绑定到所有进程,当 nbproc 大于 1 时会发出警告,因为连接时无法选择目标进程。但是,通过使用此设置,可以将统计套接字固定到一组特定的进程,通常是第一个进程。无论使用多少个进程,使用此设置时警告将自动禁用。最大进程 ID 取决于机器的字长(32 位或 64 位)。更好的选择是使用 "stats socket" 行的 "process" 设置来强制指定每行的进程。
指定目录前缀,该前缀将附加在所有不以“/”开头的服务器状态文件名前面。另请参阅 "server-state-file"、"load-server-state-from-file" 和 "server-state-file-name"。
指定包含服务器状态的文件路径。如果路径以斜杠('/')开头,则视为绝对路径,否则视为相对于使用 "server-state-base" 指定的目录(如果已设置)或当前目录。在重新加载 HAProxy 之前,可以使用统计命令 "show servers state" 保存服务器的当前状态。该命令的输出必须写入 <file> 指向的文件中。启动时,在处理流量之前,HAProxy 将读取、加载并应用文件中找到且在其当前运行配置中可用的每个服务器的状态。另请参阅 "server-state-base" 和 "show servers state"、"load-server-state-from-file" 和 "server-state-file-name"。
此设置仅在编译时支持 OpenSSL 时可用。它为所有未明确定义密码算法列表的 "bind" 行设置默认字符串,该字符串描述在 SSL/TLS 握手期间协商的密码算法列表(“密码套件”)。该字符串的格式在 OpenSSL 手册页的 "man 1 ciphers" 中定义,例如可以是 "AES:ALL:!aNULL:!eNULL:+RC4:@STRENGTH"(不含引号)。请查看 "bind" 关键字以获取更多信息。
此设置仅在编译时支持 OpenSSL 时可用。它为所有 "bind" 行设置强制使用的默认 ssl-options。请查看 "bind" 关键字以了解可用选项。
global ssl-default-bind-options no-sslv3 no-tls-tickets
此设置仅在编译时支持 OpenSSL 时可用。它为所有未明确定义密码算法列表的 "server" 行设置默认字符串,该字符串描述在与服务器进行 SSL/TLS 握手期间协商的密码算法列表。该字符串的格式在 "man 1 ciphers" 中定义。请查看 "server" 关键字以获取更多信息。
此设置仅在编译时支持 OpenSSL 时可用。它为所有 "server" 行设置强制使用的默认 ssl-options。请查看 "server" 关键字以了解可用选项。
此设置仅在编译时支持 OpenSSL 时可用。它为所有未明确定义 DH 参数的 "bind" 行设置默认 DH 参数,这些参数在 SSL/TLS 握手期间使用临时 Diffie-Hellman(DHE)密钥交换时使用。如果绑定证书文件中存在自定义 DH 参数,它将被覆盖。如果未使用 ssl-dh-param-file 或直接在证书文件中设置自定义 DH 参数,将使用由 tune.ssl.default-dh-param 指定大小的预生成 DH 参数。已知自定义参数更安全,因此推荐使用。可以使用 OpenSSL 命令 "openssl dhparam <size>" 生成自定义 DH 参数,其中 size 应至少为 2048,因为 1024 位 DH 参数不应再被视为安全。
服务器端 SSL 验证的默认行为。如果指定为 'none',则不验证服务器证书。默认值为 'required',除非使用命令行选项 '-dV' 强制指定。
将 UNIX 套接字绑定到 <path> 或将 TCPv4/v6 地址绑定到 <address:port>。对此套接字的连接将返回各种统计信息输出,甚至允许发出一些命令来更改某些运行时设置。请查阅管理指南的第 9.2 节“Unix 套接字命令”以获取更多详细信息。支持 "bind" 行支持的所有参数,例如限制某些用户或其访问权限的访问。请查阅第 5.1 节以获取更多信息。
统计套接字的默认超时时间设置为 10 秒。可以使用 "stats timeout" 更改此值。该值必须以毫秒为单位传递,或者带有时间单位后缀,如 { us, ms, s, m, h, d }。
默认情况下,统计套接字限制为 10 个并发连接。可以使用 "stats maxconn" 更改此值。
将进程的用户 ID 更改为 <number>。建议该用户 ID 专用于 HAProxy 或一小组类似的守护进程。HAProxy 必须以超级用户权限启动才能切换到另一个用户。另请参阅 "gid" 和 "user"。
将每个进程的最大文件描述符数设置为 <number>。默认情况下,它是自动计算的,因此建议不要使用此选项。
为在 "bind" 语句中声明的 UNIX 侦听套接字设置通用配置。这主要用于简化这些 UNIX 套接字的声明并减少错误风险,因为这些设置通常是必需的,但也是特定于进程的。<prefix> 设置可用于强制所有套接字路径相对于该目录。这可能需要访问另一个组件的 chroot。请注意,这些路径在 haproxy chroot 自身之前解析,因此它们是绝对路径。<mode>、<user>、<uid>、<group> 和 <gid> 的含义与 "bind" 语句使用的同名参数相同。如果两者都指定,则 "bind" 语句具有更高的优先级,这意味着 "unix-bind" 设置可被视为进程范围的默认设置。
与 "uid" 类似,但使用 /etc/passwd 中用户名 <user name> 的 UID。另请参阅 "uid" 和 "group"。
只允许字母、数字、连字符和下划线,与 DNS 名称类似。此语句在 HA 配置中很有用,其中两个或多个进程或服务器共享相同的 IP 地址。通过在所有节点上设置不同的节点名称,可以轻松地立即发现哪个服务器正在处理流量。
添加描述实例的文本。请注意,需要转义某些字符(例如 #),并且此文本将插入 HTML 页面中,因此您应避免使用“<”和“>”字符。
51Degrees 数据文件的路径,用于提供设备检测服务。该文件应已解压缩,并且 HAProxy 具有相关权限可以访问。请注意,此选项仅在 haproxy 编译时启用了 USE_51DEGREES 时可用。
要从数据集中加载的 51Degrees 属性名称列表。完整的名称列表可在 51Degrees 网站上找到:https://51degrees.com/resources/property-dictionary 请注意,此选项仅在 haproxy 编译时启用了 USE_51DEGREES 时可用。
一个字符,将附加到包含 51Degrees 结果的响应头中的每个属性值之后。如果未设置,则默认为“,”。请注意,此选项仅在 haproxy 编译时启用了 USE_51DEGREES 时可用。
将 51Degrees 转换器缓存的大小设置为 <number> 个条目。这是一个 LRU 缓存,用于记住以前的设备检测及其结果。默认情况下,此缓存是禁用的。请注意,此选项仅在 haproxy 编译时启用了 USE_51DEGREES 时可用。
默认情况下,haproxy 会尝试将健康检查的开始时间分散到服务器场中所有服务器的最小健康检查间隔内。其原理是避免对同一服务器上运行的服务进行密集检查。但是当使用较大的检查间隔(10 秒或更长)时,服务器场中的最后几个服务器需要一些时间才能开始被测试,这可能是一个问题。此参数用于强制设置第一个和最后一个检查之间的延迟上限,即使服务器的检查间隔较大。当服务器以较短的间隔运行时,它们的间隔仍将得到尊重。
将每个进程的最大并发连接数设置为 <number>。它等同于命令行参数 "-n"。当达到此限制时,代理将停止接受连接。"ulimit-n" 参数会根据此值自动调整。另请参阅 "ulimit-n"。注意:在某些平台上,"select" 轮询器不能可靠地使用超过 1024 个文件描述符。如果您的平台只支持 select 并在启动时报告 "select FAILED",您需要减少 maxconn 直到它正常工作(通常略低于 500)。如果未设置此值,它将默认为构建时在 DEFAULT_MAXCONN 中设置的值(在 haproxy -vv 中报告),如果没有强制执行内存限制,或者将根据内存限制、缓冲区大小、分配给压缩的内存、SSL 缓存大小以及是否使用 SSL 和相关的 maxsslconn(也可以是自动的)来计算。
将每个进程每秒的最大连接数设置为 <number>。当达到此限制时,代理将停止接受连接。它可以用来限制全局容量,而不考虑每个前端的容量。需要注意的是,这只能用作服务保护措施,因为当达到限制时,前端之间不一定会公平分配,所以最好也为每个前端限制一个接近其预期份额的值。此外,降低 tune.maxaccept 可以提高公平性。
将每个进程的最大输入压缩速率设置为 <number> 千字节/秒。对于每个会话,如果达到最大值,会话期间的压缩级别将降低。如果在会话开始时达到最大值,该会话将完全不压缩。如果未达到最大值,压缩级别将增加到 tune.comp.maxlevel。值为零表示没有限制,这是默认值。
设置 HAProxy 在停止对新请求进行压缩或降低当前请求的压缩级别之前可以达到的最大 CPU 使用率。它的工作方式类似于 'maxcomprate',但衡量的是 CPU 使用率而不是传入数据带宽。该值以 haproxy 使用的 CPU 百分比表示。在多进程(nbproc > 1)的情况下,每个进程管理其各自的使用率。值为 100 将禁用此限制。默认值为 100。设置较低的值将防止压缩工作减慢整个进程的速度并引入高延迟。
将每个进程的最大管道数设置为 <number>。目前,管道仅由基于内核的 tcp 拼接使用。由于一个管道包含两个文件描述符,"ulimit-n" 值将相应增加。默认值为 maxconn/4,这对于大多数重度使用情况来说似乎已经足够了。拼接代码动态分配和释放管道,并且可以回退到标准复制,因此将此值设置得太低可能只会影响性能。
将每个进程每秒的最大会话数设置为 <number>。当达到此限制时,代理将停止接受连接。它可以用来限制全局容量,而不考虑每个前端的容量。需要注意的是,这只能用作服务保护措施,因为当达到限制时,前端之间不一定会公平分配,所以最好也为每个前端限制一个接近其预期份额的值。此外,降低 tune.maxaccept 可以提高公平性。
将每个进程的最大并发 SSL 连接数设置为 <number>。默认情况下没有特定于 SSL 的限制,这意味着全局 maxconn 设置将适用于所有连接。设置此限制可以避免 openssl 使用过多内存并在 malloc 返回 NULL 时崩溃(因为它不幸地不能可靠地检查这种情况)。请注意,该限制同时适用于传入和传出连接,因此一个先解密后加密的连接算作 2 个 SSL 连接。如果未设置此值,但强制执行了内存限制,则此值将根据内存限制、maxconn、缓冲区大小、分配给压缩的内存、SSL 缓存大小以及在前端、后端或两者中是否使用 SSL 自动计算。如果在有内存限制时既未指定 maxconn 也未指定 maxsslconn,haproxy 将自动调整这些值,以便 100% 的连接可以在没有风险的情况下通过 SSL 进行,并会考虑启用 SSL 的侧(前端、后端、两者)。
将每个进程每秒的最大 SSL 会话数设置为 <number>。当达到此限制时,SSL 侦听器将停止接受连接。它可以用来限制全局 SSL CPU 使用率,而不考虑每个前端的容量。需要注意的是,这只能用作服务保护措施,因为当达到限制时,前端之间不一定会公平分配,所以最好也为每个前端限制一个接近其预期份额的值。同样重要的是要注意,会话是在进入 SSL 堆栈之前而不是之后计算的,这也保护了堆栈免受不良握手的影响。此外,降低 tune.maxaccept 可以提高公平性。
设置 zlib 每个进程可用的最大 RAM 量(以兆字节为单位)。当达到最大量时,只要 RAM 不可用,将来的会话将不会压缩。当设置为 0 时,没有限制。默认值为 0。该值在 UNIX 套接字上以字节为单位可用,通过 "show info" 命令的 "MaxZlibMemUsage" 行显示,zlib 使用的内存为 "ZlibMemUsage"(以字节为单位)。
禁用在 Linux 上使用 "epoll" 事件轮询系统。它等同于命令行参数 "-de"。下一个使用的轮询系统通常是 "poll"。另请参阅 "nopoll"。
禁用在 BSD 上使用 "kqueue" 事件轮询系统。它等同于命令行参数 "-dk"。下一个使用的轮询系统通常是 "poll"。另请参阅 "nopoll"。
禁用 "poll" 事件轮询系统的使用。它等同于命令行参数 "-dp"。下一个使用的轮询系统将是 "select"。通常不需要禁用 "poll",因为它在 HAProxy 支持的所有平台上都可用。另请参阅 "nokqueue" 和 "noepoll"。
禁用在 Linux 上使用内核在套接字之间进行 tcp 拼接。它等同于命令行参数 "-dS"。数据将使用传统的、更具可移植性的 recv/send 调用进行复制。内核 tcp 拼接仅限于一些非常近期的内核 2.6 实例。大多数 2.6.25 到 2.6.28 之间的版本都有错误,会转发损坏的数据,因此不得使用。此选项使得在有疑问时可以轻松地全局禁用内核拼接。另请参阅 "option splice-auto"、"option splice-request" 和 "option splice-response"。
禁用使用 getaddrinfo(3) 进行名称解析。它等同于命令行参数 "-dG"。将使用已弃用的 gethostbyname(3)。
禁用 SO_REUSEPORT 的使用 - 请参阅 socket(7)。它等同于命令行参数 "-dR"。
有时,希望避免以精确的间隔向服务器发送代理和健康检查,例如当许多逻辑服务器位于同一物理服务器上时。借助此参数,可以在检查间隔中添加 0 到 +/- 50% 之间的随机性。2 到 5 之间的值似乎效果很好。默认值仍为 0。
为每个进程可以分配的缓冲区数量设置硬性限制。默认值为零,表示无限制。最小非零值将始终大于 "tune.buffers.reserve",理想情况下应始终约为其两倍。强制设置此值对于限制进程可能占用的内存量同时保持正常行为特别有用。当达到此限制时,需要缓冲区的会话将等待另一个会话释放一个缓冲区。由于缓冲区是动态分配和释放的,只要限制合理,等待时间非常短且不易察觉。实际上,有时降低限制甚至可以通过提高 CPU 缓存效率来提高性能。测试表明,在平均 HTTP 流量下,限制为预期全局 maxconn 设置的 1/10 会有很好的效果,这也会显著减少内存使用。内存节省的原因是许多连接不会分配 2*tune.bufsize。除非 haproxy 核心开发人员建议,否则最好不要动这个值。
设置预分配并保留的缓冲区数量,仅在内存分配失败导致的内存短缺情况下使用。最小值为 2,也是默认值。用户没有理由更改此值,它主要针对 haproxy 核心开发人员。
将缓冲区大小设置为此大小(以字节为单位)。较低的值允许在相同数量的 RAM 中共存更多会话,而较高的值允许某些具有非常大 cookie 的应用程序工作。默认值为 16384,可以在构建时更改。强烈建议不要更改此默认值,因为非常低的值会破坏某些服务(如统计信息),而大于默认大小的值会增加内存使用,可能导致系统内存耗尽。至少全局 maxconn 参数应按此值增加的相同因子减少。如果 HTTP 请求大于(tune.bufsize - tune.maxrewrite),haproxy 将返回 HTTP 400(Bad Request)错误。同样,如果 HTTP 响应大于此大小,haproxy 将返回 HTTP 502(Bad Gateway)。
将检查缓冲区大小设置为此大小(以字节为单位)。较高的值可能有助于在非常大的页面中查找字符串或正则表达式模式,但这可能意味着更多的内存和 CPU 使用。默认值为 16384,可以在构建时更改。不建议更改此值,而应尽可能使用更好的检查方法。
设置最大压缩级别。压缩级别影响压缩期间的 CPU 使用率。此值影响压缩期间的 CPU 使用率。每个使用压缩的会话都使用此值初始化压缩算法。默认值为 1。
设置捕获的 cookie 的最大长度。"capture cookie xxx len yyy" 允许的最大值将是此值,任何更高的值都将自动截断为此值。重要的是不要设置太高的值,因为所有 cookie 捕获无论其配置值如何都会分配此大小(它们共享一个池)。此值是每个请求每个响应的,因此每个连接分配的内存是此值的两倍。如果未指定,限制设置为 63 个字符。建议不要更改此值。
设置请求中的最大报头数。当请求的报头数(包括第一行)大于此值时,它将被拒绝,并返回 "400 Bad Request" 状态码。同样,过大的响应将被阻止,并返回 "502 Bad Gateway"。默认值为 101,对于所有用途来说已经足够,考虑到广泛部署的 Apache 服务器也使用相同的限制。有时可以进一步提高此限制,以便在修复错误的应用程序之前临时允许其工作。可接受的范围是 1..32767。请记住,每个新报头都会为每个会话消耗 32 位的内存,因此不要将此限制设置得太高。
设置一个持续时间,在此之后 haproxy 将认为空缓冲区可能与空闲流相关联。这用于在交替转发大数据和小数据时优化调整某些数据包大小。使用 splice() 或在 SSL 中发送大缓冲区的决定受此参数调节。该值为 0 到 65535 之间的毫秒数。值为零表示 haproxy 不会尝试检测空闲流。默认值为 1000,这似乎能正确检测最终用户的暂停(例如:在点击前阅读页面)。没有理由更改此值。请检查下面的 tune.ssl.maxrecord。
该指令强制 Lua 引擎每执行 <number> 条指令就执行一次 yield。这允许中断一个长脚本,并让 HAProxy 调度器处理其他任务,如接受连接或转发流量。默认值为 10000 条指令。如果 HAProxy 经常执行一些 Lua 代码但需要更高的响应性,可以降低此值。如果 Lua 代码相当长且其结果对于处理数据绝对必要,可以增加 <number>。
设置 Lua 每个进程可用的最大 RAM 量(以兆字节为单位)。默认情况下为零,表示无限制。设置限制很重要,以确保脚本中的错误不会导致系统内存耗尽。
这是 Lua 会话的执行超时时间。这对于防止无限循环或在 Lua 中花费过多时间很有用。此超时仅计算纯 Lua 运行时间。如果 Lua 执行了 sleep,则 sleep 时间不计入在内。默认超时时间为 4 秒。
目的与 "tune.lua.session-timeout" 相同,但此超时专用于任务。默认情况下,此超时未设置,因为任务可能在 HAProxy 的整个生命周期内保持活动状态。例如,用于检查服务器的任务。
这是 Lua 服务的执行超时时间。这对于防止无限循环或在 Lua 中花费过多时间很有用。此超时仅计算纯 Lua 运行时间。如果 Lua 执行了 sleep,则 sleep 时间不计入在内。默认超时时间为 4 秒。
设置一个进程在切换到其他工作之前可以连续接受的最大连接数。在单进程模式下,较高的数字在高连接率下性能更好。然而,在多进程模式下,在进程之间保持一点公平性通常能更好地提高性能。此值单独应用于每个侦听器,以便考虑到侦听器绑定的进程数。此值默认为 64。在多进程模式下,它除以侦听器绑定的进程数的两倍。将此值设置为 -1 将完全禁用此限制。通常不需要调整此值。
设置一次调用轮询系统可以处理的最大事件量。默认值根据操作系统进行调整。已经注意到,将其降低到 200 以下会略微降低延迟,但会牺牲网络带宽,而将其增加到 200 以上则会以延迟换取略微增加的带宽。
将保留的缓冲区空间设置为此大小(以字节为单位)。保留空间用于报头重写或追加。套接字上的第一次读取永远不会超过 bufsize-maxrewrite。历史上,它默认为 bufsize 的一半,但这没有太大意义,因为很少有大量的报头需要添加。设置得太高会妨碍处理大的请求或响应。设置得太低会妨碍向已有的较大请求或 POST 请求添加新报头。通常明智的做法是将其设置为大约 1024。如果大于 bufsize 的一半,它会自动调整为 bufsize 的一半。这意味着您在更改 bufsize 时不必担心它。
将模式查找缓存的大小设置为 <number> 个条目。这是一个 LRU 缓存,用于记住以前的查找及其结果。它被 ACL 和 map 用于慢速模式查找,即使用 "sub"、"reg"、"dir"、"dom"、"end"、"bin" 匹配方法以及不区分大小写的字符串的查找。它适用于模式表达式,这意味着它能够记住在配置行上指定的所有模式(包括所有从文件中加载的模式)中的查找结果。它会自动使通过 HTTP 操作或在 CLI 上更新的条目失效。默认缓存大小设置为 10000 个条目,这将其在 32 位系统上的内存占用限制在约 5 MB,在 64 位系统上限制在约 8 MB。此缓存中发生冲突的风险非常低,大约是缓存大小除以 2^64。通常,在默认缓存大小为 10000 个条目的情况下,以每秒 10000 个请求的速度,暴力攻击在 60 年后造成一次冲突的几率为 1%,或者在 6 年后为 0.1%。这被认为远低于由老化组件引起的内存损坏风险。如果这不可接受,可以通过将此参数设置为 0 来禁用缓存。
将内核管道缓冲区大小设置为此大小(以字节为单位)。默认情况下,管道是系统的默认大小。但有时在使用 TCP 拼接时,增加管道大小可以提高性能,特别是在怀疑管道未被填满且执行了许多 splice() 调用时。这对内核的内存占用有影响,因此如果影响不明确,则不应更改此值。
强制将客户端或服务器端的内核套接字接收缓冲区大小设置为指定的值(以字节为单位)。此值适用于所有 TCP/HTTP 前端和后端。通常不应设置此值,默认大小 (0) 让内核根据可用内存量自动调整此值。但是,有时将其设置为非常低的值(例如 4096)有助于节省内核内存,防止其缓冲过多的接收数据。不过,较低的值会显著增加 CPU 使用率。
强制将客户端或服务器端的内核套接字发送缓冲区大小设置为指定的值(以字节为单位)。此值适用于所有 TCP/HTTP 前端和后端。通常不应设置此值,默认大小 (0) 让内核根据可用内存量自动调整此值。但是,有时将其设置为非常低的值(例如 4096)有助于节省内核内存,防止其缓冲过多的接收数据。不过,较低的值会显著增加 CPU 使用率。另一个用例是防止与极慢的客户端发生写超时,因为内核会等待大部分缓冲区被读取后才再次通知 haproxy。
设置全局 SSL 会话缓存的大小,以块为单位。一个块足够大,可以容纳一个没有对等证书的编码会话。带有对等证书的编码会话根据对等证书的大小存储在多个块中。一个块大约使用 200 字节的内存。默认值可以在构建时强制指定,否则默认为 20000。当缓存已满时,最空闲的条目将被清除并重新分配。较高的值可以减少这种清除的发生,从而通过确保所有用户尽可能长时间地保持其会话来减少 CPU 密集型的 SSL 握手次数。如果 "nbproc" 大于 1,所有条目在启动时预先分配,并在所有进程之间共享。将此值设置为 0 会禁用 SSL 会话缓存。此布尔值禁用所有进程之间的 SSL 会话缓存共享。通常不应使用,因为它会因客户端命中随机进程而强制进行许多重新协商。但在某些操作系统上可能需要,因为这些系统上可能无法使用任何 SSL 缓存同步方法。在这种情况下,在 SSL 层之前添加第一层基于哈希的负载均衡可能会限制会话共享缺失的影响。
设置缓存的 SSL 会话可以保持有效的时长。此时间以秒为单位表示,默认为 300(5 分钟)。重要的是要理解,这并不保证会话会持续那么长时间,因为如果缓存已满,最长时间空闲的会话将被清除,尽管它们配置了生命周期。此设置的真正用处是防止会话被使用太长时间。
设置一次传递给 SSL_write() 的最大字节数。默认值 0 表示没有限制。通过 SSL/TLS,客户端只有在收到完整的记录后才能解密数据。对于大记录,这意味着客户端可能需要下载多达 16kB 的数据才能开始处理它们。限制该值可以改善位于高延迟或低带宽网络上的浏览器的页面加载时间。建议找到适合 1 或 2 个 TCP 段(通常在以太网上启用 TCP 时间戳时为 1448 字节,或禁用时间戳时为 1460 字节)的最佳值,同时记住 SSL/TLS 会增加一些开销。测试期间,1419 和 2859 的典型值取得了良好效果。使用 "strace -e trace=write" 找到最佳值。Haproxy 将在检测到空闲流后自动切换到此设置(请参阅上面的 tune.idletimer)。
在 DHE 密钥交换的情况下,设置用于生成临时/瞬时 Diffie-Hellman 密钥的 Diffie-Hellman 参数的最大大小。最终大小将尝试匹配服务器的 RSA(或 DSA)密钥的大小(例如,对于 2048 位 RSA 密钥使用 2048 位临时 DH 密钥),但不会超过此最大值。默认值为 1024。只允许 1024 或更高的值。较高的值会增加 CPU 负载,而大于 1024 位的值不受 Java 7 及更早版本的客户端支持。如果直接在证书文件中或使用 ssl-dh-param-file 参数提供了静态 Diffie-Hellman 参数,则不使用此值。
将用于存储生成证书的缓存大小设置为 <number> 个条目。这是一个 LRU 缓存。因为动态生成 SSL 证书的开销很大,所以它们被缓存起来。默认缓存大小设置为 1000 个条目。
这四个调整项有助于管理变量系统使用的最大内存量。"global" 限制所有作用域可用的总内存量。"sess" 限制会话作用域的内存,"txn" 限制事务作用域的内存,"reqres" 限制每个请求或响应处理的内存。内存核算是分层的,意味着更粗粒度的限制包含更细粒度的限制:"sess" 包含 "txn",而 "txn" 包含 "reqres"。例如,当 "tune.vars.sess-max-size" 限制为 100 时,"tune.vars.txn-max-size" 和 "tune.vars.reqres-max-size" 也不能超过 100。如果我们创建一个包含 100 字节的变量 "txn.var",所有可用空间都被消耗。请注意,在运行时超出限制不会导致错误消息,但值可能会被截断或损坏。因此,请务必准确规划存储所有变量所需的空间量。
为每个会话在 zlib 初始化中设置 memLevel 参数。它定义了应为内部压缩状态分配多少内存。值为 1 使用最少的内存,但速度慢且压缩率降低;值为 9 使用最大的内存以获得最佳速度。可以是 1 到 9 之间的值。默认值为 8。
为每个会话在 zlib 初始化中设置窗口大小(历史缓冲区的大小)。此参数的较大值会以内存使用为代价带来更好的压缩效果。可以是 8 到 15 之间的值。默认值为 15。
启用调试模式,将所有交换信息转储到标准输出,并禁止 fork 到后台。它等同于命令行参数 "-d"。它绝不应在生产配置中使用,因为它可能会阻止系统完全启动。
启动期间不显示任何消息。它等同于命令行参数 "-q"。
可以通过仅允许经过身份验证和授权的用户来控制对前端/后端/侦听部分或 http 统计信息的访问。为此,需要创建至少一个用户列表并定义用户。
创建名为 <listname> 的新用户列表。可以使用许多独立的用户列表来存储独立客户的身份验证和授权数据。
将组 <groupname> 添加到当前用户列表。也可以通过使用逗号分隔的名称列表(前面有 "users" 关键字)将用户附加到此组。
将用户 <username> 添加到当前用户列表。可以使用安全(加密)和不安全(未加密)的密码。加密密码使用 crypt(3) 函数进行评估,因此根据系统的能力,支持不同的算法。例如,现代基于 Glibc 的 Linux 系统支持 MD5、SHA-256、SHA-512,当然还有经典的、基于 DES 的密码加密方法。
userlist L1 group G1 users tiger,scott group G2 users xdb,scott user tiger password $6$k6y3o.eP$JlKBx9za9667qe4(...)xHSwRv6J.C0/D7cV91 user scott insecure-password elgato user xdb insecure-password hello userlist L2 group G1 group G2 user tiger password $6$k6y3o.eP$JlKBx(...)xHSwRv6J.C0/D7cV91 groups G1 user scott insecure-password elgato groups G1,G2 user xdb insecure-password hello groups G2
请注意,这两个列表在功能上是相同的。
可以在多个 haproxy 实例之间通过 TCP 连接以多主方式传播粘性表中的任何数据类型的条目。每个实例将其本地更新和插入推送到远程对等节点。推送的值会覆盖远程值,而不进行聚合。中断的交换会自动检测并从最后一个已知点恢复。此外,在软重启期间,旧进程使用这样的 TCP 连接连接到新进程,以在新进程尝试连接其他对等节点之前推送其所有条目。这确保了在重新加载期间的快速复制,即使对于大型表,通常也只需要几分之一秒。请注意,服务器 ID 用于远程识别服务器,因此重要的是配置看起来相似,或者至少在所有参与者上对每个服务器强制使用相同的 ID。
创建名为 <peersect> 的新对等节点列表。它是一个独立的部分,由一个或多个粘性表引用。
禁用一个对等节点部分。它会禁用与此部分相关的侦听和任何同步。这用于禁用粘性表的同步,而无需注释掉所有 "peers" 引用。
这会重新启用先前被禁用的对等节点部分。
在对等节点部分内定义一个对等节点。如果 <peername> 设置为本地对等节点名称(默认为主机名,或使用 "-L" 命令行选项强制指定),haproxy 将在 <ip>:<port> 上侦听传入的远程对等节点连接。否则,<ip>:<port> 定义了连接到远程对等节点的位置,<peername> 在协议级别用于在服务器端识别和验证远程对等节点。在软重启期间,旧实例使用本地对等节点 <ip>:<port> 连接到新实例并启动完整的复制(教学过程)。强烈建议在所有对等节点上具有完全相同的 peers 声明,并且仅依赖 "-L" 命令行参数来更改本地对等节点名称。这使得在所有对等节点之间维护一致的配置文件变得更容易。您可能希望在地址参数中引用一些环境变量,请参阅关于环境变量的第 2.3 节。
peers mypeers peer haproxy1 192.168.0.1:1024 peer haproxy2 192.168.0.2:1024 peer haproxy3 10.2.0.1:1024 backend mybackend mode tcp balance roundrobin stick-table type ip size 20k peers mypeers stick on src server srv1 192.168.0.30:80 server srv2 192.168.0.31:80
当服务器状态发生变化时,可以发送电子邮件警报。如果配置了电子邮件警报,则会发送到邮件发送器部分中配置的每个邮件发送器。电子邮件使用 SMTP 发送给邮件发送器。
创建名为 <mailersect> 的新邮件发送器列表。它是一个独立的部分,由一个或多个代引用。
在邮件发送器部分内定义一个邮件发送器。
mailers mymailers mailer smtp1 192.168.0.1:587 mailer smtp2 192.168.0.2:587 backend mybackend mode tcp balance roundrobin email-alert mailers mymailers email-alert from test1@horms.org email-alert to test2@horms.org server srv1 192.168.0.30:80 server srv2 192.168.0.31:80
代理配置可以位于一组部分中: - defaults [<name>] - frontend <name> - backend <name> - listen <name> "defaults" 部分为其声明之后的所有其他部分设置默认参数。这些默认参数由下一个 "defaults" 部分重置。有关可以在 "defaults" 部分中设置的参数列表,请参见下文。名称是可选的,但为了更好的可读性,建议使用它。 "frontend" 部分描述了一组接受客户端连接的侦听套接字。 "backend" 部分描述了一组服务器,代理将连接到这些服务器以转发传入连接。 "listen" 部分定义了一个完整的代理,将其前端和后端部分组合在一个部分中。它通常对纯 TCP 流量很有用。 所有代理名称必须由大小写字母、数字、'-'(破折号)、'_'(下划线)、'.'(点)和':'(冒号)组成。ACL 名称区分大小写,这意味着 "www" 和 "WWW" 是两个不同的代理。 历史上,所有代理名称都可以重叠,但这只会在日志中引起麻烦。自从引入内容切换以来,强制要求具有重叠功能(前端/后端)的两个代理具有不同的名称。但是,仍然允许前端和后端共享相同的名称,因为这种配置似乎很常见。 目前,支持两种主要的代理模式:"tcp"(也称为第 4 层)和 "http"(也称为第 7 层)。在第 4 层模式下,HAProxy 仅在两端之间转发双向流量。在第 7 层模式下,HAProxy 分析协议,并可以通过允许、阻止、切换、添加、修改或删除请求或响应中的任意内容来与之交互,这些操作基于任意标准。 在 HTTP 模式下,应用于流经连接的请求和响应的处理取决于前端 HTTP 选项和后端 HTTP 选项的组合。 HAProxy 支持 5 种连接模式: - KAL:keep alive("option http-keep-alive"),这是默认模式:处理所有请求和响应,连接在响应和新请求之间保持打开但空闲状态。 - TUN:tunnel("option http-tunnel"):这是 1.0 到 1.5-dev21 版本的默认模式:只处理第一个请求和响应,其余所有内容都直接转发,不进行任何分析。不应使用此模式,因为它会在日志记录和 HTTP 处理方面造成很多麻烦。 - PCL:passive close("option httpclose"):与隧道模式完全相同,但在双向都附加 "Connection: close",以尝试使两端在第一次请求/响应交换后关闭。 - SCL:server close("option http-server-close"):在收到响应结束后,面向服务器的连接被关闭,但面向客户端的连接保持打开。 - FCL:forced close("option forceclose"):在响应结束后,连接被主动关闭。 将应用于通过前端和后端连接的有效模式可以由两种代理模式根据以下矩阵确定,但简而言之,模式是对称的,keep-alive 是最弱的选项,force close 是最强的。 后端模式 | KAL | TUN | PCL | SCL | FCL ----+-----+-----+-----+-----+---- KAL | KAL | TUN | PCL | SCL | FCL ----+-----+-----+-----+-----+---- TUN | TUN | TUN | PCL | SCL | FCL 前端 ----+-----+-----+-----+-----+---- 模式 PCL | PCL | PCL | PCL | FCL | FCL ----+-----+-----+-----+-----+---- SCL | SCL | SCL | FCL | SCL | FCL ----+-----+-----+-----+-----+---- FCL | FCL | FCL | FCL | FCL | FCL
支持以下关键字列表。它们中的大多数只能在有限的几种配置段类型中使用。其中一些被标记为“已弃用”(deprecated),因为它们继承自可能令人困惑或功能受限的旧语法,并且有新的推荐关键字来替代它们。标有“(*)”的关键字可以选择性地使用“no”前缀进行反转,例如“no option contstats”。当某个选项默认已启用,但需要为特定实例禁用时,这样做很有意义。此类选项也可以使用“default”前缀,以恢复默认设置,无论在之前的“defaults”配置段中指定了什么。
本节提供了每个关键字及其用法的描述。
声明或完成一个访问控制列表。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 是![]() |
acl invalid_src src 0.0.0.0/7 224.0.0.0/3 acl invalid_src src_port 0:1023 acl local_dst hdr(host) -i localhost
有关 ACL 的用法,请参见第 7 节。
基于一个现有的应用程序 cookie 定义会话粘性。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 否![]() | 是![]() | 是![]() |
<cookie> 这是应用程序使用的 cookie 名称,HAProxy 将需要为每个新会话学习该 cookie。 <length> 这是每个 cookie 值中将要被记忆和检查的最大字符数。 <holdtime> 这是 cookie 在未使用的情况下,经过多长时间后将从内存中移除。如果未指定单位,此时间以毫秒为单位。 request-learn 如果指定此选项,那么在服务器没有在响应中指定任何 cookie 的情况下,haproxy 将能够学习请求中找到的 cookie。这通常发生在 PHPSESSID cookie,或者当 haproxy 的会话在应用程序会话之前过期并且选择了正确的服务器时。建议指定此选项以提高可靠性。 prefix 当指定此选项时,haproxy 将匹配 cookie 前缀(或 URL 参数前缀)。appsession 的值是此此前缀之后的数据。 示例: appsession ASPSESSIONID len 64 timeout 3h prefix 这将匹配 cookie ASPSESSIONIDXXXX=XXXXX,appsession 的值将是 XXXX=XXXXX。 mode 此选项允许更改 URL 解析器模式。目前支持 2 种模式: - path-parameters:解析器在路径参数部分(每个参数由分号分隔)中查找 appsession,这对于 JSESSIONID 等非常方便。如果未设置该选项,这是默认模式。 - query-string:在此模式下,解析器将在查询字符串中查找 appsession。
从 1.6 版本开始,appsession 已被移除。使用 stick-tables 更灵活、更方便,并且 stick-tables 支持多主复制和跨重载的数据保留,而 appsession 不支持。
向系统提供关于期望的监听队列(backlog)大致大小的提示。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 否![]() |
<conns> 是待处理连接的数量。根据操作系统的不同,它可能表示已确认的连接数、未确认的连接数或两者之和。
为了防范 SYN 洪水攻击,一种解决方案是增加系统的 SYN 队列大小。根据系统的不同,有时它只能通过系统参数进行调整,有时根本无法调整,有时系统依赖于应用程序在调用 listen() 系统调用时给出的提示。默认情况下,HAProxy 将前端的 maxconn 值传递给 listen() 系统调用。在可以利用此值的系统上,有时能够指定一个不同的值会很有用,因此有了这个 backlog 参数。在 Linux 2.4 上,该参数被系统忽略。在 Linux 2.6 上,它被用作一个提示,系统最多接受不小于该值的最小的 2 的幂次方,并且永远不会超过某些限制(通常是 32768)。
定义在后端中使用的负载均衡算法。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
<algorithm> 是在进行负载均衡时选择服务器的算法。这仅在没有持久性信息可用,或者当连接被重新调度到另一台服务器时适用。<algorithm> 可能是以下之一: roundrobin 每台服务器根据其权重轮流使用。当服务器的处理时间保持均匀分布时,这是最平滑和最公平的算法。此算法是动态的,这意味着服务器权重可以实时调整,例如用于慢启动。它在设计上限制每个后端最多有 4095 台活动服务器。请注意,在一些大型服务器集群中,当一台服务器在短暂宕机后恢复时,有时可能需要几百个请求才能重新整合到集群中并开始接收流量。这是正常现象,尽管非常罕见。在此指出,以防您有机会观察到它,从而不必担心。 static-rr 每台服务器根据其权重轮流使用。此算法与 roundrobin 类似,但它是静态的,这意味着实时更改服务器权重不会有任何效果。另一方面,它对服务器数量没有设计上的限制,当一台服务器恢复时,一旦完整的映射被重新计算,它总是立即被重新引入到集群中。它的运行 CPU 占用也稍低(约 -1%)。 leastconn 连接数最少的服务器接收连接。在负载相同的服务器组内执行轮询,以确保所有服务器都会被使用。建议在期望有非常长会话的场景中使用此算法,例如 LDAP、SQL、TSE 等... 但不太适合使用短会话的协议,如 HTTP。此算法是动态的,这意味着服务器权重可以实时调整,例如用于慢启动。 first 第一个有可用连接槽的服务器接收连接。服务器的选择从最低的数字标识符到最高的(参见服务器参数 "id"),默认为服务器在集群中的位置。一旦服务器达到其 maxconn 值,就使用下一个服务器。不设置 maxconn 就使用此算法是没有意义的。此算法的目的是始终使用最少数量的服务器,以便在非繁忙时段可以关闭多余的服务器。此算法忽略服务器权重,对长会话(如 RDP 或 IMAP)比 HTTP 带来更多好处,尽管在 HTTP 中也可能有用。为了有效使用此算法,建议云控制器定期检查服务器使用情况,在未使用时关闭它们,并定期检查后端队列,在队列膨胀时启动新服务器。或者,使用 "http-check send-state" 可以通知服务器负载情况。 source 源 IP 地址被哈希并除以运行中服务器的总权重,以指定哪台服务器将接收请求。这确保了只要没有服务器宕机或上线,相同的客户端 IP 地址将始终访问同一台服务器。如果由于运行中服务器数量的变化导致哈希结果改变,许多客户端将被导向到不同的服务器。此算法通常用于 TCP 模式,其中无法插入 cookie。它也可以在互联网上使用,为拒绝会话 cookie 的客户端提供尽力而为的粘性。此算法默认是静态的,这意味着实时更改服务器权重将没有效果,但这可以通过使用 "hash-type" 来改变。 uri 此算法对 URI 的左半部分(问号之前)或整个 URI(如果存在 "whole" 参数)进行哈希,并将哈希值除以运行中服务器的总权重。结果指定哪台服务器将接收请求。这确保了只要没有服务器上线或宕机,相同的 URI 将始终被导向到同一台服务器。这用于代理缓存和反病毒代理,以最大化缓存命中率。请注意,此算法只能在 HTTP 后端中使用。此算法默认是静态的,这意味着实时更改服务器权重将没有效果,但这可以通过使用 "hash-type" 来改变。此算法支持两个可选参数 "len" 和 "depth",两者都后跟一个正整数。当需要仅根据 URI 的开头来均衡服务器时,这些选项可能很有用。"len" 参数表示算法应仅考虑 URI 开头的那么多字符来计算哈希。请注意,将 "len" 设置为 1 很少有意义,因为大多数 URI 以一个前导 "/" 开头。"depth" 参数表示用于计算哈希的最大目录深度。请求中的每个斜杠都算作一个级别。如果两个参数都指定了,当任一参数达到时评估就会停止。 url_param 将在每个 HTTP GET 请求的查询字符串中查找参数中指定的 URL 参数。如果使用了 "check_post" 修饰符,那么当在 URL 中的问号('?')后的查询字符串中找不到参数时,将在 HTTP POST 请求实体中搜索该参数。只有在收到已通告的数据量或请求缓冲区已满时,才会开始分析消息体。在极少数情况下使用分块编码时,只扫描第一个分块。被分块边界分隔的参数值可能会被随机均衡(如果可能的话)。此关键字曾支持一个可选的 <max_wait> 参数,现在已被忽略。如果找到参数后跟一个等号('=')和一个值,则该值被哈希并除以运行中服务器的总权重。结果指定哪台服务器将接收请求。这用于在请求中跟踪用户标识符,并确保只要没有服务器上线或宕机,同一用户 ID 将始终被发送到同一台服务器。如果没有找到值或没有找到参数,则应用轮询算法。请注意,此算法只能在 HTTP 后端中使用。此算法默认是静态的,这意味着实时更改服务器权重将没有效果,但这可以通过使用 "hash-type" 来改变。 hdr(<name>) HTTP 头部 <name> 将在每个 HTTP 请求中被查找。就像等效的 ACL 'hdr()' 函数一样,括号中的头部名称不区分大小写。如果头部不存在或不包含任何值,则应用轮询算法。有一个可选的 'use_domain_only' 参数可用,用于将哈希算法缩减到主域部分,适用于某些特定的头部,如 'Host'。例如,在 Host 值 "haproxy.1wt.eu" 中,只会考虑 "1wt"。此算法默认是静态的,这意味着实时更改服务器权重将没有效果,但这可以通过使用 "hash-type" 来改变。 rdp-cookie rdp-cookie(<name>) RDP cookie <name>(如果省略,则为 "mstshash")将在每个传入的 TCP 请求中被查找和哈希。就像等效的 ACL 'req_rdp_cookie()' 函数一样,名称不区分大小写。此机制作为一种降级的持久性模式很有用,因为它使得始终将同一用户(或同一会话 ID)发送到同一台服务器成为可能。如果找不到 cookie,则使用正常的轮询算法。请注意,为使其工作,前端必须确保请求缓冲区中已存在 RDP cookie。为此,您必须使用 'tcp-request content accept' 规则结合 'req_rdp_cookie_cnt' ACL。此算法默认是静态的,这意味着实时更改服务器权重将没有效果,但这可以通过使用 "hash-type" 来改变。另请参阅 rdp_cookie 模式获取函数。 <arguments> 是某些算法可能需要的可选参数列表。目前,只有 "url_param" 和 "uri" 支持可选参数。
当没有设置其他算法、模式或选项时,后端的负载均衡算法被设置为轮询(roundrobin)。每个后端只能设置一次算法。
balance roundrobin balance url_param userid balance url_param session_id check_post 64 balance hdr(User-Agent) balance hdr(host) balance hdr(Host) use_domain_only
注意:在使用带“url_param”的“check_post”扩展时,必须考虑以下注意事项和限制: - 所有 POST 请求都有资格被考虑,因为无法确定参数是否会在可能包含二进制数据的主体或实体中找到。因此,可能需要另一种方法来限制对主体中没有 URL 参数的 POST 请求的考虑。(参见 acl reqideny http_end) - 使用大于请求缓冲区大小的 <max_wait> 值没有意义且无用。缓冲区大小在构建时设置,默认为 16 kB。 - 不支持 Content-Encoding,参数搜索可能会失败;负载均衡将回退到轮询(Round Robin)。 - 不支持 Expect: 100-continue,负载均衡将回退到轮询(Round Robin)。 - Transfer-Encoding (RFC7230 3.3.1) 仅在第一个分块中受支持。如果整个参数值不在第一个分块中,服务器的选择是未定义的(实际上,由第一个分块中实际出现的多少来定义)。 - 此功能不支持生成 100、411 或 501 响应。 - 在某些情况下,请求“check_post”可能会尝试扫描消息体的全部内容。扫描通常在线性空白或控制字符被发现时终止,这表明可能是一个 URL 参数列表的结束。对于 SGML 类型的消息体,这可能不是一个问题。
在前端(frontend)中定义一个或多个监听地址和/或端口。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 否![]() |
<address> 是可选的,可以是一个主机名、一个 IPv4 地址、一个 IPv6 地址或 '*'。它指定了前端将监听的地址。如果未设置,将监听系统上的所有 IPv4 地址。'*' 或系统的特殊地址 "0.0.0.0" 也是如此。IPv6 的等效地址是 '::'。 可选地,可以在地址前使用地址族前缀来强制指定地址族,而不管地址格式如何,这对于指定没有斜杠('/')的 unix 套接字路径很有用。目前支持的前缀有: - 'ipv4@' -> 地址始终是 IPv4 - 'ipv6@' -> 地址始终是 IPv6 - 'unix@' -> 地址是本地 unix 套接字的路径 - 'abns@' -> 地址在抽象命名空间中(仅限 Linux)。 注意:由于抽象套接字不可“重新绑定”,它们在软重启期间与多进程模式不太兼容,因此如果 nbproc 大于 1,最好避免使用它们。其效果是,如果新进程启动失败,只有旧进程中的一个能够重新绑定到该套接字。 - 'fd@<n>' -> 使用从父进程继承的文件描述符 <n>。该 fd 必须已绑定,并且可能已经或尚未在监听。 您可能希望在地址参数中引用一些环境变量,请参阅关于环境变量的第 2.3 节。 <port_range> 是一个唯一的 TCP 端口,或者是一个端口范围,代理将为上面指定的 IP 地址接受连接。对于 TCP 监听器,端口是强制性的。请注意,在 IPv6 地址的情况下,端口始终是最后一个冒号(':')后面的数字。 范围可以是: - 一个数字端口(例如:'80') - 一个用破折号分隔的端口范围,明确说明下限和上限(例如:'2000-2100'),这些都包含在范围内。 必须特别注意端口范围,因为每个 <address:port> 对都会消耗一个套接字(= 一个文件描述符),所以用一个简单的范围很容易消耗大量描述符,并耗尽套接字。此外,每个 <address:port> 对在同一系统上运行的所有实例中必须只使用一次。 请注意,绑定到低于 1024 的端口通常需要特殊权限来启动程序,这与 'uid' 参数无关。 <path> 是一个以斜杠('/')开头的 UNIX 套接字路径。这是 TCP 监听端口的替代方案。Haproxy 将在此处的套接字上接收 UNIX 连接。路径必须以斜杠开头,默认是绝对路径。它可以是相对于全局配置段中由 "unix-bind" 定义的前缀的相对路径。请注意,前缀加上套接字路径的总长度不能超过 UNIX 套接字的某些系统限制,通常设置为 107 个字符。 <param*> 是在同一行声明的所有套接字共有的参数列表。这些众多的参数取决于操作系统和构建选项,并有专门的一整个章节来介绍它们。更多详情请参考第 5 节。
可以指定一个由逗号分隔的地址:端口组合列表。然后,前端将监听所有这些地址。一个前端可以监听的地址和端口数量没有固定限制,一个前端中的 "bind" 语句数量也没有限制。
listen http_proxy bind :80,:443 bind 10.0.0.1:10080,10.0.0.1:10443 bind /var/run/ssl-frontend.sock user root mode 600 accept-proxy listen http_https_proxy bind :80 bind :443 ssl crt /etc/haproxy/site.pem listen http_https_proxy_explicit bind ipv6@:80 bind ipv4@public_ssl:443 ssl crt /etc/haproxy/site.pem bind unix@ssl-frontend.sock user root mode 600 accept-proxy listen external_bind_app1 bind "fd@${FD_APP1}"
注意:关于 Linux 的抽象命名空间套接字,HAProxy 使用整个 sun_path 长度作为地址长度。其他一些程序,如 socat,默认只使用字符串长度。在 socat 中对任何抽象套接字定义传递选项 ",unix-tightsocklen=0",以使其与 HAProxy 兼容。
将一个实例的可见性限制在特定的进程号集合中。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
all 所有进程都将看到这个实例。这是默认值。它可以用来覆盖一个默认值。 odd 此实例将在进程 1,3,5,...63 上启用。此选项可以与其他数字组合使用。 even 此实例将在进程 2,4,6,...64 上启用。此选项可以与其他数字组合使用。如果进程数少于 2,请不要使用它,否则某些实例可能会在所有进程中都缺失。 number 此实例将在此进程号或范围内启用,其值必须在 1 和 32 或 64 之间,具体取决于机器的字长。如果一个代理被绑定到大于已配置的 global.nbproc 的进程号,如果指定了单个进程,它将被强制到进程 #1,否则将被强制到所有进程。
此关键字将某些实例的绑定限制在某些进程上。这对于避免有太多进程监听相同端口非常有用。例如,在一台双核机器上,在全局配置段中设置 'nbproc 2',然后将监听器分配给 'odd' 和 'even' 实例可能是有意义的。目前,使用此关键字无法引用超过 32 或 64 个进程,但这对于大多数设置应该足够了。请注意,'all' 真正意味着所有进程,无论机器的字长如何,并不限于前 32 或 64 个。每个 "bind" 行可以进一步限制在代理进程的一个子集上,请参阅第 5.1 节中的 "process" bind 关键字。当前端没有显式的 "bind-process" 行时,它会尝试绑定到其所有 "bind" 行引用的进程。这意味着前端可以轻松地适应其监听器的进程。如果某些后端被绑定到其他进程的前端引用,则该后端会自动继承前端的进程。
listen app_ip1 bind 10.0.0.1:80 bind-process odd listen app_ip2 bind 10.0.0.2:80 bind-process even listen management bind 10.0.0.3:80 bind-process 1 2 3 4 listen management bind 10.0.0.4:80 bind-process 1-4
如果/除非条件匹配,则阻止一个第 7 层请求。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 是![]() |
如果/除非 <condition> 匹配,HTTP 请求将在第 7 层处理的早期阶段被阻止。如果请求被阻止,将返回一个 403 错误。条件必须引用 ACL(参见第 7 节)。这通常用于在满足或不满足某些条件时,拒绝访问某些敏感资源。每个实例的 "block" 语句数量没有固定限制。此形式已弃用,请不要在任何新配置中使用它,请改用新的 "http-request deny"。
acl invalid_src src 0.0.0.0/7 224.0.0.0/3 acl invalid_src src_port 0:1023 acl local_dst hdr(host) -i localhost # block 已弃用。请改用 http-request deny: #block if invalid_src || local_dst http-request deny if invalid_src || local_dst
有关 ACL 的用法,请参见第 7 节。
在请求和响应中捕获并记录一个 cookie。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 否![]() |
<name> 是要捕获的 cookie 名称的开头部分。为了匹配确切的名称,只需在名称后加上一个等号('=')。完整的名称将出现在日志中,这对于那些会同时调整 cookie 名称和值的应用服务器(例如:ASPSESSIONXXXXX)很有用。<length> 是日志中报告的最大字符数,包括 cookie 名称、等号和值,全部采用标准的 "name=value" 形式。如果字符串超过 <length>,它将被从右侧截断。
只捕获第一个 cookie。请求头中的 "cookie" 和响应头中的 "set-cookie" 都会被监控。这对于检查导致用户之间会话交叉或盗用的应用程序错误特别有用,因为通常用户的 cookie 只能在登录页面上更改。当客户端没有提供 cookie 时,相关的日志列将报告 "-"。当请求没有导致服务器分配 cookie 时,响应列中会报告一个 "-"。捕获只在前端执行,因为对于给定的前端,日志格式不能根据后端而改变。这在未来可能会改变。请注意,一个前端只能有一个 "capture cookie" 语句。最大捕获长度由全局的 "tune.http.cookielen" 设置决定,默认为 63 个字符。不能在 "defaults" 配置段中指定捕获。
capture cookie ASPSESSION len 32
捕获并记录指定请求头的最后一次出现。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 否![]() |
<name> 是要捕获的头的名称。头名称不区分大小写,但通常的做法是按照它们在请求中出现的样子来写,每个单词的首字母大写。头名称不会出现在日志中,只报告其值,但其在日志中的位置会得到尊重。<length> 是从值中提取并报告在日志中的最大字符数。如果字符串超过 <length>,它将被从右侧截断。
捕获该头最后一次出现的完整值。该值将添加在日志中的大括号 ('{}') 之间。如果捕获了多个头,它们将由竖线 ('|') 分隔,并按照它们在配置中声明的相同顺序出现。不存在的头将被记录为空字符串。请求头捕获的常见用途包括虚拟主机环境中的 "Host" 字段、支持上传时的 "Content-length"、用于快速区分真实用户和机器人的 "User-agent",以及在代理环境中用于查找请求来源的 "X-Forwarded-For"。请注意,在捕获诸如 "User-agent" 之类的头时,可能会记录一些空格,这会使日志分析更加困难。因此,如果您知道您的日志解析器不够智能,无法依赖大括号,请注意您记录的内容。捕获的请求头数量及其长度没有限制,但明智的做法是保持它们较低以限制每个会话的内存使用。为了保持同一前端的日志格式一致,头捕获只能在前端声明。不能在 "defaults" 配置段中指定捕获。capture request header Host len 15 capture request header X-Forwarded-For len 15 capture request header Referer len 15
捕获并记录指定响应头的最后一次出现。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 否![]() |
<name> 是要捕获的头的名称。头名称不区分大小写,但通常的做法是按照它们在响应中出现的样子来写,每个单词的首字母大写。头名称不会出现在日志中,只报告其值,但其在日志中的位置会得到尊重。<length> 是从值中提取并报告在日志中的最大字符数。如果字符串超过 <length>,它将被从右侧截断。
捕获该头最后一次出现的完整值。结果将在捕获的请求头之后,添加在日志中的大括号 ('{}') 之间。如果捕获了多个头,它们将由竖线 ('|') 分隔,并按照它们在配置中声明的相同顺序出现。不存在的头将被记录为空字符串。响应头捕获的常见用途包括 "Content-length" 头,它指示预计将返回多少字节,以及 "Location" 头,用于跟踪重定向。捕获的响应头数量及其长度没有限制,但明智的做法是保持它们较低以限制每个会话的内存使用。为了保持同一前端的日志格式一致,头捕获只能在前端声明。不能在 "defaults" 配置段中指定捕获。capture response header Content-length len 9 capture response header Location len 15
设置客户端侧的最大不活动时间。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 否![]() |
<timeout> 超时值默认以毫秒为单位指定,但也可以是任何其他单位,如果数字后跟有单位后缀,如本文档开头所述。
不活动超时适用于期望客户端确认或发送数据时。在 HTTP 模式下,这个超时在第一阶段(客户端发送请求时)和响应期间(客户端正在读取服务器发送的数据时)尤其重要。超时值默认以毫秒为单位指定,但也可以是任何其他单位,如果数字后跟有单位后缀,如本文档开头所述。在 TCP 模式下(以及在较小程度上,在 HTTP 模式下),强烈建议客户端超时与服务器超时保持相等,以避免调试复杂的状况。一个好的做法是,通过指定略高于 3 秒倍数的超时(例如:4 或 5 秒)来覆盖一到多次 TCP 数据包丢失。此参数特定于前端,但可以在 "defaults" 配置段中一次性为所有前端指定。这实际上是最简单的方法之一,可以避免忘记它。未指定的超时会导致无限超时,这是不推荐的。这种用法被接受并且可以工作,但在启动时会报告一个警告,因为如果系统的超时也没有配置,可能会导致系统中过期的会话累积。此参数是为兼容性而提供的,但目前已弃用。请改用 "timeout client"。
启用 HTTP 压缩。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
algo 后面是支持的压缩算法列表。type 后面是将要被压缩的 MIME 类型列表。offload 使 haproxy 仅作为压缩卸载器工作(见说明)。
目前支持的算法有: identity 这主要用于调试,并且在开发压缩功能时很有用。Identity 不对数据应用任何更改。 gzip 应用 gzip 压缩。此设置仅在内置 zlib 或 libslz 支持时可用。 deflate 与 "gzip" 相同,但使用 deflate 算法和 zlib 格式。请注意,此算法在许多浏览器上的支持存在歧义,并且在最近的浏览器中根本不支持。强烈建议不要将其用于除实验之外的任何用途。此设置仅在内置 zlib 或 libslz 支持时可用。 raw-deflate 与 "deflate" 相同,但不带 zlib 包装器,当浏览器想要 "deflate" 时用作替代。所有主流浏览器都理解它,并且尽管违反了标准,但已知它比 "deflate" 工作得更好,至少在 MSIE 和某些版本的 Safari 上是这样。不要与 "deflate" 结合使用,因为两者都对相同的 Accept-Encoding 令牌做出反应,所以要么用这个,要么用那个。此设置仅在内置 zlib 或 libslz 支持时可用。 压缩将根据 Accept-Encoding 请求头来激活。对于 identity,它不关心该头。 如果后端服务器支持 HTTP 压缩,这些指令将是空操作:haproxy 将看到压缩后的响应,并且不会再次压缩。 如果后端服务器不支持 HTTP 压缩,并且请求中有 Accept-Encoding 头,haproxy 将压缩匹配的响应。 "offload" 设置使 haproxy 移除 Accept-Encoding 头,以防止后端服务器压缩响应。强烈建议不要这样做,因为这意味着所有的压缩工作都将在 haproxy 所在的单点上完成。然而,在某些部署场景中,haproxy 可能被安装在一个有问题的网关前面,该网关的 HTTP 压缩实现有缺陷且无法关闭。在这种情况下,haproxy 可以用来防止该网关发出无效的负载。在这种情况下,简单地在配置中移除该头是行不通的,因为它在头被解析之前应用,这会阻止 haproxy 进行压缩。"offload" 设置应该用于此类场景。注意:目前,在 defaults 配置段中设置 "offload" 会被忽略。 在以下情况下禁用压缩: * 请求的 "Accept-Encoding" 头中没有宣传支持的压缩算法 * 响应消息不是 HTTP/1.1 * HTTP 状态码不是 200 * 响应头 "Transfer-Encoding" 包含 "chunked"(临时解决方法) * 响应既不包含 "Content-Length" 头,也不包含最后一个值为 "chunked" 的 "Transfer-Encoding" * 响应包含一个 "Content-Type" 头,其第一个值以 "multipart" 开头 * 响应在 "Cache-control" 头中包含 "no-transform" 值 * User-Agent 匹配 "Mozilla/4",除非是带有 XP SP2 的 MSIE 6,或 MSIE 7 及更高版本 * 响应包含 "Content-Encoding" 头,表明响应已经被压缩(参见 compression offload) 注意:压缩不会重写 Etag 头,也不会发出 Warning 头。
compression algo gzip compression type text/html text/plain
设置等待服务器连接尝试成功的最大时间。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
<timeout> 超时值默认以毫秒为单位指定,但也可以是任何其他单位,如果数字后跟有单位后缀,如本文档开头所述。
如果服务器与 haproxy 位于同一局域网内,连接应该是即时的(少于几毫秒)。无论如何,一个好的做法是,通过指定略高于 3 秒倍数的超时(例如:4 或 5 秒)来覆盖一到多次 TCP 数据包丢失。默认情况下,如果队列超时未指定,连接超时也会将其预设为相同的值。历史上,contimeout 也曾用于在 listen 配置段中设置 tarpit 超时,这在纯前端中是不可能的。此参数特定于后端,但可以在 "defaults" 配置段中一次性为所有后端指定。这实际上是最简单的方法之一,可以避免忘记它。未指定的超时会导致无限超时,这是不推荐的。这种用法被接受并且可以工作,但在启动时会报告一个警告,因为如果系统的超时也没有配置,可能会导致系统中失败的会话累积。此参数是为向后兼容性而提供的,但目前已弃用。请改用 "timeout connect"、"timeout queue" 或 "timeout tarpit"。
在后端启用基于 cookie 的持久性。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
<name> 是为了实现持久性而将被监控、修改或插入的 cookie 的名称。这个 cookie 通过响应中的 "Set-Cookie" 头发送给客户端,并在所有请求中由客户端通过 "Cookie" 头带回。应特别注意选择一个不会与任何可能的应用程序 cookie 冲突的名称。此外,如果相同的后端可能被相同的客户端使用(例如:HTTP/HTTPS),如果不希望它们之间有持久性,应注意在所有后端之间使用不同的 cookie 名称。 rewrite 此关键字表示 cookie 将由服务器提供,haproxy 将必须修改其值以在其中设置服务器的标识符。当复杂的 "Set-cookie" 和 "Cache-control" 头的管理留给应用程序时,此模式很方便。应用程序可以决定是否适合发出持久性 cookie。由于所有响应都应被监控,此模式在 HTTP 隧道模式下不起作用。除非应用程序行为非常复杂和/或有问题,否则建议新部署不要从这种模式开始。此关键字与 "insert" 和 "prefix" 不兼容。 insert 此关键字表示如果客户端尚未拥有一个允许其访问此服务器的 cookie,则持久性 cookie 将必须由 haproxy 插入到服务器响应中。当不带 "preserve" 选项使用时,如果服务器发出同名 cookie,它将在处理前被移除。因此,此模式可用于升级在 "rewrite" 模式下运行的现有配置。该 cookie 将只是一个会话 cookie,不会存储在客户端的磁盘上。默认情况下,除非添加了 "indirect" 选项,否则服务器将看到客户端发出的 cookie。由于缓存效应,通常明智的做法是添加 "nocache" 或 "postonly" 关键字(见下文)。"insert" 关键字与 "rewrite" 和 "prefix" 不兼容。 prefix 此关键字表示不依赖于专门的持久性 cookie,而是将完成一个现有的 cookie。在某些特定环境中,客户端可能不支持多个 cookie,而应用程序已经需要它。在这种情况下,每当服务器设置一个名为 <name> 的 cookie 时,它将以服务器的标识符和分隔符作为前缀。该前缀将从所有客户端请求中移除,以便服务器仍然能找到它发出的 cookie。由于所有请求和响应都可能被修改,此模式在隧道模式下不起作用。"prefix" 关键字与 "rewrite" 和 "insert" 不兼容。注意:强烈建议不要将 "indirect" 与 "prefix" 一起使用,否则服务器的 cookie 更新将不会发送给客户端。 indirect 当指定此选项时,对于已经拥有一个有效 cookie 以访问处理了请求的服务器的客户端,将不会发出任何 cookie。如果服务器自己设置了这样的 cookie,它将被移除,除非也设置了 "preserve" 选项。在 "insert" 模式下,这还将从传输到服务器的请求中移除 cookie,从而使持久性机制从应用程序的角度看完全透明。注意:强烈建议不要将 "indirect" 与 "prefix" 一起使用,否则服务器的 cookie 更新将不会发送给客户端。 nocache 在客户端和 HAProxy 之间有缓存的情况下,建议与 insert 模式结合使用此选项,因为它确保如果需要插入 cookie,可缓存的响应将被标记为不可缓存。这很重要,因为如果所有的持久性 cookie 都添加在一个可缓存的主页上,那么所有的客户都将从外部缓存中获取该页面,并且都将共享相同的持久性 cookie,导致一台服务器接收的流量远多于其他服务器。另请参阅 "insert" 和 "postonly" 选项。 postonly 此选项确保 cookie 插入将仅在对 POST 请求的响应上执行。它是 "nocache" 选项的替代方案,因为 POST 响应是不可缓存的,所以这确保了持久性 cookie 永远不会被缓存。由于大多数网站在第一次 POST(通常是登录请求)之前不需要任何形式的持久性,这是一种优化缓存而不会有在缓存中找到持久性 cookie 风险的非常有效的方法。另请参阅 "insert" 和 "nocache" 选项。 preserve 此选项只能与 "insert" 和/或 "indirect" 一起使用。它允许服务器自己发出持久性 cookie。在这种情况下,如果在响应中找到 cookie,haproxy 将保持其不变。这对于例如在注销请求后结束持久性非常有用。为此,服务器只需发出一个具有无效值(例如:空)或过去日期的 cookie。通过将此机制与 "disable-on-404" 检查选项相结合,可以执行完全平滑的关闭,因为用户在注销后肯定会离开服务器。 httponly 此选项告诉 haproxy 在插入 cookie 时添加 "HttpOnly" cookie 属性。此属性用于使用户代理不与非 HTTP 组件共享 cookie。有关此属性的更多信息,请查看 RFC6265。 secure 此选项告诉 haproxy 在插入 cookie 时添加 "Secure" cookie 属性。此属性用于使用户代理永远不会通过非安全通道发出此 cookie,这意味着使用此标志学习的 cookie 将仅通过 SSL/TLS 连接呈现。有关此属性的更多信息,请查看 RFC6265。 domain 此选项允许指定插入 cookie 的域。它需要一个参数:一个有效的域名。如果域名以点开头,浏览器允许将其用于任何以该名称结尾的主机。也可以通过多次调用此选项来指定多个域名。某些浏览器可能对域名数量有小的限制,所以这样做时要小心。作为记录,向 MSIE 6 或 Firefox 2 发送 10 个域名可以正常工作。 maxidle 此选项允许插入的 cookie 在闲置一段时间后被忽略。它仅适用于插入模式的 cookie。当 cookie 发送给客户端时,该 cookie 的发出日期也会被发送。在后续呈现此 cookie 时,如果日期比参数指示的延迟(以秒为单位)更早,它将被忽略。否则,当响应发送给客户端时,如果需要,它将被刷新。这对于防止那些从不关闭浏览器的用户在同一台服务器上停留太长时间(例如:在服务器集群大小更改后)特别有用。当设置此选项且 cookie 没有日期时,它总是被接受,但在响应中会被刷新。这保留了管理员访问其网站的能力。日期在未来超过 24 小时的 cookie 会被忽略。这样做可以让管理员修复时区问题,而不会有将用户踢出网站的风险。 maxlife 此选项允许插入的 cookie 在一定生命周期后被忽略,无论它们是否在使用中。它仅适用于插入模式的 cookie。当 cookie 首次发送给客户端时,该 cookie 的发出日期也会被发送。在后续呈现此 cookie 时,如果日期比参数指示的延迟(以秒为单位)更早,它将被忽略。如果请求中的 cookie 没有日期,它将被接受并设置一个日期。日期在未来超过 24 小时的 cookie 会被忽略。这样做可以让管理员修复时区问题,而不会有将用户踢出网站的风险。与 maxidle 相反,此值不会被刷新,只有第一次访问的日期算数。maxidle 和 maxlife 可以同时使用。这对于防止那些从不关闭浏览器的用户在同一台服务器上停留太长时间(例如:在服务器集群大小更改后)特别有用。这比 maxidle 方法更强,因为它在一定的绝对延迟后强制重新调度。 attr 此选项告诉 haproxy 在插入 cookie 时添加一个额外的属性。属性值可以包含除控制字符或 ";" 之外的任何字符。此选项可以重复使用。
每个 HTTP 后端只能有一个持久性 cookie,并且可以在 defaults 配置段中声明。cookie 的值将是 "server" 语句中 "cookie" 关键字后指定的值。如果未为给定服务器声明 cookie,则不会设置 cookie。
cookie JSESSIONID prefix cookie SRV insert indirect nocache cookie SRV insert postonly indirect cookie SRV insert indirect nocache maxidle 30m maxlife 8h
声明一个捕获槽。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 否![]() |
<length> 是允许捕获的长度。
此声明仅在 frontend 或 listen 配置段中可用,但保留的槽可以在 backend 中使用。“request”关键字分配一个用于请求中的捕获槽,“response”分配一个用于响应中的捕获槽。
更改后端中服务器的默认选项。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
<param*> 是此服务器的参数列表。“default-server”关键字接受许多重要选项,并有专门的完整章节进行介绍。请参阅第 5 节以获取更多详细信息。
default-server inter 1000 weight 13
指定在没有匹配到“use_backend”规则时使用的后端。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 否![]() |
<backend> 是要使用的后端的名称。
在使用“use_backend”关键字在前端和后端之间进行内容切换时,指明在没有规则匹配时将使用哪个后端通常很有用。这通常是动态后端,它将捕获所有未确定的请求。
use_backend dynamic if url_dyn use_backend static if url_css url_img extension_img default_backend dynamic
描述一个 listen、frontend 或 backend。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 是![]() |
允许添加一句话来在 HAProxy HTML 统计页面中描述相关对象。该描述将打印在其所描述对象名称的右侧。<string> 参数中的空格无需使用反斜杠转义。
禁用一个 proxy、frontend 或 backend。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
“disabled”关键字用于禁用一个实例,主要目的是为了释放一个监听端口或临时禁用一个服务。该实例仍会被创建,其配置也会被检查,但它将以“停止”状态创建,并在统计信息中显示为该状态。它不会接收任何流量,也不会发送任何健康检查或日志。通过在“defaults”部分添加“disabled”关键字,可以一次性禁用多个实例。
设置一个默认服务器地址
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 否![]() | 是![]() | 是![]() |
<address> 是默认服务器的 IPv4 地址。或者,也支持可解析的主机名,但此名称将在启动期间解析。<ports> 是一个强制性的端口规范。所有连接都将发送到此端口,并且不允许像普通服务器那样使用端口偏移量。
“dispatch”关键字指定一个默认服务器,用于在没有其他服务器可以接受连接时使用。过去它曾被用于将非持久连接转发到辅助负载均衡器。由于其语法简单,它也被用于简单的 TCP 中继。为了更清晰,建议不要使用它,而是使用“server”指令。
启用一个 proxy、frontend 或 backend。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
“enabled”关键字用于显式启用一个实例,当 defaults 已被设置为“disabled”时。这种情况很少使用。
返回文件内容以替代 HAProxy 生成的错误
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
<code> 是 HTTP 状态码。目前,HAProxy 能够生成的状态码有 200、400、403、405、408、429、500、502、503 和 504。<file> 指定一个包含完整 HTTP 响应的文件。建议遵循通用惯例,在文件名后附加“.http”,这样人们就不会将响应与 HTML 错误页面混淆,并建议使用绝对路径,因为文件是在执行任何 chroot 之前读取的。
重要的是要理解,此关键字并非用于重写服务器返回的错误,而是用于重写 HAProxy 检测并返回的错误。这就是为什么支持的错误列表仅限于一小部分。状态码 200 是为响应匹配“monitor-uri”规则的请求而发出的。文件内容会原样返回到 TCP 套接字上。这允许使用任何技巧,例如重定向到另一个 URL 或站点,以及清除 cookie、强制启用或禁用缓存等技巧。软件包提供了默认的错误文件,其返回内容与默认错误相同。文件大小不应超过配置的缓冲区大小(BUFSIZE),通常是 8 或 16 kB,否则它们将被截断。为了避免在所有服务器都宕机时客户端与 HAProxy 之间发生循环(导致返回错误而不是图像),明智的做法是不要在文件中放置任何对本地内容的引用(例如:图像)。为了更好地符合 HTTP 规范,建议所有头行都以 CR-LF 结尾,而不是单独的 LF。文件在读取配置时同时被读取并保存在内存中。因此,即使进程被 chroot,错误仍然会继续返回,并且在进程运行时不会考虑任何文件更改。开发这些文件的一个简单方法是将它们与 403 状态码关联,并请求一个被阻止的 URL。
errorfile 400 /etc/haproxy/errorfiles/400badreq.http errorfile 408 /dev/null # 解决 Chrome 预连接的 bug errorfile 403 /etc/haproxy/errorfiles/403forbid.http errorfile 503 /etc/haproxy/errorfiles/503sorry.http
返回一个到某个 URL 的 HTTP 重定向,以替代 HAProxy 生成的错误
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
<code> 是 HTTP 状态码。目前,HAProxy 能够生成的状态码有 200、400、403、405、408、429、500、502、503 和 504。<url> 是“Location”头的确切内容。它可以包含指向同一站点上错误页面的相对 URI,或指向另一站点上错误页面的绝对 URI。应特别注意相对 URI,以避免在 URI 本身可能生成相同错误(例如:500)时发生重定向循环。
重要的是要理解,此关键字并非用于重写服务器返回的错误,而是用于重写 HAProxy 检测并返回的错误。这就是为什么支持的错误列表仅限于一小部分。状态码 200 是为响应匹配“monitor-uri”规则的请求而发出的。请注意,这两个关键字都返回 HTTP 302 状态码,它告诉客户端使用相同的 HTTP 方法获取指定的 URL。对于非 GET 方法(如 POST),这可能会很有问题,因为发送给客户端的 URL 可能不允许 GET 以外的方法。要解决此问题,请使用“errorloc303”,它会发送 HTTP 303 状态码,指示客户端必须使用 GET 请求获取该 URL。
返回一个到某个 URL 的 HTTP 重定向,以替代 HAProxy 生成的错误
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
<code> 是 HTTP 状态码。目前,HAProxy 能够生成的状态码有 200、400、403、405、408、429、500、502、503 和 504。<url> 是“Location”头的确切内容。它可以包含指向同一站点上错误页面的相对 URI,或指向另一站点上错误页面的绝对 URI。应特别注意相对 URI,以避免在 URI 本身可能生成相同错误(例如:500)时发生重定向循环。
重要的是要理解,此关键字并非用于重写服务器返回的错误,而是用于重写 HAProxy 检测并返回的错误。这就是为什么支持的错误列表仅限于一小部分。状态码 200 是为响应匹配“monitor-uri”规则的请求而发出的。请注意,这两个关键字都返回 HTTP 303 状态码,它告诉客户端使用相同的 HTTP GET 方法获取指定的 URL。这解决了与“errorloc”和 302 状态码相关的常见问题。一些在 HTTP/1.1 之前设计的非常旧的浏览器可能不支持它,但到目前为止还没有报告过此类问题。
声明用于电子邮件警报的信封和头部的发件人电子邮件地址。这是发送电子邮件警报的来源地址。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
<emailaddr> 是发送电子邮件警报时使用的发件人电子邮件地址
还需要设置“email-alert mailers”和“email-alert to”,如果设置了,则为该代理启用电子邮件警报发送功能。
声明将发送电子邮件警报的消息的最大日志级别。这充当发送电子邮件警报的过滤器。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
<level> 8 个 syslog 级别之一:emerg alert crit err warning notice info debug 以上 syslog 级别从低到高排序。
默认级别是 alert。还需要设置“email-alert from”、“email-alert mailers”和“email-alert to”,如果设置了,则为该代理启用电子邮件警报发送功能。在以下情况下会发送警报: * 一个未暂停的服务器被标记为 down 且 <level> 是 alert 或更低 * 一个已暂停的服务器被标记为 down 且 <level> 是 notice 或更低 * 一个服务器被标记为 up 或进入 drain 状态且 <level> 是 notice 或更低 * 启用了“option log-health-checks”,<level> 是 info 或更低,并且发生了健康检查状态更新
声明发送电子邮件警报时要使用的邮件程序
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
<mailersect> 是用于发送电子邮件警报的邮件程序部分的名称。
还需要设置“email-alert from”和“email-alert to”,如果设置了,则为该代理启用电子邮件警报发送功能。
声明与邮件程序通信时要使用的主机名地址。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
<hostname> 是与邮件程序通信时使用的主机名
默认使用系统的主机名。还需要设置“email-alert from”、“email-alert mailers”和“email-alert to”,如果设置了,则为该代理启用电子邮件警报发送功能。
声明电子邮件警报信封中的收件人地址和头部的收件人地址。这是发送电子邮件警报的目标地址。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
<emailaddr> 是发送电子邮件警报时使用的收件人电子邮件地址
还需要设置“email-alert mailers”和“email-alert to”,如果设置了,则为该代理启用电子邮件警报发送功能。
声明一个条件以强制在宕机服务器上保持持久性
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 否![]() | 是![]() | 是![]() |
默认情况下,请求不会被分派到宕机的服务器。可以使用“option persist”来强制此行为,但这是无条件的,并且如果设置了“option redispatch”,它会重新分派到一个有效的服务器。这使得强制某些请求到达一个因维护操作而被人为标记为宕机的服务器的可能性非常小。“force-persist”语句允许声明各种基于 ACL 的条件,当满足这些条件时,将导致请求忽略服务器的宕机状态,并仍然尝试连接到它。这使得可以启动一个服务器,该服务器仍对健康检查返回错误,并运行一个特殊配置的浏览器来测试服务。在这些便利的方法中,可以使用特定的源 IP 地址或特定的 cookie。cookie 还有一个优点,即可以轻松地在测试页面的浏览器上添加/删除。一旦服务得到验证,就可以通过向健康检查返回有效的响应来向世界开放该服务。当满足“if”条件或不满足“unless”条件时,强制持久性将被启用。使用此功能时,最终的重新分派总是被禁用的。
指定后端负载达到何种程度时服务器将达到其 maxconn
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
<conns> 是后端上的连接数,该连接数将使服务器使用最大连接数。
当服务器指定了“maxconn”参数时,表示其并发连接数永远不会更高。此外,如果它有“minconn”参数,则表示一个根据后端负载动态变化的限制。服务器将始终接受至少 <minconn> 个连接,绝不会超过 <maxconn>,并且当后端的并发连接数少于 <conns> 时,限制将在两个值之间平滑过渡。这使得在正常负载期间可以限制服务器上的负载,但在重要负载时可以进一步推高负载,而不会在异常负载期间使服务器过载。由于很难正确设置此值,haproxy 会自动将其设置为所有可能分支到此后端的(基于“use_backend”和“default_backend”规则)前端 maxconn 总和的 10%。这样,不设置它也是安全的。但是,涉及动态名称的“use_backend”不被计算在内,因为无法知道它们是否可能匹配。
# 服务器将接受 100 到 1000 个并发连接 # 当后端达到 10000 个连接时,将达到 1000 的最大值。 backend dynamic fullconn 10000 server srv1 dyn1:80 minconn 100 maxconn 1000 server srv2 dyn2:80 minconn 100 maxconn 1000
在软停止后,维持代理在一段时间内可操作
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
<time> 是当通过 SIGUSR1 信号接收到软停止时,实例将保持可操作且前端套接字仍在监听的时间(默认为毫秒)。
这可以用来确保服务按特定顺序消失。它被设计成这样,专用于外部设备监控的前端会立即失败,而其他前端则会保持运行,直到设备检测到故障所需的时间。请注意,目前使用此参数的好处非常小,实际上它可能会使软重新配置过程复杂化,而不是简化它。
指定一种将哈希值映射到服务器的方法
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
<method> 是用于从 <function> 计算出的哈希值中选择服务器的方法: map-based 哈希表是一个包含所有活动服务器的静态数组。哈希值将非常平滑,会考虑权重,但是是静态的,即服务器运行时权重的变化将被忽略。这意味着不会有慢启动。此外,由于服务器是根据其在数组中的位置选择的,当服务器数量变化时,大多数映射都会改变。这意味着当服务器上线或下线,或者当服务器添加到服务器组时,大多数连接将被重新分配到不同的服务器。这对于缓存等场景可能不方便。 consistent 哈希表是一个填充了每个服务器多次出现的树。哈希键在树中查找,并选择最近的服务器。这种哈希是动态的,它支持在服务器运行时更改权重,因此与慢启动功能兼容。它的优点是,当服务器上线或下线时,只有它的关联被移动。当服务器添加到服务器组时,只有一小部分映射被重新分配,使其成为缓存的理想方法。然而,由于其原理,分布永远不会非常平滑,有时可能需要调整服务器的权重或其 ID 以获得更平衡的分布。为了在多个负载均衡器上获得相同的分布,重要的是所有服务器都具有完全相同的 ID。注意:如果没有指定哈希函数,一致性哈希使用 sdbm 和 avalanche。 <function> 是要使用的哈希函数: sdbm 此函数最初是为 sdbm(一个 ndbm 的公共领域重新实现)数据库库创建的。它被发现在打乱比特方面表现良好,导致键的更好分布和更少的分裂。它也碰巧是一个具有良好分布的通用哈希函数,除非总服务器权重是 64 的倍数,在这种情况下应用 avalanche 修饰符可能会有帮助。 djb2 此函数最早由 Dan Bernstein 多年前在 comp.lang.c 上提出。研究表明,对于某些工作负载,此函数提供的分布优于 sdbm。它通常在基于文本的输入上表现良好,但对于纯数字输入或当总服务器权重是 33 的倍数时,除非也使用 avalanche 修饰符,否则性能可能会非常差。 wt6 此函数是在过去测试其他函数时为 haproxy 设计的。它不像其他函数那样平滑,但对输入数据集或服务器数量的敏感性要小得多。对于一致性哈希或当对数字数据(如源 IP 地址或 URL 参数中的访问者标识符)进行哈希时,它可以作为 sdbm+avalanche 或 djb2+avalanche 的替代方案。 crc32 这是以太网、gzip、PNG 等中使用的最常见的 CRC32 实现。它比其他函数慢,但可能提供更好的分布或更不可预测的结果,尤其是在处理字符串时。 <modifier> 指示在哈希键后应用的可选方法: avalanche 此指令表示不应使用上述哈希函数的原始结果,而应首先应用一个 4 字节的完全雪崩哈希。此步骤的目的是混合前一个哈希产生的比特,以避免当输入包含一些有限值或当服务器数量是哈希某个组件(SDBM 为 64,DJB2 为 33)的倍数时产生任何不希望的效果。启用 avalanche 往往会使结果更不可预测,但它也不如使用原始函数时平滑。对于某些工作负载,可能需要进行一些测试。此哈希是 Bob Jenkins 提出的众多哈希之一。
默认的哈希类型是“map-based”,建议在大多数情况下使用。默认的函数是“sdbm”,函数的选择应基于被哈希值的范围。
在对健康检查响应 HTTP/404 时启用维护模式
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
当设置此选项时,返回 HTTP 404 状态码的服务器将从进一步的负载均衡中排除,但仍会接收持久连接。这为 Web 管理员提供了一种非常方便的方法来优雅地关闭他们的服务器。同样重要的是要注意,在此模式下被检测为失败的服务器不会生成警报,只会生成一个通知。如果服务器再次响应 2xx 或 3xx,它将立即被重新插入到服务器组中。在统计页面上,处于此模式的服务器状态报告为“NOLB”。重要的是要注意,此选项仅与“httpchk”选项一起使用。如果此选项与“http-check expect”一起使用,则它优先于后者,因此 404 响应仍将被视为软停止。
使 HTTP 健康检查考虑响应内容或特定状态码
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
<match> 是一个关键字,指示如何在响应中查找特定模式。该关键字可以是“status”、“rstatus”、“string”或“rstring”之一。关键字前面可以加上感叹号(“!”)以否定匹配。感叹号和关键字之间允许有空格。有关支持的关键字的更多详细信息,请参见下文。<pattern> 是要查找的模式。它可以是字符串或正则表达式。如果模式包含空格,必须使用通常的反斜杠('\')进行转义。
默认情况下,“option httpchk”认为响应状态码 2xx 和 3xx 是有效的,其他是无效的。当使用“http-check expect”时,它定义了什么被认为是有效或无效的。一个后端只支持一个“http-check”语句。如果服务器未能响应或超时,检查显然会失败。可用的匹配项有: status <string> : 测试 HTTP 状态码的精确字符串匹配。如果响应的状态码与此字符串完全相同,则健康检查响应将被视为有效。如果“status”关键字前缀为“!”,则如果状态码匹配,响应将被视为无效。 rstatus <regex> : 测试 HTTP 状态码的正则表达式。如果响应的状态码匹配该表达式,则健康检查响应将被视为有效。如果“rstatus”关键字前缀为“!”,则如果状态码匹配,响应将被视为无效。这主要用于检查多个代码。 string <string> : 在 HTTP 响应体中测试精确的字符串匹配。如果响应体包含此确切字符串,则健康检查响应将被视为有效。如果“string”关键字前缀为“!”,则如果响应体包含此字符串,响应将被视为无效。这可以用于在动态页面的末尾查找强制性词语,或在检查页面上出现特定错误时(例如:堆栈跟踪)检测故障。 rstring <regex> : 在 HTTP 响应体上测试正则表达式。如果响应体匹配此表达式,则健康检查响应将被视为有效。如果“rstring”关键字前缀为“!”,则如果响应体匹配该表达式,响应将被视为无效。这可以用于在动态页面的末尾查找强制性词语,或在检查页面上出现特定错误时(例如:堆栈跟踪)检测故障。 重要的是要注意,响应的大小将受限于由全局“tune.chksize”选项定义的特定大小,默认为 16384 字节。因此,太大的响应在使用“string”或“rstring”时可能不包含强制模式。如果绝对需要大的响应,可以通过设置全局变量来更改默认最大大小。然而,值得记住的是,解析非常大的响应可能会浪费一些 CPU 周期,尤其是在使用正则表达式时,并且最好将检查集中在较小的资源上。此外,“http-check expect”不支持 HTTP keep-alive。请记住,它会自动附加一个“Connection: close”头,这意味着此头不应出现在由“option httpchk”提供的请求中。最后,如果“http-check expect”与“http-check disable-on-404”结合使用,那么当服务器响应 404 时,后者具有优先权。
# 只接受状态 200 为有效 http-check expect status 200 # 将 SQL 错误视为错误 http-check expect ! string SQL\ Error # 仅将状态 5xx 视为错误 http-check expect ! rstatus ^5 # 检查在 /html 之前是否有一个正确的十六进制标签 http-check expect rstring <!--tag:[0-9a-f]*--></html>
启用在 HTTP 健康检查中发送状态头
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
设置此选项后,haproxy 将系统性地发送一个特殊的“X-Haproxy-Server-State”头,其中包含一系列参数,向每个服务器指示 haproxy 如何看待它们。例如,当一个服务器在无法访问 haproxy 的情况下被操作,并且操作员需要知道 haproxy 是否仍然认为它在线,或者该服务器是否是服务器组中的最后一个时,这可能很有用。该头由分号分隔的字段组成,第一个字段是一个词(“UP”、“DOWN”、“NOLB”),后面可能跟着转换前的总检查次数中的有效检查次数,就像在统计界面中显示的那样。接下来的头是“<variable>=<value>”的形式,以无特定顺序指示统计界面中可用的一些值: - 一个变量“address”,包含后端服务器的地址。这对应于服务器声明中的 <address> 字段。对于 unix 域套接字,它将显示“unix”。 - 一个变量“port”,包含后端服务器的端口。这对应于服务器声明中的 <port> 字段。对于 unix 域套接字,它将显示“unix”。 - 一个变量“name”,包含后端名称后跟一个斜杠(“/”)然后是服务器名称。当一个服务器在多个后端中被检查时,这很有用。 - 一个变量“node”,包含 haproxy 节点的名称,如全局“node”变量中所设置,否则为系统的未指定主机名。 - 一个变量“weight”,表示服务器的权重,一个斜杠(“/”)和服务器组的总权重(仅计算可用的服务器)。这有助于了解当此服务器失败时是否有其他服务器可用来处理负载。 - 一个变量“scur”,表示服务器上当前的并发连接数,后跟一个斜杠(“/”)然后是同一后端所有服务器上的总连接数。 - 一个变量“qcur”,表示服务器队列中当前的请求数。 应用服务器接收到的头示例: >>> X-Haproxy-Server-State: UP 2/3; name=bck/srv2; node=lb1; weight=1/2; \ scur=13/22; qcur=0
第 7 层请求的访问控制
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 是![]() |
http-request 语句定义了一组适用于第 7 层处理的规则。这些规则在 frontend、listen 或 backend 部分遇到时,会按其声明顺序进行评估。任何规则都可以选择性地后跟一个基于 ACL 的条件,在这种情况下,只有当条件为真时,该规则才会被评估。第一个关键字是规则的操作。目前支持的操作包括: - “allow”:停止规则评估,让请求通过检查。不再评估后续的“http-request”规则。 - “deny”:停止规则评估,并立即拒绝请求,发出一个 HTTP 403 错误,或者可选地发出“deny_status”参数指定的状码。允许的状态码列表仅限于那些可以被“errorfile”指令覆盖的状态码。不再评估后续的“http-request”规则。 - “tarpit”:停止规则评估,并立即阻塞请求,在由“timeout tarpit”或(如果前者未设置)“timeout connect”指定的延迟时间内不响应。在该延迟之后,如果客户端仍然连接,则返回一个 HTTP 500 错误,这样客户端就不会怀疑它被“tarpitted”(拖延)了。日志将报告标志“PT”。tarpit 规则的目标是在攻击期间减慢机器人的速度,当它们在并发请求数量上受到限制时。它对非常愚蠢的机器人非常有效,并且与“deny”规则相比,将显著减少防火墙的负载。但当面对“正确”开发的机器人时,它可能会通过强迫 haproxy 和前端防火墙支持疯狂数量的并发连接而使情况变得更糟。另请参阅下面的“silent-drop”操作。 - “auth”:停止规则评估,并立即以 HTTP 401 或 407 错误代码响应,以邀请用户提供有效的用户名和密码。不再评估后续的“http-request”规则。支持一个可选的“realm”参数,它设置与响应一起返回的认证领域(通常是应用程序的名称)。 - “redirect”:根据重定向规则执行 HTTP 重定向。这与“redirect”语句完全相同,只是它插入了一个可以在其他“http-request”规则中间处理的重定向规则,并且这些规则使用“log-format”字符串。有关规则的语法,请参阅“redirect”关键字。 - “add-header”附加一个 HTTP 头字段,其名称在 <name> 中指定,其值由 <fmt> 定义,<fmt> 遵循日志格式规则(请参阅第 8.2.4 节中的自定义日志格式)。这对于将连接特定的信息传递给服务器(例如:客户端的 SSL 证书),或将多个头合并为一个特别有用。此规则不是最终规则,因此可以添加其他类似的规则。请注意,头的添加是立即执行的,因此一个规则可能会重用前一个规则产生的头。 - “set-header”与“add-header”作用相同,只是首先会移除已存在的同名头。这在向服务器传递安全信息时很有用,此时头不能被外部用户操纵。请注意,新值是在移除之前计算的,因此可以将一个值连接到现有头。 - “del-header”移除所有名称在 <name> 中指定的 HTTP 头字段。 - “replace-header”根据 <match-regex> 匹配头字段 <name> 的所有出现中的正则表达式,并用 <replace-fmt> 参数替换它们。<replace-fmt> 中允许使用格式字符,其工作方式与“add-header”中的 <fmt> 参数类似。匹配是区分大小写的。重要的是要理解,此操作只考虑整个头行,而不管它们可能包含多少个值。此用法适用于值中自然包含逗号的头,例如 If-Modified-Since 等。
http-request replace-header Cookie foo=([^;]*);(.*) foo=\1;ip=%bi;\2
应用于: Cookie: foo=foobar; expires=Tue, 14-Jun-2016 01:40:45 GMT; 输出: Cookie: foo=foobar;ip=192.168.1.20; expires=Tue, 14-Jun-2016 01:40:45 GMT; 假设后端 IP 是 192.168.1.20 - “replace-value”的工作方式与“replace-header”类似,但它将正则表达式与头字段 <name> 的每个逗号分隔的值进行匹配,而不是整个头。这适用于允许携带多个值的所有头。一个例子可以是 Accept 头。
http-request replace-value X-Forwarded-For ^192\.168\.(.*)$ 172.16.\1
应用于: X-Forwarded-For: 192.168.10.1, 192.168.13.24, 10.0.0.37 输出: X-Forwarded-For: 172.16.10.1, 172.16.13.24, 10.0.0.37 - “set-method”用格式字符串 <fmt> 的评估结果重写请求方法。很少有正当理由需要这样做,因为这更有可能破坏某些东西而不是修复它。 - “set-path”用格式字符串 <fmt> 的评估结果重写请求路径。查询字符串(如果有)保持不变。如果在路径之前找到方案和授权机构,它们也保持不变。如果请求没有路径(“*”),则用格式替换它。这可以用于在路径前添加一个目录组件。另请参阅“set-query”和“set-uri”。
# 在路径前添加主机名 http-request set-path /%[hdr(host)]%[path]
- “set-query”用格式字符串 <fmt> 的评估结果重写请求的查询字符串,该字符串出现在第一个问号(“?”)之后。问号之前的部分保持不变。如果请求不包含问号并且新值不为空,则在 URI 的末尾添加一个问号,后跟新值。如果问号存在,即使值为空,它也永远不会被移除。这可以用于从查询字符串中添加或删除参数。另请参阅“set-query”和“set-uri”。
# 在查询字符串中将“%3D”替换为“=” http-request set-query %[query,regsub(%3D,=,g)]
- “set-uri”用格式字符串 <fmt> 的评估结果重写请求 URI。方案、授权机构、路径和查询字符串都一次性被替换。这可以用于在代理前重写主机,或对 URI 进行复杂修改,例如在路径和查询字符串之间移动部分。另请参阅“set-path”和“set-query”。 - “set-nice”设置当前正在处理的请求的“nice”因子。它只对同时处理的其他请求产生影响。默认值为 0,除非被“bind”行上的“nice”设置更改。接受的范围是 -1024..1024。值越高,请求就越“友好”。较低的值会使请求比其他请求更重要。这可以用于提高某些请求的速度,或降低不重要请求的优先级。在没有事先实验的情况下使用此设置可能会导致一些重大的性能下降。 - “set-log-level”用于在满足某个条件时更改当前请求的日志级别。有效级别是 8 个 syslog 级别(参见“log”关键字)加上特殊级别“silent”,它会禁用此请求的日志记录。此规则不是最终规则,因此最后一个匹配的规则获胜。此规则可用于禁用来自其他设备的健康检查。 - “set-tos”用于在支持此功能的平台上,将发送给客户端的数据包的 TOS 或 DSCP 字段值设置为在 <tos> 中传递的值。此值表示整个 8 位的 IP TOS 字段,可以用十进制或十六进制格式(以“0x”为前缀)表示。请注意,在 DSCP 或 TOS 中只使用较高的 6 位,而较低的两位始终为 0。这可以用于根据请求中的某些信息调整边界路由器上的一些路由行为。有关更多信息,请参阅 RFC 2474、2597、3260 和 4594。 - “set-mark”用于在支持此功能的平台上,将发送给客户端的所有数据包的 Netfilter MARK 设置为在 <mark> 中传递的值。此值是一个无符号 32 位值,可由 netfilter 和路由表匹配。它可以用十进制或十六进制格式(以“0x”为前缀)表示。这可用于强制某些数据包走不同的路由(例如,对于批量下载使用更便宜的网络路径)。这适用于 Linux 内核 2.6.32 及更高版本,并需要管理员权限。 - “add-acl”用于向 ACL 添加新条目。ACL 必须从文件中加载(即使是虚拟的空文件)。要更新的 ACL 的文件名在括号之间传递。它接受一个参数:<key fmt>,它遵循日志格式规则,用于收集新条目的内容。它在插入前在 ACL 中进行查找,以避免重复(或更多)的值。此查找通过线性搜索完成,对于大型列表可能会很昂贵!它等同于 stats 套接字中的“add acl”命令,但可以由 HTTP 请求触发。 - “del-acl”用于从 ACL 中删除一个条目。ACL 必须从文件中加载(即使是虚拟的空文件)。要更新的 ACL 的文件名在括号之间传递。它接受一个参数:<key fmt>,它遵循日志格式规则,用于收集要删除的条目的内容。它等同于 stats 套接字中的“del acl”命令,但可以由 HTTP 请求触发。 - “del-map”用于从 MAP 中删除一个条目。MAP 必须从文件中加载(即使是虚拟的空文件)。要更新的 MAP 的文件名在括号之间传递。它接受一个参数:<key fmt>,它遵循日志格式规则,用于收集要删除的条目的内容。它接受一个参数:“文件名”它等同于 stats 套接字中的“del map”命令,但可以由 HTTP 请求触发。 - “set-map”用于向 MAP 添加新条目。MAP 必须从文件中加载(即使是虚拟的空文件)。要更新的 MAP 的文件名在括号之间传递。它接受 2 个参数:<key fmt>,它遵循日志格式规则,用于收集 MAP 键;<value fmt>,它遵循日志格式规则,用于收集新条目的内容。它在插入前在 MAP 中进行查找,以避免重复(或更多)的值。此查找通过线性搜索完成,对于大型列表可能会很昂贵!它等同于 stats 套接字中的“set map”命令,但可以由 HTTP 请求触发。 - capture <sample> [ len <length> | id <id> ] : 从请求缓冲区捕获样本表达式 <sample>,并将其转换为最多 <len> 个字符的字符串。生成的字符串存储在下一个请求的“capture”槽中,因此它可能会出现在一些捕获的 HTTP 头旁边。然后它会自动出现在日志中,并且可以使用样本获取规则提取它以将其提供给头或其他任何东西。长度应该受到限制,因为在整个会话生命周期中,此大小将为每次捕获分配。请查看第 7.3 节(获取样本)和“捕获请求头”以获取更多信息。如果使用关键字“id”而不是“len”,则操作会尝试将捕获的字符串存储在先前声明的捕获槽中。这在后端运行捕获时很有用。槽 ID 可以由先前的指令“http-request capture”或“declare capture”关键字声明。在后端使用此操作时,请仔细检查相关的前端是否具有所需的捕获槽,否则此规则将在运行时被忽略。由于 HAProxy 能够在运行时动态解析后端名称,因此在配置解析时无法检测到这一点。 - { track-sc0 | track-sc1 | track-sc2 } <key> [table <table>] : 启用从当前请求跟踪粘性计数器。这些规则不会停止评估,也不会更改默认操作。同一连接可同时跟踪的计数器数量在构建时在 MAX_SESS_STKCTR 中设置(在 haproxy -vv 中报告),默认为 3,因此 track-sc 的数量在 0 和 (MAX_SESS_STCKTR-1) 之间。执行的第一个“track-sc0”规则启用对指定表的计数器作为第一组进行跟踪。执行的第一个“track-sc1”规则启用对指定表的计数器作为第二组进行跟踪。执行的第一个“track-sc2”规则启用对指定表的计数器作为第三组进行跟踪。建议的做法是使用第一组计数器用于每个前端的计数器,第二组用于每个后端的计数器。但这只是一个指导方针,所有计数器都可以在任何地方使用。这些操作接受一个或两个参数:<key> 是强制性的,并且是第 7.3 节中描述的样本表达式规则。它描述了将分析、提取、组合和使用传入请求或连接的哪些元素,以选择要更新哪个表条目的计数器。<table> 是一个可选的表,用于替代默认表,即当前代理中声明的粘性表。然后,键的所有匹配和更新的计数器都将在该表中执行,直到会话结束。一旦执行了“track-sc*”规则,就会在表中查找该键,如果未找到,则为其分配一个条目。然后在整个会话生命周期中保留指向该条目的指针,并且该条目的计数器会尽可能频繁地更新,每次会话的计数器更新时,以及在会话结束时系统地更新。计数器仅针对跟踪开始后发生的事件进行更新。作为一个例外,连接计数器和请求计数器会系统地更新,以便它们反映有用的信息。如果条目跟踪并发连接计数器,只要条目被跟踪,就会计算一个连接,并且在该时间内条目不会过期。跟踪计数器还提供了比仅仅检查键更高的性能优势,因为对于所有使用它的 ACL 检查,只执行一次表查找。 - sc-set-gpt0(<sc-id>) <int> : 此操作根据由 <sc-id> 指定的粘性计数器和 <int> 的值设置 GPT0 标记。预期的结果是一个布尔值。如果发生错误,此操作会静默失败,并继续评估操作。 - sc-inc-gpc0(<sc-id>): 此操作根据由 <sc-id> 指定的粘性计数器递增 GPC0 计数器。如果发生错误,此操作会静默失败,并继续评估操作。 - set-var(<var-name>) <expr> : 用于设置变量的内容。变量是内联声明的。<var-name> 变量的名称以其作用域的指示开始。允许的作用域是:“sess”:变量在整个会话中共享 “txn”:变量在事务(请求和响应)中共享 “req”:变量仅在请求处理期间共享 “res”:变量仅在响应处理期间共享 此前缀后跟一个名称。分隔符是“.”。名称只能包含字符“a-z”、“A-Z”、“0-9”和“_”。<expr> 是一个标准的 HAProxy 表达式,由样本获取后跟一些转换器组成。
http-request set-var(req.my_var) req.fhdr(user-agent),lower
- set-src <expr> : 用于将源 IP 地址设置为指定表达式的值。当 HAProxy 前面的代理重写了源 IP,但在 HTTP 头中提供了正确的 IP 时,或者您想为了隐私而屏蔽源 IP 时,这很有用。<expr> 是一个标准的 HAProxy 表达式,由样本获取后跟一些转换器组成。
http-request set-src hdr(x-forwarded-for) http-request set-src src,ipmask(24)
当 set-src 成功时,源端口设置为 0。 - “silent-drop”:停止规则评估,并使用一种系统相关的方式使面向客户端的连接突然消失,该方式试图阻止客户端被通知。其效果是客户端仍然看到一个已建立的连接,而 HAProxy 上则没有。其目的是实现与“tarpit”类似的效果,只是它在运行 HAProxy 的机器上完全不使用任何本地资源。它可以承受比“tarpit”高得多的负载,并减慢更强大的攻击者的速度。重要的是要理解使用此机制的影响。放置在客户端和 HAProxy 之间的所有有状态设备(防火墙、代理、负载均衡器)也将长时间保持已建立的连接,并可能因此操作而受到影响。在具有足够权限的现代 Linux 系统上,使用 TCP_REPAIR 套接字选项来阻止 TCP 重置的发送。在其他系统上,套接字的 TTL 会减少到 1,以便 TCP 重置不会通过第一个路由器,尽管它仍然会传送到本地网络。除非您完全理解其工作原理,否则不要使用它。 每个实例的 http-request 语句数量没有限制。重要的是要知道,http-request 规则在 HTTP 处理的早期阶段处理,紧接在“block”规则之后,在“reqdel”或“reqrep”或“reqadd”规则之前。这样,“add-header”/“set-header”添加的头对于几乎所有后续的 ACL 规则都是可见的。在较新版本(>= 1.5)中不鼓励使用“reqadd”/“reqdel”/“reqrep”来操作请求头。但如果需要使用正则表达式来删除头,仍然可以使用“reqdel”。另外,请使用“http-request deny/allow/tarpit”而不是“reqdeny”/“reqpass”/“reqtarpit”。
acl nagios src 192.168.129.3 acl local_net src 192.168.0.0/16 acl auth_ok http_auth(L1) http-request allow if nagios http-request allow if local_net auth_ok http-request auth realm Gimme if local_net auth_ok http-request deny
acl auth_ok http_auth_group(L1) G1 http-request auth unless auth_ok
http-request set-header X-Haproxy-Current-Date %T http-request set-header X-SSL %[ssl_fc] http-request set-header X-SSL-Session_ID %[ssl_fc_session_id,hex] http-request set-header X-SSL-Client-Verify %[ssl_c_verify] http-request set-header X-SSL-Client-DN %{+Q}[ssl_c_s_dn] http-request set-header X-SSL-Client-CN %{+Q}[ssl_c_s_dn(cn)] http-request set-header X-SSL-Issuer %{+Q}[ssl_c_i_dn] http-request set-header X-SSL-Client-NotBefore %{+Q}[ssl_c_notbefore] http-request set-header X-SSL-Client-NotAfter %{+Q}[ssl_c_notafter]
acl key req.hdr(X-Add-Acl-Key) -m found acl add path /addacl acl del path /delacl acl myhost hdr(Host) -f myhost.lst http-request add-acl(myhost.lst) %[req.hdr(X-Add-Acl-Key)] if key add http-request del-acl(myhost.lst) %[req.hdr(X-Add-Acl-Key)] if key del
acl value req.hdr(X-Value) -m found acl setmap path /setmap acl delmap path /delmap use_backend bk_appli if { hdr(Host),map_str(map.lst) -m found } http-request set-map(map.lst) %[src] %[req.hdr(X-Value)] if setmap value http-request del-map(map.lst) %[src] if delmap
第 7 层响应的访问控制
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 是![]() |
http-response 语句定义了一组应用于第 7 层处理的规则。在 frontend、listen 或 backend 部分遇到这些规则时,会按照声明的顺序对其进行评估。任何规则后面都可以选择性地跟一个基于 ACL 的条件,这种情况下,只有当条件为真时,规则才会被评估。由于这些规则应用于响应,因此 backend 的规则会首先应用,然后是 frontend 的规则。第一个关键字是规则的操作。目前支持的操作包括: - "allow":停止规则的评估,并让响应通过检查。当前部分不再评估任何 "http-response" 规则。 - "deny":停止规则的评估,并立即拒绝响应,发出 HTTP 502 错误。不再评估任何 "http-response" 规则。 - "add-header" 追加一个 HTTP 头部字段,其名称由 <name> 指定,其值由 <fmt> 定义,遵循日志格式规则(参见第 8.2.4 节中的自定义日志格式)。例如,这可以用于向客户端发送 cookie,或者传递一些内部信息。此规则不是最终规则,因此可以添加其他类似的规则。请注意,头部添加是立即执行的,因此一条规则可能会重用前一条规则产生的头部。 - "set-header" 的作用与 "add-header" 相同,只是如果头部名称已存在,会先将其删除。这在向服务器传递安全信息时很有用,因为该头部不能被外部用户操纵。 - "del-header" 删除所有名称由 <name> 指定的 HTTP 头部字段。 - "replace-header" 根据 <match-regex> 匹配头部字段 <name> 中的所有正则表达式出现,并用 <replace-fmt> 参数替换它们。<replace-fmt> 中允许使用格式字符,其工作方式与 "add-header" 中的 <fmt> 参数类似。匹配是区分大小写的。重要的是要理解,此操作只考虑整个头部行,无论它们可能包含多少个值。这种用法适用于值中自然包含逗号的头部,例如 Set-Cookie、Expires 等。
http-response replace-header Set-Cookie (C=[^;]*);(.*) \1;ip=%bi;\2
应用于:Set-Cookie: C=1; expires=Tue, 14-Jun-2016 01:40:45 GMT 输出:Set-Cookie: C=1;ip=192.168.1.20; expires=Tue, 14-Jun-2016 01:40:45 GMT 假设后端 IP 是 192.168.1.20。 - "replace-value" 的工作方式与 "replace-header" 类似,不同之处在于它针对头部字段 <name> 的每个逗号分隔的值匹配正则表达式,而不是整个头部。这适用于所有允许携带多个值的头部。一个例子可以是 Accept 头部。
http-response replace-value Cache-control ^public$ private
应用于:Cache-Control: max-age=3600, public 输出:Cache-Control: max-age=3600, private - "set-status" 将响应状态码替换为 <status>,该值必须是介于 100 和 999 之间的整数。请注意,原因会自动适应新的状态码。
# 返回 "431 Request Header Fields Too Large" http-response set-status 431
- "set-nice" 设置当前正在处理的请求的 "nice" 因子。它只对同时处理的其他请求产生影响。默认值为 0,除非被 "bind" 行上的 "nice" 设置更改。接受的范围是 -1024..1024。值越高,请求就越“友好”(优先级越低)。较低的值将使请求比其他请求更重要。这可以用于提高某些请求的速度,或降低不重要请求的优先级。未经事先实验使用此设置可能会导致严重的性能下降。 - "set-log-level" 用于在满足特定条件时更改当前请求的日志级别。有效级别是 8 个 syslog 级别(参见 "log" 关键字)加上特殊级别 "silent",该级别会禁用此请求的日志记录。此规则不是最终规则,因此最后一个匹配的规则生效。此规则可用于禁用来自其他设备的健康检查。 - "set-tos" 用于在支持此功能的平台上,将发送给客户端的数据包的 TOS 或 DSCP 字段值设置为在 <tos> 中传递的值。此值表示 IP TOS 字段的全部 8 位,可以用十进制或十六进制格式(以 "0x" 为前缀)表示。请注意,DSCP 或 TOS 中只使用较高的 6 位,而较低的两位始终为 0。这可以用于根据请求中的某些信息调整边界路由器上的一些路由行为。更多信息请参见 RFC 2474、2597、3260 和 4594。 - "set-mark" 用于在支持此功能的平台上,将发送给客户端的所有数据包的 Netfilter MARK 设置为在 <mark> 中传递的值。此值是一个无符号的 32 位值,可以被 netfilter 和路由表匹配。它可以用十进制或十六进制格式(以 "0x" 为前缀)表示。这可以用于强制某些数据包采用不同的路由(例如,为批量下载选择更便宜的网络路径)。这在 Linux 内核 2.6.32 及以上版本上有效,并需要管理员权限。 - "add-acl" 用于向 ACL 添加新条目。ACL 必须从文件中加载(即使是空的虚拟文件)。要更新的 ACL 的文件名在括号之间传递。它接受一个参数:<key fmt>,该参数遵循日志格式规则,用于收集新条目的内容。它在插入前会先在 ACL 中进行查找,以避免重复(或多个)值。此查找是通过线性搜索完成的,对于大型列表可能会很耗时!它等同于来自 stats 套接字的 "add acl" 命令,但可以由 HTTP 响应触发。 - "del-acl" 用于从 ACL 中删除一个条目。ACL 必须从文件中加载(即使是空的虚拟文件)。要更新的 ACL 的文件名在括号之间传递。它接受一个参数:<key fmt>,该参数遵循日志格式规则,用于收集要删除的条目的内容。它等同于来自 stats 套接字的 "del acl" 命令,但可以由 HTTP 响应触发。 - "del-map" 用于从 MAP 中删除一个条目。MAP 必须从文件中加载(即使是空的虚拟文件)。要更新的 MAP 的文件名在括号之间传递。它接受一个参数:<key fmt>,该参数遵循日志格式规则,用于收集要删除的条目的内容。它等同于来自 stats 套接字的 "del map" 命令,但可以由 HTTP 响应触发。 - "set-map" 用于向 MAP 中添加一个新条目。MAP 必须从文件中加载(即使是空的虚拟文件)。要更新的 MAP 的文件名在括号之间传递。它接受 2 个参数:<key fmt>,遵循日志格式规则,用于收集 MAP 键;以及 <value fmt>,遵循日志格式规则,用于收集新条目的内容。它在插入前会先在 MAP 中进行查找,以避免重复(或多个)值。此查找是通过线性搜索完成的,对于大型列表可能会很耗时!它等同于来自 stats 套接字的 "set map" 命令,但可以由 HTTP 响应触发。 - capture <sample> id <id> : 从响应缓冲区中捕获样本表达式 <sample>,并将其转换为字符串。生成的字符串存储到下一个请求的 "capture" 槽中,因此它可能会出现在一些捕获的 HTTP 头部旁边。然后它会自动出现在日志中,并且可以使用样本提取规则将其提取出来,以馈送到头部或任何其他地方。请查看第 7.3 节(提取样本)和“捕获响应头部”以获取更多信息。关键字 "id" 是用于存储字符串的捕获槽的 ID。捕获槽必须在关联的 frontend 中定义。这对于在后端运行捕获很有用。槽 ID 可以由之前的 "http-response capture" 指令声明,或使用 "declare capture" 关键字。在后端使用此操作时,请仔细检查相关的 frontend 是否具有所需的捕获槽,否则此规则将在运行时被忽略。由于 HAProxy 能够在运行时动态解析后端名称,因此在配置解析时无法检测到此问题。 - "redirect":此操作基于重定向规则执行 HTTP 重定向。它支持类似于 "http-request redirect" 规则的格式字符串,但有一个例外,即在响应上只可能进行 "location" 类型的重定向。有关规则的语法,请参见 "redirect" 关键字。在响应期间应用重定向规则时,与服务器的连接将被关闭,以便无法将任何数据从服务器转发到客户端。 - set-var(<var-name>) expr:用于设置变量的内容。变量是内联声明的。<var-name> 变量的名称以一个关于其作用域的指示开始。允许的作用域是: "sess":变量在整个会话中共享 "txn":变量在事务(请求和响应)中共享 "req":变量仅在请求处理期间共享 "res":变量仅在响应处理期间共享 此前缀后跟一个名称。分隔符是“.”。名称只能包含字符 'a-z'、'A-Z'、'0-9' 和 '_'。 <expr> 是一个标准的 HAProxy 表达式,由一个样本提取后跟一些转换器组成。
http-response set-var(sess.last_redir) res.hdr(location)
- sc-set-gpt0(<sc-id>) <int> : 此操作根据由 <sc-id> 指定的粘性计数器和 <int> 的值设置 GPT0 标记。预期的结果是一个布尔值。如果发生错误,此操作将静默失败,并且操作评估将继续。 - sc-inc-gpc0(<sc-id>):此操作根据由 <sc-id> 指定的粘性计数器递增 GPC0 计数器。如果发生错误,此操作将静默失败,并且操作评估将继续。 - "silent-drop":停止规则的评估,并使用一种系统相关的方式使面向客户端的连接突然消失,该方式试图阻止客户端被通知。其效果是客户端仍然看到一个已建立的连接,而在 HAProxy 上则没有。目的是实现与 "tarpit" 相当的效果,只不过它完全不使用运行 HAProxy 的机器上的任何本地资源。它可以抵抗比 "tarpit" 高得多的负载,并减慢更强大的攻击者的速度。理解使用此机制的影响很重要。放置在客户端和 HAProxy 之间的所有有状态设备(防火墙、代理、负载均衡器)也将长时间保持已建立的连接,并可能因此操作而受到影响。在具有足够权限的现代 Linux 系统上,TCP_REPAIR 套接字选项用于阻止 TCP 重置的发送。在其他系统上,套接字的 TTL 会减少到 1,以便 TCP 重置不会通过第一个路由器,尽管它仍然会传递到本地网络。除非你完全理解其工作原理,否则不要使用它。 每个实例的 http-response 语句数量没有限制。重要的是要知道 http-response 规则在 HTTP 处理的非常早期阶段进行处理,在 "rspdel"、"rsprep" 或 "rspadd" 规则之前。这样,由 "add-header"/"set-header" 添加的头部对于几乎所有后续的 ACL 规则都是可见的。在较新版本(>= 1.5)中,不鼓励使用 "rspadd"/"rspdel"/"rsprep" 来操作请求头。但如果需要使用正则表达式来删除头部,仍然可以使用 "rspdel"。另外,请使用 "http-response deny" 而不是 "rspdeny"。
acl key_acl res.hdr(X-Acl-Key) -m found acl myhost hdr(Host) -f myhost.lst http-response add-acl(myhost.lst) %[res.hdr(X-Acl-Key)] if key_acl http-response del-acl(myhost.lst) %[res.hdr(X-Acl-Key)] if key_acl
acl value res.hdr(X-Value) -m found use_backend bk_appli if { hdr(Host),map_str(map.lst) -m found } http-response set-map(map.lst) %[src] %[res.hdr(X-Value)] if value http-response del-map(map.lst) %[src] if ! value
声明空闲的 HTTP 连接如何在请求之间共享
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
默认情况下,HAProxy 和后端服务器之间建立的连接属于发起它的会话。缺点是在响应和下一个请求之间,连接保持空闲且未被使用。在许多情况下,出于性能原因,希望能够重用这些空闲连接来服务来自不同会话的其他请求。该指令允许调整此行为。参数指示所需的连接重用策略: - "never":空闲连接永远不会在会话之间共享。这是默认选择。可以强制使用此选项来取消从 defaults 部分继承的不同策略,或用于故障排除。例如,如果某个旧的错误应用程序认为同一连接上的多个请求来自同一个客户端,并且无法修复该应用程序,则可能需要在单个后端中禁用连接共享。此类应用程序的一个例子可能是在隧道模式下使用 cookie 插入且不检查第一个请求之后的任何请求的旧版 HAProxy。 - "safe":这是推荐的策略。会话的第一个请求总是通过其自己的连接发送,只有后续的请求可能会被分派到其他现有连接上。这确保了在发送请求时如果服务器关闭连接,浏览器可以决定静默重试。由于它与常规的 keep-alive 完全等效,因此不应有任何副作用。 - "aggressive":此模式在 Web 服务环境中可能很有用,其中并非所有服务器都已知,并且希望将大多数第一个请求通过现有连接传递。在这种情况下,第一个请求仅通过已至少重用过一次的现有连接传递,证明服务器正确支持连接重用。只有在确定客户端可以偶尔重试失败的请求,并且积极连接重用的好处明显超过罕见连接失败的缺点时,才应使用此模式。 - "always":此模式仅在已知到服务器的路径在释放现有连接后不会很快断开时推荐使用。它允许会话的第一个请求发送到现有连接。当后端是缓存服务器群时,这可以提供显著的性能提升,因为这类组件倾向于表现出一致的行为,并将从连接共享中受益。建议在此模式下保持 "http-keep-alive" 超时值较低,以使没有死连接保持可用。在大多数情况下,这将导致与 "aggressive" 相同的性能增益,但风险更大。只有当它比 "aggressive" 模式能改善情况时才应使用。 当启用 HTTP 连接共享时,会特别注意尊重连接属性和兼容性。具体来说: - 使用 "usesrc" 后跟客户端相关值("client"、"clientip"、"hdr_ip")建立的连接被标记为私有,永不共享; - 发送到带有 TLS SNI 扩展的服务器的连接被标记为私有,永不共享; - 接收到状态码 401 或 407 的连接期望返回时发送一些身份验证信息。由于某些错误的身份验证方案(如 NTLM)依赖于连接,这些连接被标记为私有,永不共享; 不涉及连接池,一旦会话死亡,它所附加的最后一个空闲连接将同时被删除。这确保了连接在所有会话关闭后不会持续存在。 注意:连接重用提高了 "server maxconn" 设置的准确性,因为在空闲连接仍然可用时,几乎不会建立新的连接。这在使用 "always" 策略时尤其如此。
将服务器名称添加到请求中。使用由 <header> 给出的头字符串。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
<header> 用于发送服务器名称的头字符串。
"http-send-name-header" 语句会将目标服务器的名称添加到 HTTP 请求的头信息中。该名称是使用提供的头字符串添加的。
为代理设置一个持久 ID。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 是![]() |
为代理设置一个持久 ID。此 ID 必须是唯一的正数。如果未设置,将自动分配一个未使用的 ID。第一个分配的值将是 1。此 ID 当前仅在统计信息中返回。
声明一个忽略持久性的条件
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 否![]() | 是![]() | 是![]() |
默认情况下,当启用 cookie 持久性时,每个包含该 cookie 的请求都是无条件持久的(假设目标服务器正常运行)。"ignore-persist" 语句允许声明各种基于 ACL 的条件,当满足这些条件时,请求将忽略持久性。这有时对于负载均衡静态文件的请求很有用,因为这些文件通常不需要持久性。这也可以用于完全禁用特定 User-Agent 的持久性(例如,某些网络爬虫机器人)。 当 "if" 条件满足时,或者除非 "unless" 条件满足时,持久性将被忽略。
acl url_static path_beg /static /images /img /css acl url_static path_end .gif .png .jpg .css .js ignore-persist if url_static
允许 HAProxy 的无缝重载
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
此指令将 HAProxy 指向一个文件,该文件保存了之前运行进程的服务器状态。这样,在启动时,处理流量之前,新进程可以像没有发生重载一样将旧状态应用于服务器。"load-server-state-from-file" 指令的目的是告诉 HAProxy 使用哪个文件。目前,只有 2 个参数,可以防止加载状态,或者从包含所有后端和服务器的文件中加载状态。状态文件可以通过在 stats 套接字上运行 "show servers state" 命令并重定向输出来生成。该文件的格式是版本化的并且非常特定。要理解它,请阅读 "show servers state" 命令的文档(管理指南的第 9.2 章)。
global 加载由名为 "server-state-file" 的全局指令指向的文件的内容。 local 如果设置了 "server-state-file-name" 指令,则加载其指向的文件的内容。如果未设置,则使用后端名称作为文件名。 none 不为此后端加载任何状态
注意: - 除非在服务器上启用了 DNS 解析,否则服务器的 IP 地址不会更新。这意味着,如果服务器 IP 地址已通过 stat 套接字更改,则该信息在重载后不会被重新应用。 - 除非在新旧配置文件之间发生了变化,否则将应用前一个运行进程的服务器权重。
最小配置global stats socket /tmp/socket server-state-file /tmp/server_state defaults load-server-state-from-file global backend bk server s1 127.0.0.1:22 check weight 11 server s2 127.0.0.1:22 check weight 12
然后可以运行: socat /tmp/socket - <<< "show servers state" > /tmp/server_state 文件 /tmp/server_state 的内容将如下所示: 1 # <文档示例中省略了字段名称> 1 bk 1 s1 127.0.0.1 2 0 11 11 4 6 3 4 6 0 0 1 bk 2 s2 127.0.0.1 2 0 12 12 4 6 3 4 6 0 0
最小配置global stats socket /tmp/socket server-state-base /etc/haproxy/states defaults load-server-state-from-file local backend bk server s1 127.0.0.1:22 check weight 11 server s2 127.0.0.1:22 check weight 12
然后可以运行: socat /tmp/socket - <<< "show servers state bk" > /etc/haproxy/states/bk 文件 /etc/haproxy/states/bk 的内容将如下所示: 1 # <文档示例中省略了字段名称> 1 bk 1 s1 127.0.0.1 2 0 11 11 4 6 3 4 6 0 0 1 bk 2 s2 127.0.0.1 2 0 12 12 4 6 3 4 6 0 0
启用事件和流量的每个实例日志记录。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
前缀:当必须清除记录器列表时,应使用 no。例如,如果您不想从默认记录器列表继承。此前缀不允许有参数。
global 应在实例的日志记录参数与全局参数相同时使用。这是最常见的用法。"global" 用 "global" 部分中找到的日志条目的 <address>、<facility> 和 <level> 替换它们。每个实例只能使用一个 "log global" 语句,并且此形式不带其他参数。 <address> 指示日志发送到何处。它采用与 "global" 部分日志相同的格式,可以是以下之一: - 一个 IPv4 地址,可选地后跟一个冒号(':')和一个 UDP 端口。如果未指定端口,则默认使用 514(标准 syslog 端口)。 - 一个 IPv6 地址,后跟一个冒号(':')和一个可选的 UDP 端口。如果未指定端口,则默认使用 514(标准 syslog 端口)。 - 一个指向 UNIX 域套接字的文件系统路径,同时要考虑 chroot(确保路径在 chroot 内可访问)和 uid/gid(确保路径具有适当的写权限)。您可能希望在地址参数中引用一些环境变量,请参阅关于环境变量的第 2.3 节。 <length> 是一个可选的最大行长度。大于此值的日志行在发送前将被截断。原因是 syslog 服务器对日志行长度的处理方式不同。所有服务器都支持默认值 1024,但某些服务器会直接丢弃更长的行,而其他服务器则会记录它们。如果服务器支持长行,那么在此处设置此值以避免截断长行可能是有意义的。同样,如果服务器会丢弃长行,那么在发送之前将其截断是更可取的。接受的值为 80 到 65535(含)。对于所有标准用法,默认值 1024 通常是合适的。某些长捕获或 JSON 格式日志的特定情况可能需要更大的值。 <facility> 必须是 24 个标准 syslog facility 之一: kern user mail daemon auth syslog lpr news uucp cron auth2 ftp ntp audit alert cron2 local0 local1 local2 local3 local4 local5 local6 local7 <level> 是可选的,可以指定用于过滤传出消息。默认情况下,所有消息都会被发送。如果指定了级别,则只有严重性至少与此级别一样重要的消息才会被发送。可以指定一个可选的最低级别。如果设置了它,那么比此级别更严重级别发出的日志将被限制到此级别。这用于避免在某些默认 syslog 配置下向所有终端发送 "emerg" 消息。已知有八个级别: emerg alert crit err warning notice info debug
重要的是要记住,是由前端决定要从连接中记录什么,并且在内容切换的情况下,来自后端的日志条目将被忽略。连接以 "info" 级别记录。然而,后端日志声明定义了服务器状态更改将如何以及在何处被记录。级别 "notice" 将用于指示服务器启动,"warning" 将用于终止信号和最终的服务终止,而 "alert" 将用于服务器宕机时。 注意:根据 RFC3164,消息在发出前会被截断为 1024 字节。
log global log 127.0.0.1:514 local0 notice # 只发送重要事件 log 127.0.0.1:514 local0 notice notice # 相同但限制输出级别 log "${LOCAL_SYSLOG}:514" local0 notice # 发送到本地服务器
指定用于流量日志的日志格式字符串
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 否![]() |
此指令指定了将用于所有通过此行所在前端的流量产生的日志的日志格式字符串。如果在 defaults 部分使用此指令,所有后续的前端都将使用相同的日志格式。请参阅深入介绍日志格式字符串的第 8.2.4 节。"log-format" 指令会覆盖之前的 "option tcplog"、"log-format" 和 "option httplog" 指令。
指定 RFC5424 结构化数据日志格式字符串
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 否![]() |
此指令指定了 RFC5424 结构化数据日志格式字符串,该字符串将用于所有通过此行所在前端的流量产生的日志。如果在 defaults 部分使用此指令,所有后续的前端都将使用相同的日志格式。请参阅深入介绍日志格式字符串的第 8.2.4 节。有关 RFC5424 结构化数据部分的更多信息,请参阅 https://tools.ietf.org/html/rfc5424#section-6.3。 注意:此日志格式字符串仅用于将日志格式设置为 "rfc5424" 的记录器。
log-format-sd [exampleSDID@1234\ bytes=\"%B\"\ status=\"%ST\"]
指定用于所有传出日志的日志标签
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
将 syslog 头中的标签字段设置为此字符串。它默认为全局部分中设置的 log-tag,否则为从命令行启动的程序名称,通常是 "haproxy"。有时,区分在同一主机上运行的多个进程,或者区分在同一进程中运行的客户实例可能会很有用。在后端,关于服务器启动/关闭的日志将使用此标签。作为提示,可以在 defaults 部分中设置一个与托管客户相关的 log-tag,然后将该客户的所有前端和后端放在该部分下,然后在新的 defaults 部分中启动另一个客户。另请参见全局 "log-tag" 指令。设置用于维护 keep-alive 连接的最大服务器队列大小
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
HTTP keep-alive 试图尽可能重用同一个服务器连接,但有时这可能会适得其反,例如,如果一个服务器有大量连接,而其他服务器则处于空闲状态。对于静态服务器尤其如此。此设置的目的是设置一个排队连接数的阈值,当达到该阈值时,haproxy 将停止尝试重用同一个服务器,而倾向于寻找另一个服务器。默认值 -1 表示没有限制。值为零意味着 keep-alive 请求将永远不会排队。对于可以通过低延迟访问的非常近的服务器,并且这些服务器对中断 keep-alive 不敏感,建议使用一个较低的值(例如:本地静态服务器可以使用 10 或更小的值)。对于延迟较高的远程服务器,可能需要更高的值来弥补延迟和/或选择不同服务器的成本。请注意,这对因 401 响应而连续保持到同一服务器的响应没有影响。即使需要排队,它们仍将发送到同一服务器。
固定前端的最大并发连接数
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 否![]() |
<conns> 是前端将接受服务的最大并发连接数。超出的连接将由系统在套接字的侦听队列中排队,并在一个连接关闭后得到服务。
如果系统支持,对于大型网站来说,将此限制设置得非常高可能很有用,这样 haproxy 就可以管理连接队列,而不是让客户端面临未应答的连接尝试。此值不应超过全局 maxconn。此外,请记住,一个连接包含两个 tune.bufsize(默认为 16kB)的缓冲区,以及一些其他数据,导致每个已建立的连接消耗约 33 kB 的 RAM。这意味着,一个配备 1GB RAM 的中型系统,如果经过适当调优,可以承受大约 20000-25000 个并发连接。此外,当 <conns> 设置为较大值时,服务器的规模可能无法接受如此大的负载,因此,为它们分配一些合理的连接限制通常是明智的。默认情况下,此值设置为 2000。
设置实例的运行模式或协议
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
tcp 实例将以纯 TCP 模式工作。客户端和服务器之间将建立全双工连接,并且不会执行第 7 层检查。这是默认模式。它应该用于 SSL、SSH、SMTP 等。 http 实例将以 HTTP 模式工作。在连接到任何服务器之前,客户端请求将被深入分析。任何不符合 RFC 规范的请求都将被拒绝。第 7 层的过滤、处理和切换将成为可能。这种模式为 HAProxy 带来了其大部分价值。 health 实例将以“健康”模式工作。它只会对传入的连接回复“OK”并关闭连接。或者,如果设置了 "httpchk" 选项,则将发送“HTTP/1.0 200 OK”。在这两种情况下都不会记录任何内容。此模式用于响应外部组件的健康检查。此模式已弃用,不应再使用,因为可以通过将 TCP 或 HTTP 模式与 "monitor" 关键字相结合来做同样甚至更好的事情。
在进行内容切换时,前端和后端必须处于相同的模式(通常是 HTTP),否则配置将被拒绝。
defaults http_instances mode http
添加一个条件以向监控 HTTP 请求报告失败。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 否![]() |
if <cond> 如果条件满足,监控请求将失败,否则将成功。该条件应描述一个组合测试,如果所有条件都满足,则必须导致失败,例如后端及其备份中的服务器数量都很少。 unless <cond> 只有当条件满足时,监控请求才会成功,否则将失败。这样的条件可以基于对后端列表中最小活动服务器数量的存在的测试。
此语句添加了一个条件,可以强制对监视请求的响应报告失败。默认情况下,当外部组件查询专用于监视的 URI 时,会返回 200 响应。当满足上述条件之一时,haproxy 将返回 503 而不是 200。这对于向外部组件报告站点故障非常有用,该组件可能会根据 haproxy 报告的可用性来决定多个站点之间的路由通告。在这种情况下,人们会依赖一个涉及 "nbsrv" 标准的 ACL。请注意,"monitor fail" 仅在 HTTP 模式下工作。如果需要,可以使用 "errorfile" 或 "errorloc" 来调整两种状态消息。
frontend www mode http acl site_dead nbsrv(dynamic) lt 2 acl site_dead nbsrv(static) lt 2 monitor-uri /site_alive monitor fail if site_dead
声明一个仅限于监控请求的源网络
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 否![]() |
<source> 是源 IPv4 地址或网络,该网络只能对任何请求获取监控响应。它可以是 IPv4 地址、主机名或后跟斜杠('/')和掩码的地址。
在 TCP 模式下,任何来自匹配 <source> 的源的连接都将导致连接立即关闭,且不记录任何日志。这允许另一个设备探测端口并验证它是否仍在侦听,而无需将连接转发到远程服务器。 在 HTTP 模式下,来自匹配 <source> 的源的连接将被接受,将发送以下响应而不等待请求,然后连接将被关闭:“HTTP/1.0 200 OK”。这对于任何前端 HTTP 探针来说,通常足以检测到服务已启动并运行,而无需将请求转发到后端服务器。请注意,此响应是以原始格式发送的,没有任何转换。这很重要,因为它意味着它不会在 SSL 侦听器上进行 SSL 加密。 监控请求在非常早期处理,仅在能够阻止它们的 tcp-request 连接 ACL 之后。这些连接是短暂的,从不等待来自客户端的任何数据。它们无法被记录,这是其预定目的。它们仅用于向更高层组件报告 HAProxy 的健康状况,仅此而已。 请注意,“monitor fail”规则不适用于被“monitor-net”拦截的连接。 最后,请注意,在一个前端中只能指定一个“monitor-net”语句。如果找到多个,则只考虑最后一个。
# 地址 .252 和 .253 只是在探测我们。 frontend www monitor-net 192.168.0.252/31
拦截外部组件监控请求使用的 URI
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 否![]() |
<uri> 是我们想要拦截以返回 HAProxy 健康状态而不是转发请求的确切 URI。
当在前端收到引用 <uri> 的 HTTP 请求时,HAProxy 不会转发它,也不会记录它,而是会根据用 "monitor fail" 定义的失败条件返回 "HTTP/1.0 200 OK" 或 "HTTP/1.0 503 Service unavailable"。这对于任何前端 HTTP 探针来说通常足以检测服务是否启动并运行,而无需将请求转发到后端服务器。请注意,HTTP 方法、版本和所有头信息都会被忽略,但请求必须至少在 HTTP 级别上是有效的。此关键字只能与 HTTP 模式的前端一起使用。 监控请求的处理非常早。无法使用 ACL 阻止或转移它们。它们也无法被记录,这是其预定目的。它们仅用于向更高层组件报告 HAProxy 的健康状况,仅此而已。但是,可以使用 "monitor fail" 和 ACL 添加任意数量的条件,以便可以根据任何可以想象的检查来调整结果(最常见的是后端中可用服务器的数量)。
# 使用 /haproxy_test 来报告 haproxy 的状态 frontend www mode http monitor-uri /haproxy_test
启用或禁用对队列中待处理的已中止请求的提前丢弃。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
在负载非常高的情况下,服务器需要一些时间来响应。每个实例的连接队列会膨胀,响应时间会随着队列大小乘以平均每个会话的响应时间而增加。当客户端等待超过几秒钟时,他们通常会点击浏览器上的“停止”按钮,在队列中留下一个无用的请求,这会减慢其他用户的速度,也会减慢服务器的速度,因为该请求最终会被处理,然后在传递响应时遇到的第一个错误处被中止。 由于无法区分完全停止和客户端的简单输出关闭,HTTP 代理应保持保守,并认为客户端可能只是在等待响应时关闭了其输出通道。然而,当大量用户这样做时,这会引入拥塞的风险,并且在今天完全没有用,因为可能没有客户端会在等待响应时关闭会话。一些 HTTP 代理支持这种行为(Squid、Apache、HAProxy),而其他一些则不支持(TUX、大多数基于硬件的负载均衡器)。 因此,关闭的输入通道代表用户点击“停止”按钮的概率接近 100%,而成为破坏罕见但有效流量的单一组件的风险极低,这增加了在会话尚未处理且不污染服务器的情况下提前中止会话的诱惑。 在 HAProxy 中,用户可以使用选项 "abortonclose" 选择期望的行为。默认情况下(没有该选项),行为符合 HTTP 规范,中止的请求将被处理。但是当指定该选项时,输入通道关闭的会话将在可能的情况下被中止,无论是在队列中等待连接槽位,还是在连接建立期间(如果服务器尚未确认连接请求)。当用户倾向于点击“停止”时,这会显著减少队列大小和饱和服务器上的负载,从而减少其他用户的响应时间。 如果此选项已在 "defaults" 部分中启用,则可以通过在其前面添加 "no" 关键字来在特定实例中禁用它。
启用或禁用放宽 HTTP 请求解析
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 否![]() |
默认情况下,HAProxy 在消息解析方面符合 RFC7230。这意味着头部名称中不允许出现无效字符,否则会向客户端返回错误。这是期望的行为,因为这些禁止的字符主要用于构建利用服务器弱点和绕过安全过滤的攻击。 有时,一个有错误的浏览器或服务器会因为某种原因(配置、实现)发出无效的头部名称,而这个问题不会立即得到修复。在这种情况下,可以通过指定此选项来放宽 HAProxy 的头部名称解析器,以接受任何字符,即使这没有意义。 同样,URI 中允许出现的字符列表由 RFC3986 明确定义,字符 0-31、32(空格)、34 ('"'), 60 ('<'), 62 ('>'), 92 ('\'), 94 ('^'), 96 ('`'), 123 ('{'), 124 ('|'), 125 ('}'), 127 (delete) 以及以上的所有字符都是完全不允许的。Haproxy 总是阻止其中的一些字符(0..32, 127)。其余的默认情况下被阻止,除非启用此选项。 此选项还放宽了对 HTTP 版本的测试,它允许 HTTP/0.9 请求通过(未指定版本),并允许主版本和次版本都有多个数字。 此选项永远不应该默认启用,因为它会隐藏应用程序的错误并打开安全漏洞。它只应在问题得到确认后部署。当启用此选项时,错误的头部名称仍将在请求中被接受,但完整的请求将被捕获,以便稍后使用 UNIX stats 套接字上的 "show errors" 请求进行分析。同样,URI 部分包含无效字符的请求将被记录下来。这样做也有助于确认问题已经解决。 如果此选项已在 "defaults" 部分中启用,可以通过在其前面添加 "no" 关键字来在特定实例中禁用它。启用或禁用放宽 HTTP 响应解析
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
默认情况下,HAProxy 在消息解析方面符合 RFC7230。这意味着头部名称中不允许出现无效字符,否则会向客户端返回错误。这是期望的行为,因为这些禁止的字符主要用于构建利用服务器弱点和绕过安全过滤的攻击。 有时,一个有错误的浏览器或服务器会因为某种原因(配置、实现)发出无效的头部名称,而这个问题不会立即得到修复。在这种情况下,可以通过指定此选项来放宽 HAProxy 的头部名称解析器,以接受任何字符,即使这没有意义。 此选项还放宽了对 HTTP 版本格式的测试,它允许主版本和次版本都有多个数字。 此选项永远不应该默认启用,因为它会隐藏应用程序的错误并打开安全漏洞。它只应在问题得到确认后部署。当启用此选项时,错误的头部名称仍将在响应中被接受,但完整的响应将被捕获,以便稍后使用 UNIX stats 套接字上的 "show errors" 请求进行分析。这样做也有助于确认问题已经解决。 如果此选项已在 "defaults" 部分中启用,可以通过在其前面添加 "no" 关键字来在特定实例中禁用它。
一次使用所有备用服务器,或仅使用第一个
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
默认情况下,当所有正常服务器都宕机时,第一个可用的备用服务器将获得所有流量。有时,可能希望一次使用多个备用服务器,因为一个可能不够用。当启用 "option allbackups" 时,当所有正常服务器都不可用时,将在所有备用服务器之间执行负载均衡。将使用相同的负载均衡算法,并遵守服务器的权重。因此,备用服务器之间将不再有任何优先级顺序。此选项主要用于专用于在应用程序完全离线时返回“抱歉”页面的静态服务器群。 如果此选项已在 "defaults" 部分中启用,可以通过在其前面添加 "no" 关键字来在特定实例中禁用它。
分析所有服务器响应并阻止带有可缓存 cookie 的响应
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
一些高级框架在各处都设置应用程序 cookie,并且并不总是给开发人员足够的控制权来管理响应应该如何缓存。当在可缓存对象上返回会话 cookie 时,存在会话交叉或用户之间通过相同缓存窃取会话的高风险。在某些情况下,阻止响应比让一些敏感的会话信息泄露到野外要好。 选项 "checkcache" 启用了对所有服务器响应的深度检查,以严格遵守 HTTP 规范在可缓存性方面的要求。它仔细检查服务器响应中的 "Cache-control"、"Pragma" 和 "Set-cookie" 头部,以检查在客户端代理上缓存 cookie 的风险。 启用此选项后,唯一可以传递给客户端的响应是: - 所有不带 "Set-Cookie" 头的响应; - 所有返回码不是 200、203、206、300、301、410 的响应,前提是服务器没有设置 "Cache-control: public" 头; - 所有来自 POST 请求的响应,前提是服务器没有设置 'Cache-Control: public' 头; - 带有 'Pragma: no-cache' 头的响应 - 带有 'Cache-control: private' 头的响应 - 带有 'Cache-control: no-store' 头的响应 - 带有 'Cache-control: max-age=0' 头的响应 - 带有 'Cache-control: s-maxage=0' 头的响应 - 带有 'Cache-control: no-cache' 头的响应 - 带有 'Cache-control: no-cache="set-cookie"' 头的响应 - 带有 'Cache-control: no-cache="set-cookie,' 头的响应(允许在 set-cookie 之后有其他字段) 如果响应不符合这些要求,那么它将被阻止,就像它来自 "rspdeny" 过滤器一样,并返回 "HTTP 502 bad gateway"。会话状态显示 "PH--",表示代理在处理头部时阻止了响应。此外,将在日志中发送警报,以便管理员知道有东西需要修复。 由于对应用程序的影响很大,应用程序应在启用该选项的情况下进行深入测试,然后再投入生产。即使在生产中不使用它,在测试期间始终激活它也是一个好习惯,因为它会报告潜在危险的应用程序行为。 如果此选项已在 "defaults" 部分中启用,可以通过在其前面添加 "no" 关键字来在特定实例中禁用它。
启用或禁用在客户端发送 TCP keepalive 数据包
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 否![]() |
当客户端和服务器之间存在防火墙或任何会话感知组件,并且协议涉及非常长的会话和长的空闲期(例如:远程桌面)时,存在其中一个中间组件决定使空闲时间过长的会话过期的风险。启用套接字级别的 TCP keep-alive 使系统定期向连接的另一端发送数据包,使其保持活动状态。keep-alive 探针之间的延迟仅由系统控制,并取决于操作系统及其调整参数。 重要的是要理解,keep-alive 数据包既不是在应用程序级别发出也不是接收的。只有网络堆栈能看到它们。因此,即使代理的一侧已经使用 keep-alive 来维持其连接活动,这些 keep-alive 数据包也不会被转发到代理的另一侧。 请注意,这与 HTTP keep-alive 无关。 使用选项 "clitcpka" 可以在连接的客户端启用 TCP keep-alive 探针的发送,这在注意到 HAProxy 和客户端之间会话过期时应该有所帮助。 如果此选项已在 "defaults" 部分中启用,可以通过在其前面添加 "no" 关键字来在特定实例中禁用它。
启用连续流量统计更新
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 否![]() |
默认情况下,用于统计计算的计数器仅在会话结束时递增。在提供小对象时,它工作得很好,但对于大对象(例如大图像或档案)或 A/V 流,从 haproxy 计数器生成的图形看起来像一只刺猬。启用此选项后,计数器将在整个会话期间连续递增。重新计数直接触及热路径,因此默认情况下未启用,因为它有小的性能影响(约 0.5%)。
启用或禁用对正常、成功连接的日志记录
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 否![]() |
有些大型网站每秒处理数千个连接,日志记录对它们来说是一个主要的痛点。其中一些甚至被迫关闭日志,无法调试生产问题。设置此选项可确保正常的连接,即那些没有经历错误、超时、重试或重新分派的连接,将不会被记录。这为异常情况留下了磁盘空间。在 HTTP 模式下,会检查响应状态码,返回码为 5xx 的仍将被记录。 强烈建议不要使用此选项,因为大多数情况下,复杂问题的关键在于正常的日志中,而这些日志在这里不会被记录。如果您需要分离日志,请改用 "log-separate-errors" 选项。
启用或禁用对空连接的日志记录
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 否![]() |
在某些环境中,有些组件会定期连接到各种系统以确保它们仍然存活。这可能来自另一个负载均衡器以及监控系统。默认情况下,即使是简单的端口探测或扫描也会产生日志。如果这些连接过多地污染了日志,可以启用选项 "dontlognull" 来指示没有传输任何数据的连接将不被记录,这通常对应于那些探测。请注意,错误仍将返回给客户端并在统计信息中计算。如果这不是所期望的,可以改用选项 http-ignore-probes。通常建议不要在不受控制的环境中(例如:互联网)使用此选项,否则扫描和其他恶意活动将不会被记录。 如果此选项已在 "defaults" 部分中启用,可以通过在其前面添加 "no" 关键字来在特定实例中禁用它。
启用或禁用在响应传输后主动关闭连接。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
一些 HTTP 服务器在收到由 "option httpclose" 设置的 "Connection: close" 时不一定会关闭连接,如果客户端也不关闭,那么连接将保持打开直到超时。这会导致服务器上出现大量的并发连接,并在日志中显示出很高的全局会话时间。当发生这种情况时,可以使用 "option forceclose"。它将在服务器完成响应后立即主动关闭出站服务器通道,并比使用 "option httpclose" 更早地释放一些资源。此选项还可以与 "option http-pretend-keepalive" 结合使用,这将禁用发送 "Connection: close" 头部,但在收到整个响应后仍会导致连接关闭。 此选项禁用并替换任何先前的 "option httpclose"、"option http-server-close"、"option http-keep-alive" 或 "option http-tunnel"。 如果此选项已在 "defaults" 部分中启用,可以通过在其前面添加 "no" 关键字来在特定实例中禁用它。
启用向发送到服务器的请求中插入 X-Forwarded-For 头部
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
<network> 是一个可选参数,用于对匹配 <network> 的源禁用此选项。<name> 是一个可选参数,用于指定一个不同的 "X-Forwarded-For" 头部名称。
由于 HAProxy 以反向代理模式工作,服务器将其 IP 地址视为其客户端地址。当服务器日志中期望客户端的 IP 地址时,这有时会很烦人。为了解决这个问题,HAProxy 可以将众所周知的 HTTP 头部 "X-Forwarded-For" 添加到发送给服务器的所有请求中。此头部包含一个表示客户端 IP 地址的值。由于此头部总是附加在现有头部列表的末尾,因此必须将服务器配置为始终仅使用此头部的最后一次出现。请参阅服务器的手册以了解如何启用此标准头部的使用。请注意,必须只使用该头部的最后一次出现,因为客户端确实有可能已经带来了一个。 关键字 "header" 可用于提供一个不同的头部名称来替换默认的 "X-Forwarded-For"。当您可能已经有来自不同应用程序(例如:stunnel)的 "X-Forwarded-For" 头部并且需要保留它时,这可能很有用。此外,如果您的后端服务器不使用 "X-Forwarded-For" 头部而需要不同的头部(例如:Zeus Web 服务器需要 "X-Cluster-Client-IP")。 有时,同一个 HAProxy 实例可能在直接客户端访问和反向代理访问之间共享(例如,当使用 SSL 反向代理来解密 HTTPS 流量时)。可以通过添加 "except" 关键字后跟网络地址来为已知的源地址或网络禁用添加该头部。在这种情况下,任何匹配该网络的源 IP 都不会导致添加此头部。最常见的用途是用于私有网络或 127.0.0.1。 或者,关键字 "if-none" 表示仅当头部不存在时才会添加。这只应在完全受信任的环境中使用,因为如果到达 haproxy 的头部受最终用户控制,这可能会导致安全问题。 此选项可以在前端或后端中指定。如果其中至少有一个使用它,则会添加该头部。请注意,如果前端和后端都定义了头部子参数,则后端的设置优先于前端的设置。在 "if-none" 参数的情况下,如果前端或后端中至少有一个未指定它,则表示希望强制添加,因此它会生效。
# 公共 HTTP 地址,也由同一台机器上的 stunnel 使用 frontend www mode http option forwardfor except 127.0.0.1 # stunnel 已经添加了该标头 # 这些服务器希望在 X-Client 中获取 IP 地址 backend www mode http option forwardfor header X-Client
启用或禁用在处理前等待整个 HTTP 请求体
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
有时需要在做出决策前等待 HTTP 请求的主体。例如,"balance url_param" 就是这样做的。第一个用例是在连接到服务器之前,缓冲来自慢速客户端的请求。另一个用例是根据请求主体的内容来做出路由决策。此选项放置在前端或后端中,强制 HTTP 处理等待直到接收到整个主体,或者请求缓冲区已满,或者在分块编码的情况下第一个块已完成。它可能会对某些滥用 HTTP、期望前端和后端之间进行非缓冲传输的应用程序产生不希望的副作用,因此绝对不应默认使用。
启用或禁用空连接和请求超时的日志记录
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 否![]() |
最近一些浏览器开始实现“预连接”功能,即推测性地连接到一些最近访问过的网站,以防用户想要访问它们。这导致与网站建立许多连接,如果超时先发生,则最终导致 408 请求超时,或者当浏览器决定先关闭它们时导致 400 错误请求。这些会污染日志并增加错误计数器。已经有 "option dontlognull",但在这种情况下还不够。相反,此选项执行以下操作: - 如果在连接关闭前没有接收到任何内容,则阻止向客户端发送任何 400/408 消息; - 在这种情况下阻止发出任何日志; - 阻止增加任何错误计数器。这样,空连接将被静默忽略。请注意,除非明确需要,否则最好不要使用此选项,因为它会隐藏真正的问题。未接收到请求并看到 408 的最常见原因是客户端与中间元素(如 VPN)之间的 MTU 不一致,这会阻塞过大的数据包。这些问题通常在使用 POST 请求以及带有大 Cookie 的 GET 请求时出现。日志通常是检测它们的唯一方法。如果此选项已在 "defaults" 部分启用,可以通过在其前面加上 "no" 关键字在特定实例中禁用它。
启用或禁用从客户端到服务器的 HTTP keep-alive
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
默认情况下,HAProxy 在持久连接方面以 keep-alive 模式运行:对于每个连接,它处理每个请求和响应,并在响应结束和新请求开始之间将连接在两端保持空闲。此模式可以通过多个选项进行更改,例如 "option http-server-close"、"option forceclose"、"option httpclose" 或 "option http-tunnel"。此选项允许重新设置 keep-alive 模式,这在 defaults 部分使用了另一种模式时非常有用。设置 "option http-keep-alive" 会在客户端和服务器端启用 HTTP keep-alive 模式。这在客户端(慢速网络)提供了最低的延迟,在服务器端提供了最快的会话重用,但代价是维持与服务器的空闲连接。通常,使用此选项可以达到比 "http-server-close" 选项在小对象上达到的请求率高大约两倍。此选项主要在两种情况下有用: - 当服务器不符合 HTTP 规范并且验证连接而不是请求时(例如:NTLM 认证) - 当建立到服务器的连接成本与从服务器检索相关对象的成本相比非常显著时。后一种情况可能发生在服务器是快速的静态服务器或缓存时。在这种情况下,服务器需要进行适当的调整以支持足够高的连接数,因为连接将持续到客户端发送另一个请求为止。如果由于内容切换或负载均衡算法,客户端请求必须转到另一个后端或另一台服务器,空闲连接将立即关闭并重新打开一个新的连接。选项 "prefer-last-server" 可用于尝试优化服务器选择,以便如果当前附加到空闲连接的服务器可用,则将使用它。目前,日志不会指示请求是否来自同一会话。日志中报告的接受日期对应于上一个请求的结束,请求时间对应于等待新请求所花费的时间。keep-alive 请求时间仍然受 "timeout http-keep-alive" 定义的超时或如果未设置则由 "timeout http-request" 定义的超时限制。此选项会禁用并替换任何先前的 "option httpclose"、"option http-server-close"、"option forceclose" 或 "option http-tunnel"。当后端和前端选项不同时,所有这 4 个选项都优先于 "option http-keep-alive"。
指示系统在 HTTP 中优先考虑低交互延迟而非性能
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
在 HTTP 中,每个负载都是单向的,没有交互性的概念。任何代理都应该对数据进行一定程度的排队以获得合理的低延迟。有一些非常罕见的服务器到服务器应用程序滥用 HTTP 协议,并期望负载阶段具有高度交互性,在单个请求内双向有许多交错的数据块。这绝对不受 HTTP 规范支持,并且在大多数代理或服务器上都无法工作。当此类应用程序试图通过 haproxy 执行此操作时,它可以工作,但由于网络优化(通过指示系统等待足够的数据可用以便仅发送完整的数据包来提高性能),它们将经历高延迟。典型的延迟约为每轮 200 毫秒。请注意,这仅发生在异常使用情况下。正常使用(如 CONNECT 请求或 WebSocket)不受影响。当 "option http-no-delay" 出现在连接所使用的前端或后端中时,所有此类优化都将被禁用,以使交换尽可能快。当然,这并不能保证功能性,因为它可能会在任何其他地方中断。但是,如果它通过 HAProxy 工作,它将尽可能快地工作。此选项绝不应默认使用,并且除非发现此类有问题的应用程序,否则绝不应使用。使用此选项的影响是带宽使用和 CPU 使用的增加,这可能会在高延迟环境中显著降低性能。
定义 haproxy 是否向服务器宣告 keep-alive
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
当使用 "option http-server-close" 或 "option forceclose" 运行时,haproxy 会向转发到服务器的请求添加一个 "Connection: close" 标头。不幸的是,当一些服务器看到这个标头时,它们会自动避免对未知长度的响应使用分块编码,而这完全是无关的。直接的影响是这会阻止 haproxy 维持客户端连接的活动状态。第二个影响是客户端或缓存可能会收到不完整的响应而没有意识到,并认为响应是完整的。通过设置 "option http-pretend-keepalive",haproxy 将让服务器相信它将保持连接活动。然后服务器将不会回退到上述异常的不希望的行为。当 haproxy 获得整个响应时,它将关闭与服务器的连接,就像它使用 "forceclose" 选项一样。这样客户端可以获得正常的响应,并且连接在服务器端被正确关闭。建议不要默认启用此选项,因为大多数服务器在最后一个数据包之后会更有效地自行关闭连接,并稍早地释放其缓冲区。此外,网络上增加的数据包可能会略微降低整体峰值性能。然而值得注意的是,当启用此选项时,haproxy 的工作量会稍微减少。因此,如果 haproxy 是整个架构的瓶颈,启用此选项可能会节省一些 CPU 周期。此选项可以在前端和后端中设置。如果持有连接的前端或后端中至少有一个启用了它,则该选项被启用。此选项可以与 "option httpclose" 结合使用,这将导致向服务器宣告 keep-alive,并向客户端宣告 close。但我们不鼓励这种做法。如果此选项已在 "defaults" 部分启用,可以通过在其前面加上 "no" 关键字在特定实例中禁用它。
启用或禁用服务器端的 HTTP 连接关闭
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
默认情况下,HAProxy 在持久连接方面以 keep-alive 模式运行:对于每个连接,它处理每个请求和响应,并在响应结束和新请求开始之间将连接在两端保持空闲。此模式可以通过多个选项进行更改,例如 "option http-server-close"、"option forceclose"、"option httpclose" 或 "option http-tunnel"。设置 "option http-server-close" 会在服务器端启用 HTTP 连接关闭模式,同时保留在客户端支持 HTTP keep-alive 和流水线的能力。这在客户端(慢速网络)提供了最低的延迟,在服务器端提供了最快的会话重用以节省服务器资源,类似于 "option forceclose"。它还允许不支持 keep-alive 的服务器以 keep-alive 模式为客户端提供服务,只要它们符合 RFC7230 的要求。请注意,当某些服务器在请求中看到 "Connection: close" 时,它们并不总是符合这些要求。其效果是永远不会使用 keep-alive。一种解决方法是启用 "option http-pretend-keepalive"。目前,日志不会指示请求是否来自同一会话。日志中报告的接受日期对应于上一个请求的结束,请求时间对应于等待新请求所花费的时间。keep-alive 请求时间仍然受 "timeout http-keep-alive" 定义的超时或如果未设置则由 "timeout http-request" 定义的超时限制。此选项可以在前端和后端中设置。如果持有连接的前端或后端中至少有一个启用了它,则该选项被启用。它会禁用并替换任何先前的 "option httpclose"、"option forceclose"、"option http-tunnel" 或 "option http-keep-alive"。请查看第 4 节(“代理”)以了解当前端和后端选项不同时,此选项如何与其他选项结合使用。如果此选项已在 "defaults" 部分启用,可以通过在其前面加上 "no" 关键字在特定实例中禁用它。
禁用或启用第一次事务后的 HTTP 连接处理
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
默认情况下,HAProxy 在持久连接方面以 keep-alive 模式运行:对于每个连接,它处理每个请求和响应,并在响应结束和新请求开始之间将连接在两端保持空闲。此模式可以通过多个选项进行更改,例如 "option http-server-close"、"option forceclose"、"option httpclose" 或 "option http-tunnel"。选项 "http-tunnel" 会在第一个请求和第一个响应之后禁用任何 HTTP 处理。这是版本 1.0 到 1.5-dev21 中默认使用的模式。这是处理开销最低的模式,通常不再需要,除非在非常特定的情况下,例如使用看起来像 HTTP 但不兼容的内部协议,或者只是为了每个客户端记录一个请求以减少日志大小。请注意,在 HTTP 级别工作的所有内容,包括标头解析/添加、Cookie 处理或内容切换,将仅对第一个请求起作用,并在第一个响应后被忽略。如果此选项已在 "defaults" 部分启用,可以通过在其前面加上 "no" 关键字在特定实例中禁用它。
使用非标准的 Proxy-Connection 标头代替 Connection
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 否![]() |
虽然 RFC7230 明确规定 HTTP/1.1 代理必须使用 Connection 标头来表明它们希望使用持久或非持久连接,但浏览器和代理在代理连接时都忽略此标头,而是使用未记录的、非标准的 Proxy-Connection 标头。当试图在浏览器和此类代理之间放置负载均衡器时,问题就开始了,因为 haproxy 理解的内容与客户端和代理达成一致的内容之间存在差异。通过在前端设置此选项,如果 haproxy 看到代理请求,它可以自动切换到使用该非标准标头。这里的代理请求定义为 URI 不以“/”或“*”开头的请求。这与 HTTP 隧道模式不兼容。请注意,此选项只能在前端指定,并将影响请求的整个生命周期。此外,当设置此选项时,需要身份验证的请求如果其本身是代理请求,将自动切换到使用代理身份验证标头。这使得可以在现有代理前面检查或强制执行身份验证。此选项通常不应使用,除非在代理前面。
启用 HTTP 协议以检查服务器健康状况
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
<method> 是与请求一起使用的可选 HTTP 方法。如果未设置,则使用 "OPTIONS" 方法,因为它通常需要较低的服务器处理并且易于从日志中过滤掉。可以使用任何方法,但不建议发明非标准方法。<uri> 是 HTTP 请求中引用的 URI。它默认为 " / ",几乎所有服务器默认都可以访问,但可以更改为任何其他 URI。允许查询字符串。<version> 是可选的 HTTP 版本字符串。它默认为 "HTTP/1.0",但某些服务器可能在 HTTP 1.0 中行为不正确,因此将其更改为 HTTP/1.1 有时会有所帮助。请注意,Host 字段在 HTTP/1.1 中是必需的,作为一个技巧,可以在版本字符串后的 "\r\n" 之后传递它。
默认情况下,服务器健康检查仅包括尝试建立 TCP 连接。当指定 "option httpchk" 时,一旦建立 TCP 连接,就会发送一个完整的 HTTP 请求,2xx 和 3xx 响应被认为是有效的,而所有其他响应都表示服务器故障,包括没有任何响应。端口和间隔在服务器配置中指定。此选项不一定需要 HTTP 后端,它也适用于纯 TCP 后端。这对于检查使用 inetd 守护进程绑定到某些专用端口的简单脚本特别有用。
# 将 HTTPS 流量中继到 Apache 实例并检查服务可用性 # 使用 HTTP 请求 "OPTIONS * HTTP/1.1" 在端口 80 上。 backend https_relay mode tcp option httpchk OPTIONS * HTTP/1.1\r\nHost:\ www server apache1 192.168.1.1:443 check port 80
启用或禁用被动 HTTP 连接关闭
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
默认情况下,HAProxy 在持久连接方面以 keep-alive 模式运行:对于每个连接,它处理每个请求和响应,并在响应结束和新请求开始之间将连接在两端保持空闲。此模式可以通过多个选项进行更改,例如 "option http-server-close"、"option forceclose"、"option httpclose" 或 "option http-tunnel"。如果设置了 "option httpclose",HAProxy 将在 HTTP 隧道模式下工作,并检查每个方向是否已设置 "Connection: close" 标头,如果缺少则会添加一个。每一端都应通过在每次传输后主动关闭 TCP 连接来对此作出反应,从而导致切换到 HTTP 关闭模式。任何不同于 "close" 的 "Connection" 标头也将被移除。请注意,此选项已弃用,因为它所做的事情成本很低但不可靠。强烈建议改用 "option http-server-close" 或 "option forceclose"。很少发生某些服务器错误地忽略此标头并且即使它们回复 "Connection: close" 也不关闭连接的情况。因此,它们与旧的 HTTP 1.0 浏览器不兼容。如果发生这种情况,可以使用 "option forceclose",它会在服务器响应后主动关闭请求连接。选项 "forceclose" 也会更早地释放服务器连接,因为它不必等待客户端确认。此选项可以在前端和后端中设置。如果持有连接的前端或后端中至少有一个启用了它,则该选项被启用。它会禁用并替换任何先前的 "option http-server-close"、"option forceclose"、"option http-keep-alive" 或 "option http-tunnel"。请查看第 4 节(“代理”)以了解当前端和后端选项不同时,此选项如何与其他选项结合使用。如果此选项已在 "defaults" 部分启用,可以通过在其前面加上 "no" 关键字在特定实例中禁用它。
启用 HTTP 请求、会话状态和计时器的日志记录
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
clf 如果添加了 "clf" 参数,则输出格式将是 CLF 格式而不是 HAProxy 的默认 HTTP 格式。当您需要通过仅支持 CLF 格式且不可扩展的特定日志分析器来处理 HAProxy 的日志时,可以使用此功能。
默认情况下,日志输出格式非常简单,只包含源地址和目标地址以及实例名称。通过指定 "option httplog",每条日志行都会变成更丰富的格式,包括但不限于 HTTP 请求、连接计时器、会话状态、连接数、捕获的标头和 cookie、前端、后端和服务器名称,当然还有源地址和端口。此选项可以在前端或后端中设置。仅指定 "option httplog" 将自动清除默认设置的 'clf' 模式。"option httplog" 会覆盖任何先前的 "log-format" 指令。
启用或禁用纯 HTTP 代理模式
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
有时人们需要一个纯粹的 HTTP 代理,它能理解基本的代理请求,而不需要缓存或任何花哨的功能。在这种情况下,设置一个启用了 "option http_proxy" 的 HAProxy 实例可能是值得的。在这种模式下,不声明任何服务器,连接被转发到 URL 中 "http://" 方案后的 IP 地址和端口。不执行主机地址解析,因此这仅在传递纯 IP 地址时有效。由于此选项的使用范围相当有限,它可能只会被那些知道自己确切需要它的专家使用。这与 HTTP 隧道模式不兼容。如果此选项已在 "defaults" 部分启用,可以通过在其前面加上 "no" 关键字在特定实例中禁用它。
# 此后端理解 HTTP 代理请求并直接转发它们。 backend direct_forward option httpclose option http_proxy
启用或禁用对两个方向的独立超时处理
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
默认情况下,当数据通过套接字发送时,该套接字的写入超时和读取超时都会被刷新,因为我们认为该套接字上有活动,并且我们没有其他方法来猜测是否应该接收数据。虽然这种默认行为对于几乎所有应用程序都是可取的,但存在一种希望禁用它的情况,并且仅在有传入数据时才刷新读取超时。这发生在超时时间长、交换数据量少的会话上,例如 telnet 会话。如果服务器突然消失,输出数据会积聚在系统的套接字缓冲区中,两个超时都被正确刷新,并且没有办法知道服务器没有接收到它们,所以我们不会超时。然而,当底层协议总是回显发送的数据时,仅使用读取超时就足以检测到问题。请注意,对于更详细的协议,此问题不会发生,因为数据不会在套接字缓冲区中长时间积聚。当前端设置此选项时,它将禁用对发送给客户端的数据的读取超时更新。这种情况可能很少使用。当在后端设置该选项时,它将禁用对发送到服务器的数据的读取超时更新。这样做通常会中断来自慢速线路的大型 HTTP post,因此请谨慎使用。注意:旧版本曾将此设置称为 "option independant-streams",存在拼写错误。该拼写仍然受支持但已弃用。
使用 LDAPv3 健康检查进行服务器测试
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
可以测试服务器是否正确地使用 LDAPv3 通信,而不仅仅是测试它是否接受 TCP 连接。设置此选项后,会向服务器发送一个 LDAPv3 匿名简单绑定消息,并分析响应以查找 LDAPv3 绑定响应消息。只有当 LDAP 响应包含成功 resultCode (http://tools.ietf.org/html/rfc4511#section-4.1.9) 时,服务器才被认为是有效的。绑定请求的日志记录取决于服务器,请参阅您的文档如何配置它。
option ldap-check
使用外部进程进行服务器健康检查
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
可以使用外部命令测试服务器的健康状况。这是通过运行使用 "external-check command" 设置的可执行文件来实现的。需要设置全局的 "external-check"。
启用或禁用健康检查状态更新的日志记录
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
默认情况下,如果服务器处于 UP 状态,则会记录失败的健康检查;如果服务器处于 DOWN 状态,则会记录成功的健康检查,因此额外的信息量是有限的。启用此选项后,健康检查状态或服务器健康状况的任何变化都将被记录,这样就可以知道服务器在崩溃前偶尔会检查失败,或者确切地知道它何时未能响应有效的 HTTP 状态,然后端口何时开始拒绝连接,再然后服务器何时完全停止响应。请注意,非由健康检查引起的状态变化(例如:在 CLI 上启用/禁用)此选项有意不记录。
更改非完全成功连接的日志级别
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 否![]() |
有时在日志中查找错误并不容易。此选项使 haproxy 提高包含潜在有趣信息(如错误、超时、重试、重新分派或 HTTP 状态码 5xx)的日志级别。级别从 "info" 变为 "err"。这使得可以使用大多数 syslog 守护进程将它们单独记录到不同的文件中。注意不要将它们从原始文件中删除,否则你会丢失提供非常重要信息的顺序。使用此选项,处理每秒数千个连接的大型站点可以将正常流量记录到循环缓冲区中,并只归档较小的错误日志。
启用或禁用 HTTP 请求的早期日志记录
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 否![]() |
默认情况下,HTTP 请求在终止时记录,以便总传输时间和字节数出现在日志中。当传输大对象时,请求出现在日志中可能需要一段时间。使用 "option logasap",请求会在服务器发送完整的标头后立即被记录。日志中唯一缺少的信息是总字节数(它将指示除传输数据量之外的所有内容)和总时间(它将不考虑传输时间)。在这种情况下,一个好的做法是捕获 "Content-Length" 响应标头,以便日志至少指示预期传输的字节数。
listen http_proxy 0.0.0.0:80 mode http option httplog option logasap log 192.168.2.200 local3 >>> Feb 6 12:14:14 localhost \ haproxy[14389]: 10.0.1.2:33317 [06/Feb/2009:12:14:14.655] http-in \ static/srv1 9/10/7/14/+30 200 +243 - - ---- 3/1/1/1/0 1/0 \ "GET /image.iso HTTP/1.0"
使用 MySQL 健康检查进行服务器测试
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
<username> 这是连接到 MySQL 服务器时将使用的用户名。 post-41 发送与 v4.1 后版本客户端兼容的检查
如果您指定一个用户名,检查包括发送两个 MySQL 数据包,一个客户端认证数据包和一个 QUIT 数据包,以正确关闭 MySQL 会话。然后我们解析 MySQL 握手初始化数据包和/或错误数据包。这是一个基本但有用的测试,不会在服务器上产生错误或中止的连接。但是,它需要在 MySQL 表中添加授权,如下所示: USE mysql; INSERT INTO user (Host,User) values ('<haproxy_ip>','<username>'); FLUSH PRIVILEGES; 如果您不指定用户名(不推荐且已弃用),检查仅包括解析 MySQL 握手初始化数据包或错误数据包,我们在此模式下不发送任何内容。据报道,如果检查过于频繁和/或流量不足,可能会导致锁定。事实上,在这种情况下,您需要检查 MySQL 的 "max_connect_errors" 值,因为如果在上一次连接中断后,在少于 MySQL "max_connect_errors" 次尝试内成功建立连接,则该主机的错误计数将清零。如果 HAProxy 的服务器被阻塞,"FLUSH HOSTS" 语句是解除阻塞的唯一方法。请记住,这不会检查数据库是否存在或数据库的一致性。要做到这一点,您可以使用带有 xinetd 的外部检查。该检查需要 MySQL >=3.22,对于旧版本,请使用 TCP 检查。大多数情况下,传入的 MySQL 服务器需要看到客户端的 IP 地址用于各种目的,包括 IP 权限匹配和连接日志记录。如果可能,通常明智的做法是使用 "source" 关键字的 "usesrc" 参数,在连接到服务器时伪装客户端的 IP 地址,这需要编译时启用透明代理功能,并且 MySQL 服务器通过托管 haproxy 的机器路由客户端。启用或禁用关闭后立即清理会话资源
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
当客户端或服务器以不干净的方式中止连接时(例如:它们被物理断开),会话超时会触发,会话被关闭。但它会在系统中保持 FIN_WAIT1 状态一段时间,占用一些资源,并可能限制建立新连接的能力。当这种情况发生时,可以激活 "option nolinger",它会强制系统在关闭时立即移除任何套接字的待处理数据。因此,会话会立即从系统的表中清除。这通常会产生副作用,例如由于旧的重传立即被拒绝而导致 TCP 重置次数增加。一些防火墙有时也可能对此抱怨。因此,不建议在非绝对必要时使用此选项。当您的系统上有数千个 FIN_WAIT1 会话时(TIME_WAIT 会话不计算在内),您就知道您需要它了。此选项可以在前端和后端使用,具体取决于需要它的一方。在前端用于客户端,在后端用于服务器。如果此选项已在 "defaults" 部分启用,可以通过在其前面加上 "no" 关键字在特定实例中禁用它。
启用向发送到服务器的请求插入 X-Original-To 标头
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
<network> 是一个可选参数,用于为匹配 <network> 的源禁用此选项。<name> 是一个可选参数,用于指定一个不同的 "X-Original-To" 标头名称。
由于 HAProxy 可以在透明模式下工作,来自客户端的每个请求都可以重定向到代理,而 HAProxy 本身可以将每个请求代理到复杂的 SQUID 环境,并且来自 SO_ORIGINAL_DST 的目标主机将会丢失。当您想要基于目标 IP 地址进行访问规则时,这很烦人。为了解决这个问题,HAProxy 可以向所有发送到服务器的请求添加一个新的 HTTP 标头 "X-Original-To"。该标头包含一个表示原始目标 IP 地址的值。由于必须配置为始终仅使用此标头的最后一次出现。请注意,必须只使用该标头的最后一次出现,因为客户端很可能已经带来了一个。关键字 "header" 可用于提供一个不同的标头名称来替换默认的 "X-Original-To"。当您可能已经有来自不同应用程序的 "X-Original-To" 标头并且需要保留它时,这可能很有用。同样,如果您的后端服务器不使用 "X-Original-To" 标头并且需要不同的标头。有时,同一个 HAProxy 实例可能在直接客户端访问和反向代理访问之间共享(例如,当使用 SSL 反向代理解密 HTTPS 流量时)。可以通过添加 "except" 关键字后跟网络地址来为已知的源地址或网络禁用此标头的添加。在这种情况下,任何匹配该网络的源 IP 将不会导致添加此标头。最常见的用法是与私有网络或 127.0.0.1 一起使用。此选项可以在前端或后端指定。如果其中至少有一个使用它,则会添加该标头。请注意,如果两者都定义了,则后端的标头子参数设置优先于前端的设置。
# 原始目标地址 frontend www mode http option originalto except 127.0.0.1 # 这些服务器希望在 X-Client-Dst 中获取 IP 地址 backend www mode http option originalto header X-Client-Dst
启用或禁用对故障服务器的强制持久性
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
当 HTTP 请求到达一个带有引用故障服务器的 cookie 的后端时,默认情况下它会被重新分派到另一台服务器。如果绝对需要,可以使用 "option persist" 强制将请求首先发送到故障服务器。一个常见的用例是当服务器处于极端负载下并不断地出现状态切换时。在这种情况下,用户仍将被导向到他们打开会话的服务器,希望他们能得到正确的服务。建议将 "option redispatch" 与此选项结合使用,以便在无法连接到服务器的情况下(服务器确定故障),客户端最终将被重定向到另一台有效的服务器。如果此选项已在 "defaults" 部分启用,可以通过在其前面加上 "no" 关键字在特定实例中禁用它。
使用 PostgreSQL 健康检查进行服务器测试
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
<username> 这是连接到 PostgreSQL 服务器时将使用的用户名。
此检查发送一个 PostgreSQL StartupMessage 并等待认证请求或 ErrorResponse 消息。这是一个基本但有用的测试,不会在服务器上产生错误或中止连接。此检查与 "mysql-check" 相同。
允许多个负载均衡的请求保留在同一台服务器上
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
当使用的负载均衡算法不是确定性的,并且之前的请求已发送到 haproxy 仍然持有连接的服务器时,有时希望同一会话上的后续请求尽可能地转到同一台服务器。请注意,这与持久性不同,因为我们只表示一个偏好,haproxy 尝试应用它而没有任何形式的保证。真正的用途是用于发送到服务器的 keep-alive 连接。使用此选项时,haproxy 将尝试重用附加到该服务器的相同连接,而不是重新平衡到另一台服务器,导致连接关闭。这对于静态文件服务器可能很有意义。将此与哈希算法结合使用意义不大。注意,haproxy 已经自动尝试粘附到发送 401 的服务器或发送 407(需要身份验证)的代理。这对于使用有问题的 NTLM 身份验证挑战是强制性的,并且在排查某些故障应用程序时有很大帮助。在这些环境中,Option prefer-last-server 可能也是可取的,以避免在每次其他响应后重新分配流量。如果此选项已在 "defaults" 部分启用,可以通过在其前面加上 "no" 关键字在特定实例中禁用它。
启用或禁用连接失败时的会话重新分发
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
<interval> 可选的整数值,控制重试连接时重新分派的频率。正值 P 表示希望在每第 P 次重试时进行重新分派,负值 N 表示希望在最后一次重试前的第 N 次重试时进行重新分派。例如,默认值 -1 保留了在最后一次重试时重新分派的历史行为,正值 1 表示每次重试都重新分派,正值 3 表示每三次重试重新分派。您可以使用值 0 禁用重新分派。
在 HTTP 模式下,如果由 cookie 指定的服务器出现故障,客户端可能会永久粘附于该服务器,因为他们无法清除 cookie,因此将无法再访问服务。指定 "option redispatch" 将允许代理打破他们的持久性,并将他们重新分配到一台工作的服务器。它还允许在多次连接失败的情况下重试连接到另一台服务器。当然,这需要将 "retries" 设置为非零值。这种形式是首选形式,它取代了 "redispatch" 和 "redisp" 关键字。如果此选项已在 "defaults" 部分启用,可以通过在其前面加上 "no" 关键字在特定实例中禁用它。
使用 Redis 健康检查进行服务器测试
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
可以测试服务器是否正确地使用 REDIS 协议通信,而不仅仅是测试它是否接受 TCP 连接。设置此选项后,会向服务器发送一个 PING redis 命令,并分析响应以查找 "+PONG" 响应消息。
option redis-check
使用 SMTP 健康检查进行服务器测试
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
<hello> 是一个可选参数。它是要使用的 "hello" 命令。它可以是 "HELO" (用于 SMTP) 或 "EHLO" (用于 ESTMP)。所有其他值都将转换为默认命令 ("HELO")。<domain> 是要呈现给服务器的域名。只有在指定了 hello 命令的情况下才能指定它(并且是必需的)。默认情况下,使用 "localhost"。
设置 "option smtpchk" 后,健康检查将包括 TCP 连接和随后的 SMTP 命令。默认情况下,此命令是 "HELO localhost"。服务器的返回码将被分析,只有以 "2" 开头的返回码才被认为是有效的。所有其他响应,包括没有响应,都将构成错误并指示服务器故障。此测试旨在与 SMTP 服务器或中继一起使用。根据请求,某些服务器可能不会记录每次连接尝试,因此您可能需要进行试验以改进其行为。在端口 25 上使用 telnet 通常比调整配置更容易。大多数情况下,传入的 SMTP 服务器需要看到客户端的 IP 地址用于各种目的,包括垃圾邮件过滤、反欺骗和日志记录。如果可能,通常明智的做法是使用 "source" 关键字的 "usesrc" 参数,在连接到服务器时伪装客户端的 IP 地址,这需要编译时启用透明代理功能。
option smtpchk HELO mydomain.org
启用或禁用为每个套接字收集并提供单独的统计信息。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 否![]() |
启用或禁用双向套接字上的自动内核加速
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
当在前台或后台启用此选项时,haproxy 将自动评估使用内核 TCP 拼接在客户端和服务器之间转发数据的机会,无论哪个方向。Haproxy 使用启发式方法来估计内核拼接是否可能提高性能。两个方向是独立处理的。请注意,所使用的启发式方法不是很激进,以限制拼接的过度使用。此选项需要在编译时启用拼接,并且可以通过全局选项 "nosplice" 全局禁用。由于 splice 使用管道,使用它需要有足够的备用管道。重要说明:基于内核的 TCP 拼接是 Linux 特有的功能,首次出现在内核 2.6.25 中。它提供基于内核的加速,可在套接字之间传输数据而无需将这些数据复制到用户空间,从而提供显著的性能提升和 CPU 周期节省。由于许多早期实现存在错误、损坏数据和/或效率低下,此功能默认未启用,应谨慎使用。虽然无法检测实现的正确性,但 2.6.29 是第一个提供正常工作实现的版本。如有疑问,可以使用全局 "nosplice" 关键字全局禁用拼接。
option splice-auto
如果此选项已在 "defaults" 部分启用,可以通过在其前面加上 "no" 关键字在特定实例中禁用它。
启用或禁用请求套接字上的自动内核加速
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
当在前台或后台启用此选项时,haproxy 将尽可能使用内核 TCP 拼接来转发从客户端到服务器的数据。如果没有备用管道,它可能仍会使用 recv/send 方案。此选项需要在编译时启用拼接,并且可以通过全局选项 "nosplice" 全局禁用。由于 splice 使用管道,使用它需要有足够的备用管道。重要说明:有关使用限制,请参阅 "option splice-auto"。
option splice-request
如果此选项已在 "defaults" 部分启用,可以通过在其前面加上 "no" 关键字在特定实例中禁用它。
启用或禁用响应套接字上的自动内核加速
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
当在前台或后台启用此选项时,haproxy 将尽可能使用内核 TCP 拼接来转发从服务器到客户端的数据。如果没有备用管道,它可能仍会使用 recv/send 方案。此选项需要在编译时启用拼接,并且可以通过全局选项 "nosplice" 全局禁用。由于 splice 使用管道,使用它需要有足够的备用管道。重要说明:有关使用限制,请参阅 "option splice-auto"。
option splice-response
如果此选项已在 "defaults" 部分启用,可以通过在其前面加上 "no" 关键字在特定实例中禁用它。
启用或禁用在服务器端发送 TCP keepalive 数据包
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
当客户端和服务器之间有防火墙或任何会话感知组件,并且协议涉及非常长的会话和长的空闲期(例如:远程桌面)时,存在其中一个中间组件决定使一个长时间空闲的会话过期的风险。启用套接字级别的 TCP keep-alive 使系统定期向连接的另一端发送数据包,使其保持活动状态。keep-alive 探测之间的延迟仅由系统控制,并取决于操作系统及其调整参数。重要的是要理解,keep-alive 数据包既不是在应用程序级别发出也不是接收的。只有网络堆栈能看到它们。因此,即使代理的一方已经使用 keep-alive 来维持其连接活动,这些 keep-alive 数据包也不会被转发到代理的另一方。请注意,这与 HTTP keep-alive 无关。使用选项 "srvtcpka" 可以在连接的服务器端启用 TCP keep-alive 探测的发送,这在 HAProxy 和服务器之间注意到会话过期时应该有所帮助。如果此选项已在 "defaults" 部分启用,可以通过在其前面加上 "no" 关键字在特定实例中禁用它。
使用 SSLv3 客户端 hello 健康检查进行服务器测试
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
当一些基于 SSL 的协议在 TCP 模式下通过 HAProxy 中继时,可以测试服务器是否正确地使用 SSL 通信,而不仅仅是测试它是否接受 TCP 连接。设置 "option ssl-hello-chk" 后,一旦与服务器建立连接,就会发送纯 SSLv3 客户端 hello 消息,并分析响应以查找 SSL 服务器 hello 消息。只有当响应包含此服务器 hello 消息时,服务器才被认为是有效的。到目前为止测试的所有服务器都能正确回复 SSLv3 客户端 hello 消息,并且大多数测试的服务器甚至不记录仅包含 hello 消息的请求,这是值得赞赏的。请注意,即使 haproxy 未内置 SSL 支持,此检查也能正常工作,因为它会伪造 SSL 消息。当 SSL 支持可用时,最好使用原生 SSL 健康检查而不是这个。
使用 tcp-check 发送/期望序列执行健康检查
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
此健康检查方法旨在与 "tcp-check" 命令列表结合使用,以支持发送/期望类型的健康检查序列。TCP 检查目前支持 4 种操作模式: - 没有 "tcp-check" 指令:健康检查仅包括连接尝试,这仍然是默认模式。 - 仅提及 "tcp-check send" 或 "tcp-check send-binary":这用于在打开连接时发送一个字符串。对于某些协议,例如,发送 "QUIT" 消息有助于防止服务器为每次健康检查记录连接错误。检查结果仍将仅基于打开连接的能力。 - 仅提及 "tcp-check expect":这用于测试横幅。连接被打开,haproxy 等待服务器呈现一些必须验证某些规则的内容。检查结果将基于内容和规则之间的匹配。这适用于 POP、IMAP、SMTP、FTP、SSH、TELNET。 - 同时提及 "tcp-check send" 和 "tcp-check expect":这用于测试 hello 类型的协议。Haproxy 发送一条消息,服务器响应,并对其响应进行分析。检查结果将基于响应内容和规则之间的匹配。这通常适用于需要绑定或请求/响应模型的协议。LDAP、MySQL、Redis 和 SSL 是此类协议的示例,尽管它们都已经有自己专用的、对相应协议有更深入了解的检查。在这种模式下,可以发送许多问题,也可以分析许多答案。第五种模式可用于在脚本的不同步骤中插入注释。对于您创建的每个 tcp-check 规则,您可以添加一个 "comment" 指令,后跟一个字符串。此字符串将在调试模式下报告在日志和 stderr 中。它对于进行用户友好的错误报告很有用。"comment" 当然是可选的。
# 执行 POP 检查(仅分析服务器的横幅) option tcp-check tcp-check expect string +OK\ POP3\ ready comment POP\ protocol # 执行 IMAP 检查(仅分析服务器的横幅) option tcp-check tcp-check expect string *\ OK\ IMAP4\ ready comment IMAP\ protocol # 查找 redis 主服务器,在确保它能正常通信后 # 使用 redis 协议,然后正常退出。 # (发送一个命令,然后分析响应 3 次) option tcp-check tcp-check comment PING\ phase tcp-check send PING\r\n tcp-check expect string +PONG tcp-check comment role\ check tcp-check send info\ replication\r\n tcp-check expect string role:master tcp-check comment QUIT\ phase tcp-check send QUIT\r\n tcp-check expect string +OK 伪造一个 HTTP 请求,然后分析响应(在分析前发送多个头部) option tcp-check tcp-check comment forge\ and\ send\ HTTP\ request tcp-check send HEAD\ /\ HTTP/1.1\r\n tcp-check send Host:\ www.mydomain.com\r\n tcp-check send User-Agent:\ HAProxy\ tcpcheck\r\n tcp-check send \r\n tcp-check expect rstring HTTP/1\..\ (2..|3..) comment check\ HTTP\ response
启用或禁用在接受序列期间节省一个 ACK 数据包
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 否![]() |
当一个 HTTP 连接请求进入时,系统代表 HAProxy 对其进行确认,然后客户端立即发送其请求,系统在通知 HAProxy 新连接的同时也对其进行确认。HAProxy 随后读取请求并响应。这意味着系统发送了一个无用的 TCP ACK,因为该请求完全可以由 HAProxy 在发送响应时一并确认。因此,在 HTTP 模式下,HAProxy 会在支持此功能的平台(目前至少包括 Linux)上自动请求系统避免发送这个无用的 ACK。这应该不会引起任何问题,因为如果响应时间超过预期,系统无论如何都会在 40 毫秒后发送它。在复杂的网络调试会话中,可能需要禁用此优化,因为延迟的 ACK 在试图确定数据包延迟位置时会使故障排除变得更加复杂。此时可以通过指定 "no option tcp-smart-accept" 来恢复正常行为。也可以通过简单地指定 "option tcp-smart-accept" 来为非 HTTP 代理强制启用此功能。例如,对于一些服务器先说话的服务(如 SMTP),这样做可能是有意义的。建议避免在 defaults 部分强制设置此选项。如有疑问,请考虑在其前加上 "default" 关键字以恢复为自动值,或使用 "no" 关键字禁用它。
启用或禁用在连接序列期间节省一个 ACK 数据包
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
在某些系统(至少是 Linux)上,HAProxy 可以请求内核在收到连接请求时不立即发送一个空的 ACK,而是直接发送带有数据的请求。这可以在网络上节省一个数据包,从而提高性能。这对某些服务器也很有用,因为它们可以立即随传入连接一起获取请求。当在后端设置了 "option tcp-smart-connect" 时,此功能被启用。默认情况下不启用,因为它会使网络故障排除变得更加复杂。只在客户端先说话的协议(如 HTTP)中启用它才有意义。在其他情况下,如果没有数据可以代替 ACK 发送,则会发送一个正常的 ACK。如果此选项已在 "defaults" 部分启用,可以通过在其前面加上 "no" 关键字来在特定实例中禁用它。
启用或禁用在两侧发送 TCP keepalive 数据包
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
当客户端和服务器之间存在防火墙或任何会话感知组件,并且协议涉及非常长的会话和长时间的空闲期(例如:远程桌面)时,存在中间组件之一决定使空闲时间过长的会话过期的风险。启用套接字级别的 TCP keep-alive 使系统定期向连接的另一端发送数据包,使其保持活动状态。keep-alive 探测之间的延迟仅由系统控制,并取决于操作系统及其调整参数。重要的是要理解,keep-alive 数据包既不是在应用层发出也不是在应用层接收。只有网络堆栈才能看到它们。因此,即使代理的一侧已经使用 keep-alive 来维持其连接的活动状态,这些 keep-alive 数据包也不会被转发到代理的另一侧。请注意,这与 HTTP keep-alive 无关。使用选项 "tcpka" 会在连接的客户端和服务器两侧都启用 TCP keep-alive 探测的发送。请注意,这仅在 "defaults" 或 "listen" 部分有意义。如果此选项用于前端,则只有客户端会接收 keep-alive;如果此选项用于后端,则只有服务器端会接收 keep-alive。因此,当配置在前端和后端之间拆分时,强烈建议明确使用 "option clitcpka" 和 "option srvtcpka"。
启用包含会话状态和计时器的 TCP 连接高级日志记录
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
默认情况下,日志输出格式非常简陋,因为它只包含源地址和目标地址以及实例名称。通过指定 "option tcplog",每条日志行都会变成一种更丰富的格式,包括但不限于连接计时器、会话状态、连接数、前端、后端和服务器名称,当然还有源地址和端口。此选项对于纯 TCP 代理非常有用,以便找出客户端或服务器哪一方断开连接或超时。对于普通的 HTTP 代理,最好使用 "option httplog",它甚至更完整。此选项可以在前端或后端设置。"option tcplog" 会覆盖任何先前的 "log-format" 指令。
启用客户端透明代理
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
引入此选项是为了给第 3 层负载均衡器提供第 7 层持久性。其思想是利用操作系统的能力,将针对远程地址的传入连接重定向到本地进程(此处为 HAProxy),并让该进程知道最初请求的地址。使用此选项时,没有 cookie 的会话将被转发到传入请求的原始目标 IP 地址(该地址应与另一台设备的地址匹配),而带有 cookie 的请求仍将被转发到适当的服务器。请注意,与普遍看法相反,此选项不会使 HAProxy 在建立连接时向服务器呈现客户端的 IP。
执行外部检查时要运行的可执行文件
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
<command> 是要运行的外部命令
传递给命令的参数是: <proxy_address> <proxy_port> <server_address> <server_port> <proxy_address> 和 <proxy_port> 派生自第一个监听器,该监听器可以是 IPv4、IPv6 或 UNIX 套接字。如果是 UNIX 套接字监听器,proxy_address 将是套接字的路径,而 <proxy_port> 将是字符串 "NOT_USED"。在后端部分,无法确定监听器,<proxy_address> 和 <proxy_port> 的值都将是字符串 "NOT_USED"。一些值也通过环境变量提供。环境变量:HAPROXY_PROXY_ADDR 第一个绑定地址(如果可用)(如果不适用,则为空,例如在 "backend" 部分)。HAPROXY_PROXY_ID 后端 ID。HAPROXY_PROXY_NAME 后端名称。HAPROXY_PROXY_PORT 第一个绑定端口(如果可用)(如果不适用,则为空,例如在 "backend" 部分或对于 UNIX 套接字)。HAPROXY_SERVER_ADDR 服务器地址。HAPROXY_SERVER_CURCONN 服务器上的当前连接数。HAPROXY_SERVER_ID 服务器 ID。HAPROXY_SERVER_MAXCONN 服务器最大连接数。HAPROXY_SERVER_NAME 服务器名称。HAPROXY_SERVER_PORT 服务器端口(如果可用)(对于 UNIX 套接字为空)。PATH 执行命令时使用的 PATH 环境变量可以使用 "external-check path" 进行设置。如果命令执行并以零状态退出,则检查被视为通过,否则检查被视为失败。
external-check command /bin/true
运行外部检查时使用的 PATH 环境变量的值
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
<path> 是执行外部命令时使用的路径
默认路径为 ""。
external-check path "/usr/bin:/bin"
启用基于 RDP cookie 的持久性
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
<name> 是要检查的可选 RDP cookie 的名称。如果省略,将使用默认的 cookie 名称 "msts"。目前没有更改此名称的有效理由。
此语句启用基于 RDP cookie 的持久性。RDP cookie 包含在已知服务器列表中查找服务器所需的所有信息。因此,当在后端设置此选项时,将分析请求,如果找到 RDP cookie,则会对其进行解码。如果它匹配一个仍然处于 UP 状态的已知服务器(或者如果设置了 "option persist"),则连接将被转发到此服务器。请注意,这仅在 TCP 后端中有意义,但要使其工作,前端必须等待足够长的时间以确保请求缓冲区中存在 RDP cookie。这与 "rdp-cookie" 负载均衡方法的要求相同。因此,强烈建议将所有语句放在一个单独的 "listen" 部分中。此外,重要的是要理解,终端服务器只有在配置为“令牌重定向模式”时才会发出此 RDP cookie,这意味着“IP 地址重定向”选项被禁用。
listen tse-farm bind :3389 # 在请求中等待 RDP cookie 最多 5 秒 tcp-request inspect-delay 5s tcp-request content accept if RDP_COOKIE # 应用 RDP cookie 持久性 persist rdp-cookie # 如果服务器未知,让我们在相同的 cookie 上进行负载均衡。 # 或者,"balance leastconn" 也可能有用。 balance rdp-cookie server srv1 1.1.1.1:3389 server srv2 1.1.1.2:3389
设置前端每秒接受的新会话数限制
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 否![]() |
<rate> <rate> 参数是一个整数,指定前端每秒接受的最大新会话数。
当前端达到指定的新会话数/秒时,它将停止接受新的连接,直到速率再次降至限制以下。在此期间,待处理的会话将保存在套接字的 backlog 中(在系统缓冲区中),而 haproxy 甚至不会意识到有会话待处理。当对高负载服务应用非常低的限制时,使用 "backlog" 关键字增加套接字的 backlog 可能是有意义的。此功能在阻止基于连接的攻击或对脆弱服务器的服务滥用方面特别有效。由于会话速率每毫秒测量一次,因此它非常精确。此外,限制立即生效,完全不需要延迟来检测阈值。将 SMTP 的连接速率限制为最大每秒 10 个listen smtp mode tcp bind :25 rate-limit sessions 10 server smtp1 127.0.0.1:1025
注意:当达到最大速率时,前端的状态不会改变,但如果启用了 "socket-stats" 选项,其套接字在统计信息中将显示为 "WAITING"。
如果/除非条件匹配,则返回 HTTP 重定向
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 是![]() |
如果/除非条件匹配,HTTP 请求将导致重定向响应。如果未指定条件,则重定向无条件适用。
<loc> 使用 "redirect location",<loc> 中的确切值将被放入 HTTP "Location" 头部。当在 "http-request" 规则中使用时,<loc> 值遵循日志格式规则,并且可以包含一些动态值(请参阅第 8.2.4 节中的自定义日志格式)。<pfx> 使用 "redirect prefix","Location" 头部由 <pfx> 和完整的 URI 路径(包括查询字符串)连接而成,除非指定了 "drop-query" 选项(见下文)。作为特殊情况,如果 <pfx> 正好等于 "/",则不会在原始 URI 前插入任何内容。它允许重定向到相同的 URL(例如,插入 cookie)。当在 "http-request" 规则中使用时,<pfx> 值遵循日志格式规则,并且可以包含一些动态值(请参阅第 8.2.4 节中的自定义日志格式)。<sch> 使用 "redirect scheme","Location" 头部由 <sch> 与 "://"、然后是 "Host" 头部的第一次出现、然后是 URI 路径(包括查询字符串,除非指定了 "drop-query" 选项(见下文))连接而成。如果未找到路径或路径为 "*",则使用 "/" 代替。如果未找到 "Host" 头部,则将返回一个空的主机组件,大多数现代浏览器将其解释为重定向到相同的主机。此指令主要用于将 HTTP 重定向到 HTTPS。当在 "http-request" 规则中使用时,<sch> 值遵循日志格式规则,并且可以包含一些动态值(请参阅第 8.2.4 节中的自定义日志格式)。<code> 代码是可选的。它指示所需的 HTTP 重定向类型。仅支持代码 301、302、303、307 和 308,如果未指定代码,则默认使用 302。301 表示“永久移动”,浏览器可能会缓存该位置。302 表示“临时移动”,表示浏览器不应缓存重定向。303 等同于 302,只是浏览器将使用 GET 方法获取该位置。307 与 302 类似,但明确表示必须重用相同的方法。同样,如果必须使用相同的方法,308 会替换 301。<option> 有几个可以指定的选项来调整重定向的预期行为:- "drop-query" 当在基于前缀的重定向中使用此关键字时,位置将不带任何可能的查询字符串进行设置,这对于将用户引导到非安全页面很有用。它对位置类型的重定向没有影响。- "append-slash" 此关键字可与 "drop-query" 结合使用,以将使用不以 '/' 结尾的 URL 的用户重定向到带有 '/' 的相同 URL。这对于确保搜索引擎只看到一个 URL 很有用。为此,首选返回代码 301。- "set-cookie NAME[=value]" 将添加一个带有 NAME(以及可选的 "=value")的 "Set-Cookie" 头部到响应中。这有时用于指示用户已被看到,例如为了防范某些类型的 DoS。不添加其他 cookie 选项,因此该 cookie 将是会话 cookie。请注意,对于浏览器来说,仅有 cookie 名称而没有等号与带有等号的 cookie 是不同的。- "clear-cookie NAME[=]" 将添加一个带有 NAME(以及可选的 "=")的 "Set-Cookie" 头部,但 "Max-Age" 属性设置为零。这将告诉浏览器删除此 cookie。例如,在注销页面上很有用。重要的是要注意,清除 cookie "NAME" 不会删除使用 "NAME=value" 设置的 cookie。您必须清除 cookie "NAME=" 才能做到这一点,因为浏览器会区分它们。
仅将登录 URL 移动到 HTTPS。acl clear dst_port 80 acl secure dst_port 8080 acl login_page url_beg /login acl logout url_beg /logout acl uid_given url_reg /login?userid=[^&]+ acl cookie_set hdr_sub(cookie) SEEN=1 redirect prefix https://mysite.com set-cookie SEEN=1 if !cookie_set redirect prefix https://mysite.com if login_page !secure redirect prefix http://mysite.com drop-query if login_page !uid_given redirect location http://mysite.com/ if !login_page secure redirect location / clear-cookie USERID= if logout
为不带 '/' 的文章请求发送重定向。acl missing_slash path_reg ^/article/[^/]*$ redirect code 301 prefix / drop-query append-slash if missing_slash
当 SSL 由 haproxy 处理时,将所有 HTTP 流量重定向到 HTTPS。redirect scheme https if !{ ssl_fc }
在所有没有 'www.' 前缀的主机前添加该前缀http-request redirect code 301 location \ http://www.%[hdr(host)]%[capture.req.uri] \ unless { hdr_beg(host) -i www }
有关 ACL 的用法,请参见第 7 节。
启用或禁用连接失败时的会话重新分发
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
在 HTTP 模式下,如果由 cookie 指定的服务器宕机,客户端可能会因为无法清除 cookie 而一直固守在该服务器上,从而无法再访问该服务。指定 "redispatch" 将允许代理打破它们的持久性,并将它们重新分配到一个正常工作的服务器。它还允许在多次连接失败的情况下重试最后一次连接到另一台服务器。当然,这需要将 "retries" 设置为非零值。此形式已弃用,请不要在任何新配置中使用它,而应使用新的 "option redispatch"。
在 HTTP 请求的末尾添加一个头部
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 是![]() |
<string> 是要添加的完整行。任何空格或已知的定界符都必须使用反斜杠 ('\') 进行转义。有关 HTTP 头部操作的更多信息,请参阅第 6 节。<cond> 是一个可选的匹配条件,由 ACL 构建。当其他条件不满足时,它使得可以忽略此规则。
一个由 <string> 后跟一个换行符组成的新行将被添加到 HTTP 请求的最后一个头部之后。头部转换仅适用于通过 HAProxy 的流量,而不适用于由 HAProxy 生成的流量,例如健康检查或错误响应。
向来自端口 81 的请求添加 "X-Proto: SSL"acl is-ssl dst_port 81 reqadd X-Proto:\ SSL if is-ssl
如果某行匹配正则表达式,则明确允许该 HTTP 请求
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 是![]() |
<search> 是应用于 HTTP 头部和请求行的正则表达式。这是一个扩展正则表达式。支持括号分组,并且不需要预先的反斜杠。任何空格或已知的定界符都必须使用反斜杠 ('\') 进行转义。该模式一次应用于一整行。"reqallow" 关键字严格区分大小写,而 "reqiallow" 则忽略大小写。<cond> 是一个可选的匹配条件,由 ACL 构建。当其他条件不满足时,它使得可以忽略此规则。
包含任何匹配扩展正则表达式 <search> 的行的请求将被标记为允许,即使任何后续测试会导致拒绝。该测试同时适用于请求行和请求头部。请记住,请求行中的 URL 是区分大小写的,而头部名称则不是。使用 ACL 来编写访问策略更容易、更快、更强大。在新设计中应避免使用 Reqdeny、reqallow 和 reqpass。
# 允许 www.* 但拒绝 *.local reqiallow ^Host:\ www\. reqideny ^Host:\ .*\.local
删除 HTTP 请求中所有匹配正则表达式的头部
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 是![]() |
<search> 是应用于 HTTP 头部和请求行的正则表达式。这是一个扩展正则表达式。支持括号分组,并且不需要预先的反斜杠。任何空格或已知的定界符都必须使用反斜杠 ('\') 进行转义。该模式一次应用于一整行。"reqdel" 关键字严格区分大小写,而 "reqidel" 则忽略大小写。<cond> 是一个可选的匹配条件,由 ACL 构建。当其他条件不满足时,它使得可以忽略此规则。
请求中任何匹配扩展正则表达式 <search> 的头部行将被完全删除。此功能最常见的用途是在将请求传递给下一个服务器之前,从请求中删除不需要和/或危险的头部或 cookie。头部转换仅适用于通过 HAProxy 的流量,而不适用于由 HAProxy 生成的流量,例如健康检查或错误响应。请记住,头部名称不区分大小写。
# 删除 X-Forwarded-For 头部和 SERVER cookie reqidel ^X-Forwarded-For:.* reqidel ^Cookie:.*SERVER=
如果某行匹配正则表达式,则拒绝该 HTTP 请求
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 是![]() |
<search> 是应用于 HTTP 头部和请求行的正则表达式。这是一个扩展正则表达式。支持括号分组,并且不需要预先的反斜杠。任何空格或已知的定界符都必须使用反斜杠 ('\') 进行转义。该模式一次应用于一整行。"reqdeny" 关键字严格区分大小写,而 "reqideny" 则忽略大小写。<cond> 是一个可选的匹配条件,由 ACL 构建。当其他条件不满足时,它使得可以忽略此规则。
包含任何匹配扩展正则表达式 <search> 的行的请求将被标记为拒绝,即使任何后续测试会导致允许。该测试同时适用于请求行和请求头部。请记住,请求行中的 URL 是区分大小写的,而头部名称则不是。一旦解析完整个请求,被拒绝的请求将生成一个“HTTP 403 forbidden”响应。这与使用 ACL 的实践是一致的。使用 ACL 来编写访问策略更容易、更快、更强大。在新设计中应避免使用 Reqdeny、reqallow 和 reqpass。
# 拒绝 *.local, 然后允许 www.* reqideny ^Host:\ .*\.local reqiallow ^Host:\ www\.
在后续规则中忽略任何匹配正则表达式的 HTTP 请求行
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 是![]() |
<search> 是应用于 HTTP 头部和请求行的正则表达式。这是一个扩展正则表达式。支持括号分组,并且不需要预先的反斜杠。任何空格或已知的定界符都必须使用反斜杠 ('\') 进行转义。该模式一次应用于一整行。"reqpass" 关键字严格区分大小写,而 "reqipass" 则忽略大小写。<cond> 是一个可选的匹配条件,由 ACL 构建。当其他条件不满足时,它使得可以忽略此规则。
包含任何匹配扩展正则表达式 <search> 的行的请求将跳过后续规则,而不会分配任何拒绝或允许的裁决。该测试同时适用于请求行和请求头部。请记住,请求行中的 URL 是区分大小写的,而头部名称则不是。使用 ACL 来编写访问策略更容易、更快、更强大。在新设计中应避免使用 Reqdeny、reqallow 和 reqpass。
# 拒绝 *.local, 然后允许 www.*, 但忽略 "www.private.local" reqipass ^Host:\ www.private\.local reqideny ^Host:\ .*\.local reqiallow ^Host:\ www\.
在 HTTP 请求行中用一个字符串替换一个正则表达式
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 是![]() |
<search> 是应用于 HTTP 头部和请求行的正则表达式。这是一个扩展正则表达式。支持括号分组,并且不需要预先的反斜杠。任何空格或已知的定界符都必须使用反斜杠 ('\') 进行转义。该模式一次应用于一整行。"reqrep" 关键字严格区分大小写,而 "reqirep" 则忽略大小写。<string> 是要添加的完整行。任何空格或已知的定界符都必须使用反斜杠 ('\') 进行转义。可以使用常见的 \N 形式引用匹配的模式组,其中 N 是 0 到 9 之间的一个数字。有关 HTTP 头部操作的更多信息,请参阅第 6 节。<cond> 是一个可选的匹配条件,由 ACL 构建。当其他条件不满足时,它使得可以忽略此规则。
请求中任何匹配扩展正则表达式 <search> 的行(包括请求行和头部行)都将被完全替换为 <string>。此功能最常见的用途是在 "Host" 头部中重写 URL 或域名。头部转换仅适用于通过 HAProxy 的流量,而不适用于由 HAProxy 生成的流量,例如健康检查或错误响应。请注意,为了提高可读性,建议在请求和响应之间添加足够的空格。请记住,请求行中的 URL 是区分大小写的,而头部名称则不是。
# 在任何请求路径的开头将 "/static/" 替换为 "/"。 reqrep ^([^\ :]*)\ /static/(.*) \1\ /\2 # 在主机名中将 "www.mydomain.com" 替换为 "www"。 reqirep ^Host:\ www.mydomain.com Host:\ www
对包含匹配正则表达式的行的 HTTP 请求进行 tarpit 操作
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 是![]() |
<search> 是应用于 HTTP 头部和请求行的正则表达式。这是一个扩展正则表达式。支持括号分组,并且不需要预先的反斜杠。任何空格或已知的定界符都必须使用反斜杠 ('\') 进行转义。该模式一次应用于一整行。"reqtarpit" 关键字严格区分大小写,而 "reqitarpit" 则忽略大小写。<cond> 是一个可选的匹配条件,由 ACL 构建。当其他条件不满足时,它使得可以忽略此规则。
包含任何匹配扩展正则表达式 <search> 的行的请求将被 tarpit,这意味着它将连接到无处,保持打开预定义的时间,然后返回一个 HTTP 错误 500,这样攻击者就不会怀疑它已被 tarpit。状态 500 将在日志中报告,但完成标志将指示 "PT"。延迟由 "timeout tarpit" 定义,如果前者未设置,则由 "timeout connect" 定义。tarpit 的目标是减慢使用可识别请求攻击服务器的机器人。许多机器人限制其传出连接数,并保持连接等待可能需要几分钟才能到来的回复。根据环境和攻击情况,这在减少网络和防火墙负载方面可能特别有效。
# 忽略报告任何 "Mozilla" 或 "MSIE" 风格的用户代理,但是 # 阻止所有其他代理。 reqipass ^User-Agent:\.*(Mozilla|MSIE) reqitarpit ^User-Agent: # 阻止坏人 acl badguys src 10.1.0.3 172.16.13.20/28 reqitarpit . if badguys
设置连接失败后在服务器上执行的重试次数
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
<value> 是当连接被拒绝或超时时,应在服务器上重试连接尝试的次数。默认值为 3。
重要的是要理解,此值适用于连接尝试的次数,而不是完整的请求。当与服务器有效建立连接后,将不再进行重试。为了避免立即重新连接到正在重启的服务器,在重试发生之前会应用一个 min("timeout connect", 一秒) 的周转计时器。当设置了 "option redispatch" 时,即使 cookie 引用了不同的服务器,最后一次重试也可能在另一台服务器上执行。在 HTTP 响应的末尾添加一个头部
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 是![]() |
<string> 是要添加的完整行。任何空格或已知的定界符都必须使用反斜杠 ('\') 进行转义。有关 HTTP 头部操作的更多信息,请参阅第 6 节。<cond> 是一个可选的匹配条件,由 ACL 构建。当其他条件不满足时,它使得可以忽略此规则。
一个由 <string> 后跟一个换行符组成的新行将被添加到 HTTP 响应的最后一个头部之后。头部转换仅适用于通过 HAProxy 的流量,而不适用于由 HAProxy 生成的流量,例如健康检查或错误响应。
删除 HTTP 响应中所有匹配正则表达式的头部
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 是![]() |
<search> 是应用于 HTTP 头部和响应行的正则表达式。这是一个扩展正则表达式,因此支持括号分组,并且不需要预先的反斜杠。任何空格或已知的定界符都必须使用反斜杠 ('\') 进行转义。该模式一次应用于一整行。"rspdel" 关键字严格区分大小写,而 "rspidel" 则忽略大小写。<cond> 是一个可选的匹配条件,由 ACL 构建。当其他条件不满足时,它使得可以忽略此规则。
响应中任何匹配扩展正则表达式 <search> 的头部行将被完全删除。此功能最常见的用途是在将响应传递给客户端之前,从响应中删除不需要和/或敏感的头部或 cookie。头部转换仅适用于通过 HAProxy 的流量,而不适用于由 HAProxy 生成的流量,例如健康检查或错误响应。请记住,头部名称不区分大小写。
# 从响应中删除 Server 头部 rspidel ^Server:.*
如果某行匹配正则表达式,则阻止该 HTTP 响应
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 是![]() |
<search> 是应用于 HTTP 头部和响应行的正则表达式。这是一个扩展正则表达式,因此支持括号分组,并且不需要预先的反斜杠。任何空格或已知的定界符都必须使用反斜杠 ('\') 进行转义。该模式一次应用于一整行。"rspdeny" 关键字严格区分大小写,而 "rspideny" 则忽略大小写。<cond> 是一个可选的匹配条件,由 ACL 构建。当其他条件不满足时,它使得可以忽略此规则。
包含任何匹配扩展正则表达式 <search> 的行的响应将被标记为拒绝。该测试同时适用于响应行和响应头部。请记住,头部名称不区分大小写。此关键字的主要用途是防止敏感信息泄露,并在响应到达客户端之前阻止它。如果响应被拒绝,它将被替换为 HTTP 502 错误,以便客户端永远不会检索到任何敏感数据。使用 ACL 来编写访问策略更容易、更快、更强大。在新设计中应避免使用 Rspdeny。
# 确保没有匹配 ms-word 的内容类型会泄露 rspideny ^Content-type:\.*/ms-word
在 HTTP 响应行中用一个字符串替换一个正则表达式
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 是![]() |
<search> 是应用于 HTTP 头部和响应行的正则表达式。这是一个扩展正则表达式,因此支持括号分组,并且不需要预先的反斜杠。任何空格或已知的定界符都必须使用反斜杠 ('\') 进行转义。该模式一次应用于一整行。"rsprep" 关键字严格区分大小写,而 "rspirep" 则忽略大小写。<string> 是要添加的完整行。任何空格或已知的定界符都必须使用反斜杠 ('\') 进行转义。可以使用常见的 \N 形式引用匹配的模式组,其中 N 是 0 到 9 之间的一个数字。有关 HTTP 头部操作的更多信息,请参阅第 6 节。<cond> 是一个可选的匹配条件,由 ACL 构建。当其他条件不满足时,它使得可以忽略此规则。
响应中任何匹配扩展正则表达式 <search> 的行(包括响应行和头部行)都将被完全替换为 <string>。此功能最常见的用途是重写 Location 头部。头部转换仅适用于通过 HAProxy 的流量,而不适用于由 HAProxy 生成的流量,例如健康检查或错误响应。请注意,为了提高可读性,建议在请求和响应之间添加足够的空格。请记住,头部名称不区分大小写。
# 将 "Location: 127.0.0.1:8080" 替换为 "Location: www.mydomain.com" rspirep ^Location:\ 127.0.0.1:8080 Location:\ www.mydomain.com
在后端中声明一个服务器
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 否![]() | 是![]() | 是![]() |
<name> 是分配给此服务器的内部名称。此名称将出现在日志和警报中。如果设置了 "http-send-name-header",它将被添加到发送给服务器的请求头中。<address> 是服务器的 IPv4 或 IPv6 地址。或者,也支持可解析的主机名,但此名称将在启动期间解析。地址 "0.0.0.0" 或 "*" 具有特殊含义。它表示连接将被转发到与客户端连接相同的 IP 地址。这在透明代理架构中很有用,其中客户端的连接被拦截,并且 haproxy 必须转发到原始目标地址。这或多或少与 "transparent" 关键字所做的相同,只是使用服务器可以限制并发性并报告统计信息。可选地,可以在地址前使用地址族前缀来强制指定地址族,而不管地址格式如何,这对于指定没有斜杠 ('/') 的 unix 套接字路径很有用。目前支持的前缀有:- 'ipv4@' -> 地址始终为 IPv4 - 'ipv6@' -> 地址始终为 IPv6 - 'unix@' -> 地址是本地 unix 套接字的路径 - 'abns@' -> 地址在抽象命名空间中(仅限 Linux)。您可能希望在地址参数中引用一些环境变量,请参阅关于环境变量的第 2.3 节。<port> 是一个可选的端口规范。如果设置了,所有连接都将发送到此端口。如果未设置,将使用客户端连接的相同端口。端口也可以用 "+" 或 "-" 作为前缀。在这种情况下,服务器的端口将通过将此值添加到客户端端口来确定。<param*> 是此服务器的参数列表。"server" 关键字接受大量选项,并有一个专门的部分介绍它。更多详情请参阅第 5 节。
server first 10.1.1.1:1080 cookie first check inter 1000 server second 10.1.1.2:1080 cookie second check inter 1000 server transp ipv4@ server backup "${SRV_BACKUP}:1080" backup server www1_dc1 "${LAN_DC1}.101:80" server www1_dc2 "${LAN_DC2}.101:80"
注意:关于 Linux 的抽象命名空间套接字,HAProxy 使用整个 sun_path 长度作为地址长度。其他一些程序,如 socat,默认只使用字符串长度。在 socat 中对任何抽象套接字定义传递选项 ",unix-tightsocklen=0",以使其与 HAProxy 兼容。
设置要读取、加载并应用于此后端中可用服务器的服务器状态文件。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 否![]() | 是![]() | 是![]() |
它仅在指令 "load-server-state-from-file" 设置为 "local" 时适用。当未提供 <file> 时,如果使用了 "use-backend-name" 或未设置此指令,则使用后端名称。如果 <file> 以斜杠 '/' 开头,则它被视为绝对路径。否则,<file> 将与全局指令 "server-state-base" 连接。
下面的最小配置将使 HAProxy 查找状态服务器文件 '/etc/haproxy/states/bk'global server-state-file-base /etc/haproxy/states backend bk load-server-state-from-file
设置出站连接的源地址
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
<addr> 是 HAProxy 在连接到服务器之前将绑定的 IPv4 地址。此地址也用作健康检查的源。默认值 0.0.0.0 表示系统将选择最合适的地址以到达其目的地。可选地,可以在地址前使用地址族前缀来强制指定地址族,而不管地址格式如何,这对于指定没有斜杠 ('/') 的 unix 套接字路径很有用。目前支持的前缀有:- 'ipv4@' -> 地址始终为 IPv4 - 'ipv6@' -> 地址始终为 IPv6 - 'unix@' -> 地址是本地 unix 套接字的路径 - 'abns@' -> 地址在抽象命名空间中(仅限 Linux)。您可能希望在地址参数中引用一些环境变量,请参阅关于环境变量的第 2.3 节。<port> 是一个可选的端口。通常不需要,但在某些非常特定的上下文中可能有用。默认值零表示系统将选择一个空闲端口。请注意,后端不支持端口范围。如果要强制端口范围,必须在每个 "server" 行上指定它们。<addr2> 是在完全透明代理模式下转发连接时向服务器呈现的 IP 地址。目前仅在某些打了补丁的 Linux 内核上支持。指定此地址后,连接到服务器的客户端将看到此地址,而健康检查仍将使用地址 <addr>。<port2> 是在完全透明代理模式下转发连接时向服务器呈现的可选端口(参见上面的 <addr2>)。默认值零表示系统将选择一个空闲端口。<hdr> 是一个 HTTP 头部的名称,从中获取要绑定的 IP。这是一个逗号分隔的头部列表的名称,可以包含多个 IP 地址。默认情况下,使用最后一次出现的值。这旨在与 X-Forwarded-For 头部一起工作,并自动绑定到先前代理所见的客户端 IP 地址,通常是 Stunnel。为了使用最后一次出现之外的其他出现,请参阅下面的 <occ> 参数。当未找到头部(或出现)时,不执行绑定,以便使用代理的默认 IP 地址。另请记住,与任何 HTTP 头部一样,头部名称不区分大小写。<occ> 是多值头部中要使用的值的出现次数。这与 "hdr_ip(<hdr>)" 结合使用,以指定要用于源 IP 地址的出现次数。正值表示从第一次出现开始的位置,1 是第一个。负值表示相对于最后一次出现的位置,-1 是最后一个。这对于在基础设施入口点设置了 X-Forwarded-For 头部,并且必须在几个代理层之后使用它的情况很有帮助。如果未指定此值,则假定为 -1。在此处传递零将禁用该功能。<name> 是一个可选的接口名称,用于绑定出站流量。在支持此功能的系统(目前仅限 Linux)上,这允许将所有到服务器的流量绑定到此接口,即使它不是系统根据路由表选择的接口。应极其谨慎地使用此选项。请注意,使用此选项需要 root 权限。
"source" 关键字在复杂环境中很有用,其中只允许特定地址连接到服务器。当必须通过公共网关使用私有地址时可能需要它,并且已知系统无法自行确定适当的源地址。在某些打了补丁的 Linux 内核上可用的一个扩展可以通过可选关键字 "usesrc" 使用。它使得可以使用不属于系统本身的 IP 地址连接到服务器。这被称为“完全透明代理模式”。要使其工作,目标服务器必须通过运行 HAProxy 的机器将其流量路由回此地址,并且通常需要在此机器上启用 IP 转发。在这种“完全透明代理”模式下,可以强制向服务器呈现特定的 IP 地址。实际上这并不常用。更常见的用途是告诉 HAProxy 呈现客户端的 IP 地址。为此,有两种方法:- 呈现客户端的 IP 和端口地址。这是最透明的模式,但当机器上启用了 IP 连接跟踪时可能会导致问题,因为同一连接可能会以不同状态出现两次。但是,此解决方案具有不将系统限制在 64k 个传出地址+端口对的巨大优势,因为可以使用所有客户端范围。- 仅呈现客户端的 IP 地址并选择一个备用端口。此解决方案仍然相当优雅,但透明度稍差(下游防火墙日志将与上游的不匹配)。它还存在将并发连接数限制为通常的 64k 个端口的缺点。但是,由于上游和下游端口不同,机器上的本地 IP 连接跟踪不会因重用同一会话而受到干扰。此选项为后端中的所有服务器设置默认源。它也可以在 "defaults" 部分中指定。可以使用服务器级别的 "source" 服务器选项进行更精细的源地址规范。有关更多信息,请参阅第 5 节。为了工作,"usesrc" 需要 root 权限。
backend private # 使用我们的 192.168.1.200 源地址连接到服务器 source 192.168.1.200 backend transparent_ssl1 # 从客户端的源地址连接到 SSL 场 source 192.168.1.200 usesrc clientip backend transparent_ssl2 # 从客户端的源地址和端口连接到 SSL 场 # 如果本地机器上有 IP conntrack,则不推荐。 source 192.168.1.200 usesrc client backend transparent_ssl3 # 从客户端的源地址连接到 SSL 场。它 # 对 conntrack 更友好。 source 192.168.1.200 usesrc clientip backend transparent_smtp # 从客户端的源地址/端口连接到 SMTP 场 # 使用 Tproxy 版本 4。 source 0.0.0.0 usesrc clientip backend transparent_http # 使用先前代理所见的客户端 IP 连接到服务器 # 。 source 0.0.0.0 usesrc hdr_ip(x-forwarded-for,-1)
设置服务器端的最大不活动时间。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
<timeout> 是默认以毫秒为单位指定的超时值,但如果数字后缀有单位,则可以是任何其他单位,如本文档开头所述。
不活动超时适用于期望服务器确认或发送数据时。在 HTTP 模式下,此超时在服务器响应的第一阶段(当它必须发送头部时)尤为重要,因为它直接代表了请求的服务器处理时间。要确定在此处放置什么值,通常最好从被认为是不可接受的响应时间开始,然后检查日志以观察响应时间分布,并相应地调整该值。该值默认以毫秒为单位指定,但如果数字后缀有单位,则可以是任何其他单位,如本文档开头所述。在 TCP 模式下(以及在较小程度上,在 HTTP 模式下),强烈建议客户端超时与服务器超时保持相等,以避免调试复杂情况。无论预期的服务器响应时间如何,最好通过指定略高于 3 秒倍数的超时(例如:最少 4 或 5 秒)来覆盖至少一个或多个 TCP 数据包丢失。此参数特定于后端,但可以在 "defaults" 部分中一次性为所有后端指定。这实际上是避免忘记它的最简单解决方案之一。未指定的超时会导致无限超时,这是不推荐的。这种用法被接受并且有效,但在启动期间会报告警告,因为如果系统的超时也未配置,可能会导致系统中过期会话的累积。此参数是为兼容性而提供的,但目前已弃用。请改用 "timeout server"。
如果/除非条件匹配,则启用统计信息管理级别
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 是![]() |
此语句在条件匹配时启用统计信息管理级别。管理级别允许从 Web 界面启用/禁用服务器。出于安全原因,默认情况下,统计信息页面是只读的。注意:除非您知道自己在做什么,否则请考虑不要在多进程模式(nbproc > 1)下使用此功能:进程之间不共享内存,这可能导致随机行为。目前,POST 请求受限于缓冲区大小减去保留的缓冲区空间,这意味着如果服务器列表太长,请求将不会被处理。建议一次更改少量服务器。
# 仅对 localhost 启用统计信息管理级别 backend stats_localhost stats enable stats admin if LOCALHOST
# 由于身份验证,统计信息管理级别始终启用 backend stats_auth stats enable stats auth admin:AdMiN123 stats admin if TRUE
# 统计信息管理级别取决于经过身份验证的用户 userlist stats-auth group admin users admin user admin insecure-password AdMiN123 group readonly users haproxy user haproxy insecure-password haproxy backend stats_auth stats enable acl AUTH http_auth(stats-auth) acl AUTH_ADMIN http_auth_group(stats-auth) admin stats http-request auth unless AUTH stats admin if AUTH_ADMIN
启用带身份验证的统计信息,并为一个账户授予访问权限
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
<user> 是要授予访问权限的用户名 <passwd> 是与此用户关联的明文密码
此语句启用具有默认设置的统计信息,并将访问权限仅限于已声明的用户。可以根据需要重复多次此语句,以允许任意数量的用户。当用户尝试在没有有效账户的情况下访问统计信息时,将返回“401 Forbidden”响应,以便浏览器要求用户提供有效的用户名和密码。返回给浏览器的 realm(领域)可以使用“stats realm”进行配置。由于身份验证方法是 HTTP 基本认证,密码在网络上以明文形式传输。因此,决定配置文件也使用明文密码,以提醒用户这些密码不应是敏感的,也不应与任何其他账户共享。还可以使用“stats scope”来缩小报告中出现的代理范围。虽然此语句本身足以启用统计报告,但建议设置所有其他设置,以避免依赖默认的不明显参数。
# 公共访问(仅限于此后端) backend public_www server srv1 192.168.0.1:80 stats enable stats hide-version stats scope . stats uri /admin?stats stats realm Haproxy\ Statistics stats auth admin1:AdMiN123 stats auth admin2:AdMiN321 # 内部监控访问(无限制) backend private_monitoring stats enable stats uri /admin?stats stats refresh 5s
使用默认设置启用统计报告
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
此语句使用构建时定义的默认设置启用统计报告。除非另有说明,否则将使用以下设置:- stats uri : /haproxy?stats - stats realm : "HAProxy Statistics" - stats auth : 无身份验证 - stats scope : 无限制 尽管此语句本身足以启用统计报告,但建议设置所有其他设置,以避免依赖默认的不明显参数。
# 公共访问(仅限于此后端) backend public_www server srv1 192.168.0.1:80 stats enable stats hide-version stats scope . stats uri /admin?stats stats realm Haproxy\ Statistics stats auth admin1:AdMiN123 stats auth admin2:AdMiN321 # 内部监控访问(无限制) backend private_monitoring stats enable stats uri /admin?stats stats refresh 5s
启用统计信息并隐藏 HAProxy 版本报告
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
默认情况下,统计页面会报告一些有用的状态信息以及统计数据。其中包括 HAProxy 的版本。但是,通常认为向任何人报告精确的版本是危险的,因为它可能帮助他们利用已知弱点进行特定攻击。“stats hide-version”语句从统计报告中移除版本信息。建议对公共站点或任何具有弱登录名/密码的站点使用此功能。尽管此语句本身足以启用统计报告,但建议设置所有其他设置,以避免依赖默认的不明显参数。
# 公共访问(仅限于此后端) backend public_www server srv1 192.168.0.1:80 stats enable stats hide-version stats scope . stats uri /admin?stats stats realm Haproxy\ Statistics stats auth admin1:AdMiN123 stats auth admin2:AdMiN321 # 内部监控访问(无限制) backend private_monitoring stats enable stats uri /admin?stats stats refresh 5s
统计信息的访问控制
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 否![]() | 是![]() | 是![]() |
与“http-request”一样,这组选项允许精细控制对统计信息的访问。每个选项后面可以跟 if/unless 和 acl。第一个匹配条件(或无条件的选项)的选项是最终的。对于“deny”,将返回 403 错误;对于“allow”,将执行正常处理;对于“auth”,将返回 401/407 错误代码,以便客户端被要求输入用户名和密码。每个实例的 http-request 语句数量没有固定限制。
启用统计信息并设置身份验证领域
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
<realm> 是报告给浏览器的 HTTP 基本认证领域的名称。浏览器用它在弹出窗口中显示,邀请用户输入有效的用户名和密码。
领域被读取为单个词,因此其中的任何空格都应使用反斜杠('\')进行转义。此语句仅在与“stats auth”结合使用时才有用,因为它只与身份验证相关。尽管此语句本身足以启用统计报告,但建议设置所有其他设置,以避免依赖默认的不明显参数。
# 公共访问(仅限于此后端) backend public_www server srv1 192.168.0.1:80 stats enable stats hide-version stats scope . stats uri /admin?stats stats realm Haproxy\ Statistics stats auth admin1:AdMiN123 stats auth admin2:AdMiN321 # 内部监控访问(无限制) backend private_monitoring stats enable stats uri /admin?stats stats refresh 5s
启用带自动刷新的统计信息
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
<delay> 是建议的刷新延迟,以秒为单位指定,它将返回给查看报告页面的浏览器。虽然浏览器可以自由应用任何延迟,但通常会遵守它并每隔这么多秒刷新一次页面。刷新间隔可以用任何其他非默认的时间单位指定,方法是在值后面加上单位后缀,如本文档开头所述。
此语句在监控显示器上非常有用,可以永久显示报告负载均衡器活动的页面。设置后,HTML 报告页面将包含一个“刷新”/“停止刷新”的链接,以便用户可以选择是否希望页面自动刷新。尽管此语句本身足以启用统计报告,但建议设置所有其他设置,以避免依赖默认的不明显参数。
# 公共访问(仅限于此后端) backend public_www server srv1 192.168.0.1:80 stats enable stats hide-version stats scope . stats uri /admin?stats stats realm Haproxy\ Statistics stats auth admin1:AdMiN123 stats auth admin2:AdMiN321 # 内部监控访问(无限制) backend private_monitoring stats enable stats uri /admin?stats stats refresh 5s
启用统计信息并限制访问范围
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
<name> 是要报告的 listen、frontend 或 backend 部分的名称。特殊名称“.”(一个点)表示该语句所在的节。
指定此语句后,只有使用此语句枚举的部分才会出现在报告中。所有其他部分都将被隐藏。如果需要报告多个部分,此语句可以根据需要出现多次。请注意,名称检查是作为简单的字符串比较执行的,并且从不检查给定的部分名称是否真的存在。尽管此语句本身足以启用统计报告,但建议设置所有其他设置,以避免依赖默认的不明显参数。
# 公共访问(仅限于此后端) backend public_www server srv1 192.168.0.1:80 stats enable stats hide-version stats scope . stats uri /admin?stats stats realm Haproxy\ Statistics stats auth admin1:AdMiN123 stats auth admin2:AdMiN321 # 内部监控访问(无限制) backend private_monitoring stats enable stats uri /admin?stats stats refresh 5s
在统计页面上启用描述的报告。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
<desc> 是一个可选的要报告的描述。如果未指定,则自动使用全局部分的描述。此语句对于向客户提供共享服务的用户非常有用,其中每个客户的节点或描述应该不同。尽管此语句本身足以启用统计报告,但建议设置所有其他设置,以避免依赖默认的不明显参数。默认情况下不显示描述。
# 内部监控访问(无限制) backend private_monitoring stats enable stats show-desc Master node for Europe, Asia, Africa stats uri /admin?stats stats refresh 5s
在统计页面上启用额外信息的报告
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
在统计页面上启用额外信息的报告: - cap: 功能 (proxy) - mode: tcp、http 或 health 之一 (proxy) - id: SNMP ID (proxy, socket, server) - IP (socket, server) - cookie (backend, server) 尽管此语句本身足以启用统计报告,但建议设置所有其他设置,以避免依赖默认的不明显参数。默认行为是不显示此信息。
在统计页面上启用主机名的报告。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
<name> 是一个可选的要报告的名称。如果未指定,则自动使用全局部分的节点名称。
此语句对于向客户提供共享服务的用户非常有用,其中为每个客户提供的统计页面上的节点或描述可能不同。默认行为是不显示主机名。尽管此语句本身足以启用统计报告,但建议设置所有其他设置,以避免依赖默认的不明显参数。
# 内部监控访问(无限制) backend private_monitoring stats enable stats show-node Europe-1 stats uri /admin?stats stats refresh 5s
启用统计信息并定义访问它们的 URI 前缀
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
<prefix> 是任何将被重定向到统计信息的 URI 的前缀。此前缀可能包含一个问号('?')以指示查询字符串的一部分。
统计 URI 在中继的流量上被拦截,因此它看起来像是正常应用程序中的一个页面。强烈建议确保所选的 URI 永远不会出现在应用程序中,否则将永远无法在应用程序中访问它。haproxy 中编译的默认 URI 是 "/haproxy?stats",但这可以在构建时更改,所以最好总是明确地在此处指定它。在 URI 中包含问号通常是一个好主意,这样中间代理就不会缓存结果。此外,由于任何以该前缀开头的字符串都将被接受为统计请求,问号有助于确保没有有效的 URI 会以相同的词开头。有时将 "/" 用作 URI 前缀非常方便,并将其放在自己的 "listen" 实例中。这使得将一个地址或端口专门用于统计信息变得容易。尽管此语句本身足以启用统计报告,但建议设置所有其他设置,以避免依赖默认的不明显参数。
# 公共访问(仅限于此后端) backend public_www server srv1 192.168.0.1:80 stats enable stats hide-version stats scope . stats uri /admin?stats stats realm Haproxy\ Statistics stats auth admin1:AdMiN123 stats auth admin2:AdMiN321 # 内部监控访问(无限制) backend private_monitoring stats enable stats uri /admin?stats stats refresh 5s
定义一个请求模式匹配条件,以将用户粘滞到一台服务器上
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 否![]() | 是![]() | 是![]() |
<pattern> 是一个样本表达式规则,如 第 7.3 节 所述。它描述了将分析传入请求或连接的哪些元素,以期在粘滞表中找到匹配的条目。此规则是强制性的。<table> 是一个可选的粘滞表名称。如果未指定,则使用同一后端的表。粘滞表使用“stick-table”语句声明。<cond> 是一个可选的匹配条件。它使得只有在满足(或不满足)其他条件时才可能在某个标准上进行匹配。例如,它可以用于匹配源 IP 地址,除非请求通过一个已知的代理,在这种情况下,我们将匹配包含该 IP 地址的头部。
某些协议或应用程序需要复杂的粘滞规则,不能总是简单地依赖 Cookie 或哈希。“stick match”语句描述了一个从传入请求或连接中提取粘滞标准的规则。有关可能的模式和转换规则的完整列表,请参见第 7 节。表必须使用“stick-table”语句声明。它必须是与模式兼容的类型。默认情况下,它是存在于同一后端的那个。可以通过使用“table”关键字引用其他后端的表来共享一个表。如果引用了另一个表,则使用后端内部的服务器 ID。默认情况下,每个后端中的所有服务器 ID 都从 1 开始,因此服务器排序就足够了。但如有疑问,强烈建议使用其“id”设置强制指定服务器 ID。可以使用“if”或“unless”后跟一个条件来限制“stick match”语句应用的条件。有关基于 ACL 的条件,请参见第 7 节。“stick match”语句的数量没有限制。第一个应用并匹配的语句将导致请求被定向到与创建该条目的请求所使用的同一台服务器。这样,多个匹配可以用作回退。粘滞规则在持久性 Cookie 之后检查,因此如果已经使用 Cookie 选择了一台服务器,它们不会影响粘滞性。这样,插入 Cookie 并匹配 IP 地址以在 HTTP 和 HTTPS 之间保持粘滞性变得非常容易。注意:除非您知道自己在做什么,否则请考虑不要在多进程模式(nbproc > 1)下使用此功能:内存不在进程之间共享,这可能导致随机行为。
# 将 SMTP 用户转发到他们在过去 30 分钟内 # 刚刚用于 POP 的同一台服务器 backend pop mode tcp balance roundrobin stick store-request src stick-table type ip size 200k expire 30m server s1 192.168.1.1:110 server s2 192.168.1.1:110 backend smtp mode tcp balance roundrobin stick match src table pop server s1 192.168.1.1:25 server s2 192.168.1.1:25
定义一个请求模式,将用户与服务器关联起来
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 否![]() | 是![]() | 是![]() |
注意:此形式完全等同于后跟“stick store-request”的“stick match”,所有参数都相同。有关详细信息,请参阅这两个关键字。它仅为编写更易于维护的配置提供便利。注意:除非您知道自己在做什么,否则请考虑不要在多进程模式(nbproc > 1)下使用此功能:内存不在进程之间共享,这可能导致随机行为。
# 以下形式... stick on src table pop if !localhost # ...与此形式完全等价: stick match src table pop if !localhost stick store-request src table pop if !localhost # 对 HTTP 使用 cookie 持久性,对 HTTPS 以及 # 没有 cookie 的 HTTP 使用源地址粘滞。在两种访问之间共享同一个表。 backend http mode http balance roundrobin stick on src table https cookie SRV insert indirect nocache server s1 192.168.1.1:80 cookie s1 server s2 192.168.1.1:80 cookie s2 backend https mode tcp balance roundrobin stick-table type ip size 200k expire 30m stick on src server s1 192.168.1.1:443 server s2 192.168.1.1:443
定义一个用于在粘滞表中创建条目的请求模式
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 否![]() | 是![]() | 是![]() |
<pattern> 是一个样本表达式规则,如 第 7.3 节 所述。它描述了在选择服务器后,将分析、提取并存储到表中的传入请求或连接的哪些元素。<table> 是一个可选的粘滞表名称。如果未指定,则使用同一后端的表。粘滞表使用“stick-table”语句声明。<cond> 是一个可选的存储条件。它使得只有在满足(或不满足)某些条件时才可能存储某些标准。例如,它可以用于存储源 IP 地址,除非请求通过一个已知的代理,在这种情况下,我们将存储一个转换后的包含该 IP 地址的头部。
某些协议或应用程序需要复杂的粘滞规则,并且不能总是简单地依赖 Cookie 或哈希。“stick store-request”语句描述了一个规则,用于决定从请求中提取什么以及何时提取,以便将其存储到粘滞表中,供后续请求使用“stick match”语句进行匹配。显然,提取的部分必须有意义,并且有机会在后续请求中被匹配。例如,存储客户端的 IP 地址通常是有意义的。存储在 URL 参数中找到的 ID 也是有意义的。存储源端口几乎没有任何意义,因为它会被随机匹配。有关可能的模式和转换规则的完整列表,请参见第 7 节。表必须使用“stick-table”语句声明。它必须是与模式兼容的类型。默认情况下,它是存在于同一后端的那个。可以通过使用“table”关键字引用其他后端的表来共享一个表。如果引用了另一个表,则使用后端内部的服务器 ID。默认情况下,每个后端中的所有服务器 ID 都从 1 开始,因此服务器排序就足够了。但如有疑问,强烈建议使用其“id”设置强制指定服务器 ID。可以使用“if”或“unless”后跟一个条件来限制“stick store-request”语句应用的条件。此条件将在解析请求时评估,因此可以使用任何标准。有关基于 ACL 的条件,请参见第 7 节。“stick store-request”语句的数量没有限制,但每个请求或响应同时存储的数量限制为 8 个。这使得可以存储多达 8 个标准,所有标准都从请求或响应中提取,无论规则数量如何。只有前 8 个匹配的规则会被保留。使用此功能,可以一次性填充多个表,以期增加在另一协议或访问方法上识别用户的机会。使用多个 store-request 规则与同一个表是可能的,并且可以通过按偏好降序排列规则来找到最佳的依赖标准。对于给定的表,只会存储第一个提取的标准。所有后续引用同一表的 store-request 规则都将被跳过,并且它们的 ACL 不会被评估。“store-request”规则在建立服务器连接后进行评估,以便表中包含处理该请求的真实服务器。注意:除非您知道自己在做什么,否则请考虑不要在多进程模式(nbproc > 1)下使用此功能:内存不在进程之间共享,这可能导致随机行为。
# 将 SMTP 用户转发到他们在过去 30 分钟内 # 刚刚用于 POP 的同一台服务器 backend pop mode tcp balance roundrobin stick store-request src stick-table type ip size 200k expire 30m server s1 192.168.1.1:110 server s2 192.168.1.1:110 backend smtp mode tcp balance roundrobin stick match src table pop server s1 192.168.1.1:25 server s2 192.168.1.1:25
为当前部分配置粘滞表
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 是![]() |
ip 用 "type ip" 声明的表将只存储 IPv4 地址。这种形式非常紧凑(每个条目约 50 字节),并且允许非常快速的条目查找和存储,几乎没有开销。这主要用于存储客户端源 IP 地址。 ipv6 用 "type ipv6" 声明的表将只存储 IPv6 地址。这种形式非常紧凑(每个条目约 60 字节),并且允许非常快速的条目查找和存储,几乎没有开销。这主要用于存储客户端源 IP 地址。 integer 用 "type integer" 声明的表将存储 32 位整数,可以表示在请求中找到的客户端标识符。 string 用 "type string" 声明的表将存储最多 <len> 个字符的子字符串。如果模式提取器提供的字符串大于 <len>,它将在存储前被截断。在匹配期间,表中的字符串和提取的模式之间最多比较 <len> 个字符。如果未指定,字符串将自动限制为 32 个字符。 binary 用 "type binary" 声明的表将存储 <len> 字节的二进制块。如果模式提取器提供的块大于 <len>,它将在存储前被截断。如果样本表达式提供的块短于 <len>,它将被 0 填充。如果未指定,块将自动限制为 32 字节。 <length> 是将存储在 "string" 类型表中的最大字符数(参见上面的 "string" 类型)。或者是 "binary" 类型表中块的字节数。更改此参数时要小心,因为内存使用量会成比例增加。 <size> 是表中可以容纳的最大条目数。此值直接影响内存使用。每个条目大约计算 50 字节,外加字符串的大小(如果有)。大小支持后缀 "k"、"m"、"g",分别表示 2^10、2^20 和 2^30 的因子。 [nopurge] 表示当表已满时我们拒绝清除旧条目。如果未指定此参数且当 haproxy 想在表中存储一个条目时表已满,它将刷新一些最旧的条目以便为新条目释放空间。这通常是期望的行为。在某些特定情况下,可能希望拒绝新条目而不是清除旧条目。这可能是在存储的数据量远超硬件限制,并且我们宁愿不为新客户端提供访问,也不愿拒绝已经连接的客户端的情况下。使用此参数时,请务必正确设置 "expire" 参数(见下文)。 <peersect> 是用于复制的 peers 部分的名称。将键与服务器 ID 关联的条目与在此部分中声明的远程对等体保持同步。所有条目在软重启期间也会自动从本地对等体(旧进程)学习。注意:每个 peers 部分只能被属于同一唯一进程的表引用。 <expire> 定义了表中条目自上次创建、刷新或匹配以来的最长持续时间。过期延迟使用标准时间格式定义,类似于各种超时。最大持续时间略高于 24 天。有关更多信息,请参见第 2.4 节。如果未指定此延迟,会话不会自动过期,但一旦表满,较旧的条目将被删除。如果没有指定过期延迟,请确保不要使用 "nopurge" 参数。 <data_type> 用于在粘滞表中存储额外信息。ACL 可以使用它来控制与匹配粘滞表的客户端活动相关的各种标准。对于此处指定的每个项目,每个条目的大小都会增加,以便容纳额外的数据。一个条目可以存储多种数据类型。可以在 "store" 关键字后指定多种数据类型,以逗号分隔的列表形式。或者,可以重复 "store" 关键字,后跟一个或多个数据类型。除了自动检测和启用的 "server_id" 类型外,所有数据类型都必须明确声明才能存储。如果 ACL 引用了未存储的数据类型,则该 ACL 将不会匹配。一些数据类型需要一个参数,该参数必须紧跟在类型后面的括号中传递。有关支持的数据类型及其参数,请参见下文。
可以与条目一起存储的数据类型如下:- server_id:这是一个整数,保存请求被分配到的服务器的数字 ID。它被“stick match”、“stick store”和“stick on”规则使用。在被引用时会自动启用。- gpc0:第一个通用计数器。它是一个正的 32 位整数,可用于任何目的。大多数情况下,它将用于在某些条目上打上特殊标记,例如记录检测到特定行为,并且必须为将来的匹配所知。- gpc0_rate(<period>):在一个周期内第一个通用计数器的增量率。它是一个正的 32 位整数,可用于任何目的。就像 <gpc0> 一样,它计算事件,但不是保持累积计数,而是维护计数器递增的速率。大多数情况下,它将用于测量某些事件的发生频率(例如:对特定 URL 的请求)。- conn_cnt:连接数。它是一个正的 32 位整数,计算从匹配此条目的客户端接收到的绝对连接数。这并不意味着连接被接受,只是它们被接收了。- conn_cur:当前连接数。它是一个正的 32 位整数,存储该条目的并发连接数。一旦传入连接匹配该条目,它就会递增;一旦连接离开,它就会递减。这样就可以随时知道一个条目的确切并发连接数。- conn_rate(<period>):频率计数器(占用 12 字节)。它接受一个整数参数 <period>,该参数以毫秒为单位指示测量平均值的周期长度。它报告该周期内的平均传入连接速率,单位为连接数/周期。结果是一个整数,可以使用 ACL 进行匹配。- sess_cnt:会话数。它是一个正的 32 位整数,计算从匹配此条目的客户端接收到的绝对会话数。会话是第 4 层规则接受的连接。- sess_rate(<period>):频率计数器(占用 12 字节)。它接受一个整数参数 <period>,该参数以毫秒为单位指示测量平均值的周期长度。它报告该周期内的平均传入会话速率,单位为会话数/周期。结果是一个整数,可以使用 ACL 进行匹配。- http_req_cnt:HTTP 请求数。它是一个正的 32 位整数,计算从匹配此条目的客户端接收到的绝对 HTTP 请求数。无论它们是否是有效请求。请注意,当客户端使用 keep-alive 时,这与会话不同。- http_req_rate(<period>):频率计数器(占用 12 字节)。它接受一个整数参数 <period>,该参数以毫秒为单位指示测量平均值的周期长度。它报告该周期内的平均 HTTP 请求速率,单位为请求数/周期。结果是一个整数,可以使用 ACL 进行匹配。无论它们是否是有效请求。请注意,当客户端使用 keep-alive 时,这与会话不同。- http_err_cnt:HTTP 错误数。它是一个正的 32 位整数,计算由匹配此条目的客户端引起的绝对 HTTP 请求错误数。错误计入无效和截断的请求,以及被拒绝或 tarpitted 的请求,以及失败的身份验证。如果服务器响应 4xx,则该请求也被计为错误,因为它是客户端触发的错误(例如:漏洞扫描)。- http_err_rate(<period>):频率计数器(占用 12 字节)。它接受一个整数参数 <period>,该参数以毫秒为单位指示测量平均值的周期长度。它报告该周期内的平均 HTTP 请求错误率,单位为请求数/周期(有关计为错误的内容,请参见上面的 http_err_cnt)。结果是一个整数,可以使用 ACL 进行匹配。- bytes_in_cnt:客户端到服务器的字节数。它是一个正的 64 位整数,计算从匹配此条目的客户端接收到的累积字节数。头部包含在计数中。这可用于限制照片或视频服务器上滥用上传功能的情况。- bytes_in_rate(<period>):频率计数器(占用 12 字节)。它接受一个整数参数 <period>,该参数以毫秒为单位指示测量平均值的周期长度。它报告该周期内的平均传入字节速率,单位为字节/周期。它可用于检测上传过多和过快的用户。警告:对于大文件上传,上传的数据量可能在终止时一次性计算,从而导致平均传输速度出现峰值而不是平滑的速度。这可以通过“option contstats”部分平滑,尽管这还不完美。建议使用 byte_in_cnt 以获得更好的公平性。- bytes_out_cnt:服务器到客户端的字节数。它是一个正的 64 位整数,计算发送给匹配此条目的客户端的累积字节数。头部包含在计数中。这可用于限制滥用机器人抓取整个网站的情况。- bytes_out_rate(<period>):频率计数器(占用 12 字节)。它接受一个整数参数 <period>,该参数以毫秒为单位指示测量平均值的周期长度。它报告该周期内的平均传出字节速率,单位为字节/周期。它可用于检测下载过多和过快的用户。警告:对于大文件传输,传输的数据量可能在终止时一次性计算,从而导致平均传输速度出现峰值而不是平滑的速度。这可以通过“option contstats”部分平滑,尽管这还不完美。建议使用 byte_out_cnt 以获得更好的公平性。每个代理只有一个粘滞表。在撰写本文档时,每个代理拥有多个表似乎没有用处。如果需要,只需创建一个带有粘滞表的虚拟后端并引用它。重要的是要理解基于学习信息的粘滞性有一些限制,包括所有学习的关联在重启时都会丢失,除非对等体正确配置以在重启时传输此类信息(推荐)。总的来说,它可以作为补充,但并不总是作为唯一的粘滞性。最后,当存储许多数据类型时,内存需求可能很重要。实际上,在每个条目中一次存储上述所有指标需要每个条目 116 字节,或者对于一个百万条目的表需要 116 MB。这绝对是不能忽视的。
# 在 5 分钟内跟踪多达 100 万个 IP 地址的计数器 # 并存储一个通用计数器和在 30 秒滑动窗口上计算的 # 平均连接速率。 stick-table type ip size 1m expire 5m store gpc0,conn_rate(30s)
定义一个用于在粘滞表中创建条目的响应模式
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 否![]() | 是![]() | 是![]() |
<pattern> 是一个样本表达式规则,如 第 7.3 节 所述。它描述了在选择服务器后,将分析、提取并存储到表中的响应或连接的哪些元素。<table> 是一个可选的粘滞表名称。如果未指定,则使用同一后端的表。粘滞表使用“stick-table”语句声明。<cond> 是一个可选的存储条件。它使得只有在满足(或不满足)某些条件时才可能存储某些标准。例如,它可以用于仅在响应是 SSL 服务器问候时存储 SSL 会话 ID。
某些协议或应用程序需要复杂的粘滞规则,并且不能总是简单地依赖 Cookie 或哈希。“stick store-response”语句描述了一个规则,用于决定从响应中提取什么以及何时提取,以便将其存储到粘滞表中,供后续请求使用“stick match”语句进行匹配。显然,提取的部分必须有意义,并且有机会在后续请求中被匹配。存储在响应头中找到的 ID 是有意义的。有关可能的模式和转换规则的完整列表,请参见第 7 节。表必须使用“stick-table”语句声明。它必须是与模式兼容的类型。默认情况下,它是存在于同一后端的那个。可以通过使用“table”关键字引用其他后端的表来共享一个表。如果引用了另一个表,则使用后端内部的服务器 ID。默认情况下,每个后端中的所有服务器 ID 都从 1 开始,因此服务器排序就足够了。但如有疑问,强烈建议使用其“id”设置强制指定服务器 ID。可以使用“if”或“unless”后跟一个条件来限制“stick store-response”语句应用的条件。此条件将在解析响应时评估,因此可以使用任何标准。有关基于 ACL 的条件,请参见第 7 节。“stick store-response”语句的数量没有限制,但每个请求或响应同时存储的数量限制为 8 个。这使得可以存储多达 8 个标准,所有标准都从请求或响应中提取,无论规则数量如何。只有前 8 个匹配的规则会被保留。使用此功能,可以一次性填充多个表,以期增加在另一协议或访问方法上识别用户的机会。使用多个 store-response 规则与同一个表是可能的,并且可以通过按偏好降序排列规则来找到最佳的依赖标准。对于给定的表,只会存储第一个提取的标准。所有后续引用同一表的 store-response 规则都将被跳过,并且它们的 ACL 不会被评估。但是,即使一个 store-request 规则引用了一个表,一个 store-response 规则也可以使用同一个表。这意味着每个表可以一次从请求中学习一个元素,从响应中学习一个元素。该表将包含处理该请求的真实服务器。
# 从请求和响应中学习 SSL 会话 ID 并创建亲和性。 backend https mode tcp balance roundrobin # 最大 SSL 会话 ID 长度为 32 字节。 stick-table type binary len 32 size 30k expire 30m acl clienthello req_ssl_hello_type 1 acl serverhello rep_ssl_hello_type 2 # 使用 tcp content accepts 来检测 ssl 客户端和服务器 hello。 tcp-request inspect-delay 5s tcp-request content accept if clienthello # 默认情况下,响应检查延迟没有超时。 tcp-response content accept if serverhello # SSL 会话 ID (SSLID) 可能存在于客户端或服务器 hello 中。 # 其长度在偏移量 43 处用 1 字节编码,其值从 # 偏移量 44 开始。 # 如果是客户端 hello,则在请求上匹配并学习。 stick on payload_lv(43,1) if clienthello # 如果是服务器 hello,则在响应上学习。 stick store-response payload_lv(43,1) if serverhello server s1 192.168.1.1:443 server s2 192.168.1.1:443
打开一个新连接
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 否![]() | 是![]() | 是![]() |
当一个应用程序依赖于多个 TCP 端口,或者当 HAProxy 在单个后端中负载均衡多个服务时,有必要在将服务器视为可操作之前单独探测所有服务。当服务器行上没有配置 TCP 端口,也没有服务器端口指令时,'tcp-check connect port <port>' 必须是序列的第一步。在 tcp-check 规则集中,'connect' 是必需的,并且也必须以 'connect' 规则开始规则集。目的是确保管理员知道他们在做什么。参数:它们是可选的,可用于描述 HAProxy 应如何打开和使用 TCP 连接。port 如果未设置,则使用检查端口或服务器端口。它告诉 HAProxy 在哪里打开连接。<port> 必须是有效的 TCP 端口源整数,从 1 到 65535。send-proxy 发送一个 PROXY 协议字符串 ssl 打开一个加密连接
# 检查服务器上的 HTTP 和 HTTPs 服务。 # 首先通过服务器行端口指令打开端口 80,然后 # tcp-check 打开端口 443,加密并在其上运行请求: option tcp-check tcp-check connect tcp-check send GET\ /\ HTTP/1.0\r\n tcp-check send Host:\ haproxy.1wt.eu\r\n tcp-check send \r\n tcp-check expect rstring (2..|3..) tcp-check connect port 443 ssl tcp-check send GET\ /\ HTTP/1.0\r\n tcp-check send Host:\ haproxy.1wt.eu\r\n tcp-check send \r\n tcp-check expect rstring (2..|3..) server www 10.0.0.1 check port 80 # 检查单个服务器上的 POP 和 IMAP: option tcp-check tcp-check connect port 110 tcp-check expect string +OK\ POP3\ ready tcp-check connect port 143 tcp-check expect string *\ OK\ IMAP4\ ready server mail 10.0.0.1 check
在通用健康检查期间指定要收集和分析的数据
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 否![]() | 是![]() | 是![]() |
<match> 是一个关键字,指示如何在响应中查找特定模式。该关键字可以是 "string"、"rstring" 或 binary 之一。该关键字可以前置一个感叹号 ("!") 以否定匹配。感叹号和关键字之间允许有空格。有关支持的关键字的更多详细信息,请参见下文。<pattern> 是要查找的模式。它可以是字符串或正则表达式。如果模式包含空格,必须使用通常的反斜杠 ('\') 进行转义。如果匹配设置为 binary,则模式必须作为一系列偶数个十六进制数字传递。每两个数字序列将代表一个字节。十六进制数字可以使用大写或小写。
可用的匹配项有意与它们的 http-check 表亲相似:string <string>:测试响应缓冲区中的精确字符串匹配。如果响应的缓冲区包含此精确字符串,则健康检查响应将被视为有效。如果“string”关键字前缀为“!”,则如果正文包含此字符串,响应将被视为无效。这可以用于在协议响应中查找强制性模式,或在协议横幅中出现特定错误时检测故障。rstring <regex>:在响应缓冲区上测试正则表达式。如果响应的缓冲区匹配此表达式,则健康检查响应将被视为有效。如果“rstring”关键字前缀为“!”,则如果正文匹配该表达式,响应将被视为无效。binary <hexstring>:以十六进制形式测试响应缓冲区中的精确字符串匹配。如果响应的缓冲区包含此精确的十六进制字符串,则健康检查响应将被视为有效。目的是在二进制协议上匹配数据。需要注意的是,响应将被限制为由全局“tune.chksize”选项定义的大小,默认为 16384 字节。因此,在使用“string”、“rstring”或 binary 时,太大的响应可能不包含强制性模式。如果绝对需要大的响应,可以更改默认的最大大小通过设置全局变量。但是,值得记住的是,解析非常大的响应可能会浪费一些 CPU 周期,尤其是在使用正则表达式时,并且最好将检查集中在较小的资源上。此外,在当前状态下,检查将找不到响应中空字符之后的任何字符串或正则表达式。同样,也无法请求匹配空字符。
# 执行 POP 检查 option tcp-check tcp-check expect string +OK\ POP3\ ready # 执行 IMAP 检查 option tcp-check tcp-check expect string *\ OK\ IMAP4\ ready # 查找 redis 主服务器 option tcp-check tcp-check send PING\r\n tcp-check expect string +PONG tcp-check send info\ replication\r\n tcp-check expect string role:master tcp-check send QUIT\r\n tcp-check expect string +OK
在通用健康检查期间指定一个要作为问题发送的字符串
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 否![]() | 是![]() | 是![]() |
<data>:在通用健康检查会话期间要作为问题发送的数据。目前,<data> 必须是字符串。
# 查找 redis 主服务器 option tcp-check tcp-check send info\ replication\r\n tcp-check expect string role:master
指定一个十六进制数字字符串,作为原始 tcp 健康检查期间的二进制问题发送
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 否![]() | 是![]() | 是![]() |
<data>:在通用健康检查会话期间要作为问题发送的数据。目前,<data> 必须是字符串。<hexastring>:以其十六进制形式测试响应缓冲区中的精确字符串匹配。如果响应的缓冲区包含此精确的十六进制字符串,则健康检查响应将被视为有效。目的是发送二进制数据以在二进制协议上进行查询。
# 二进制 redis 检查 option tcp-check tcp-check send-binary 50494e470d0a # PING\r\n tcp-check expect binary 2b504F4e47 # +PONG
根据第 4 层条件对传入连接执行操作
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 否![]() |
<action> 定义了如果条件适用要执行的操作。见下文。<condition> 是一个标准的仅第 4 层的基于 ACL 的条件(见第 7 节)。
在接受一个新的传入连接后,立即可以评估一些条件来决定是接受、丢弃还是跟踪其计数器。这些条件不能使用任何数据内容,因为连接尚未被读取,缓冲区也尚未分配。这用于以非常低的开销选择性地、非常快速地接受或丢弃来自各种来源的连接。如果需要检查某些内容才能做出决定,则必须改用“tcp-request content”语句。“tcp-request connection”规则按其确切的声明顺序进行评估。如果没有规则匹配或者没有规则,默认操作是接受传入连接。可以插入的规则数量没有具体限制。支持四种类型的操作:- accept:如果条件为真(与“if”一起使用)或为假(与“unless”一起使用),则接受连接。执行的第一个此类规则结束规则评估。- reject:如果条件为真(与“if”一起使用)或为假(与“unless”一起使用),则拒绝连接。执行的第一个此类规则结束规则评估。被拒绝的连接甚至不会成为一个会话,这就是为什么它们在统计中被单独计算为“denied connections”。它们不被考虑用于会话速率限制,也不被记录。原因是这些规则只应用于过滤极高的连接速率,例如在大型 DDoS 攻击期间遇到的速率。在这些极端条件下,简单地记录每个事件的操作会使系统崩溃,并会大大降低过滤能力。如果绝对需要日志记录,则应改用“tcp-request content”规则。- expect-proxy layer4:配置面向客户端的连接,以便在从套接字读取任何字节之前接收 PROXY 协议头。这等同于在“bind”行上具有“accept-proxy”关键字,只是使用 TCP 规则允许仅对某些 IP 地址范围使用 ACL 接受 PROXY 协议。这在流量来自公共主机并经过多层负载均衡器时很方便。- capture <sample> len <length>:这仅适用于“tcp-request content”规则。它从请求缓冲区中捕获样本表达式 <sample>,并将其转换为最多 <len> 个字符的字符串。结果字符串存储在下一个请求的“capture”槽中,因此它可能会出现在一些捕获的 HTTP 头部旁边。然后它将自动出现在日志中,并且可以使用样本获取规则提取它以将其馈送到头部或任何东西中。长度应受到限制,因为此大小将在整个会话生命周期内为每次捕获分配。有关更多信息,请查看第 7.3 节(获取样本)和“捕获请求头”。- { track-sc0 | track-sc1 | track-sc2 } <key> [table <table>]:启用从当前连接跟踪粘性计数器。这些规则不会停止评估并且不会改变默认操作。同一连接可以同时跟踪的计数器数量在构建时在 MAX_SESS_STKCTR 中设置(在 haproxy -vv 中报告),默认为 3,因此 track-sc 数字在 0 和 (MAX_SESS_STCKTR-1) 之间。执行的第一个“track-sc0”规则启用将指定表的计数器作为第一组进行跟踪。执行的第一个“track-sc1”规则启用将指定表的计数器作为第二组进行跟踪。执行的第一个“track-sc2”规则启用将指定表的计数器作为第三组进行跟踪。建议的做法是使用第一组计数器用于每个前端的计数器,第二组用于每个后端的计数器。但这只是一个指南,所有计数器都可以在任何地方使用。这些操作接受一个或两个参数:<key> 是强制性的,并且是一个样本表达式规则,如第 7.3 节中所述。它描述了将分析、提取、组合传入请求或连接的哪些元素,并用于选择更新哪个表条目的计数器。请注意,“tcp-request connection”不能使用基于内容的获取。<table> 是一个可选的表,用于代替默认表,默认表是在当前代理中声明的粘滞表。然后,匹配和更新键的所有计数器都将在此表中执行,直到会话结束。一旦执行了“track-sc*”规则,就会在表中查找该键,如果找不到,则为其分配一个条目。然后在整个会话生命周期内保留一个指向该条目的指针,并且该条目的计数器会尽可能频繁地更新,每次会话的计数器更新时以及会话结束时系统地更新。计数器仅针对跟踪开始后发生的事件进行更新。例如,在跟踪第 7 层信息时,连接计数器不会更新,因为连接事件发生在提取第 7 层信息之前。如果该条目跟踪并发连接计数器,则只要该条目被跟踪,就会计算一个连接,并且该条目在此期间不会过期。跟踪计数器还提供了性能优势,不仅仅是检查键,因为对于所有使用它的 ACL 检查,只执行一次表查找。- sc-inc-gpc0(<sc-id>):“sc-inc-gpc0”根据由 <sc-id> 指定的粘性计数器递增 GPC0 计数器。如果发生错误,此操作会静默失败,并且操作评估继续。- sc-set-gpt0(<sc-id>) <int>:此操作根据由 <sc-id> 指定的粘性计数器和 <int> 的值设置 GPT0 标记。预期的结果是一个布尔值。如果发生错误,此操作会静默失败,并且操作评估继续。- "silent-drop":这将停止规则的评估,并使用一种系统相关的方式使面向客户端的连接突然消失,该方式试图阻止客户端被通知。其效果是客户端仍然看到一个已建立的连接,而 HAProxy 上没有。目的是实现与“tarpit”类似的效果,只是它在运行 HAProxy 的机器上根本不使用任何本地资源。它可以抵抗比“tarpit”更高的负载,并减慢更强的攻击者。重要的是要理解使用这种机制的影响。放置在客户端和 HAProxy 之间的所有有状态设备(防火墙、代理、负载均衡器)也将长时间保持已建立的连接,并可能因此操作而受到影响。在具有足够权限的现代 Linux 系统上,使用 TCP_REPAIR 套接字选项来阻止 TCP 重置的发出。在其他系统上,套接字的 TTL 减少到 1,以便 TCP 重置不会通过第一个路由器,尽管它仍然会传送到本地网络。除非您完全理解其工作原理,否则不要使用它。请注意,“if/unless”条件是可选的。如果操作上没有设置条件,则它只是无条件地执行。这对于“track-sc*”操作以及将默认操作更改为拒绝可能很有用。
接受所有来自白名单主机的连接,拒绝过快的连接而不计数,并跟踪已接受的连接。这导致来自滥用来源的连接速率受到限制。tcp-request connection accept if { src -f /etc/haproxy/whitelist.lst } tcp-request connection reject if { src_conn_rate gt 10 } tcp-request connection track-sc0 src
接受所有来自白名单主机的连接,计算所有其他连接并拒绝过快的连接。这导致滥用者只要不减速就会被阻止。tcp-request connection accept if { src -f /etc/haproxy/whitelist.lst } tcp-request connection track-sc0 src tcp-request connection reject if { sc0_conn_rate gt 10 }
为来自所有已知代理的流量启用 PROXY 协议。tcp-request connection expect-proxy layer4 if { src -f proxies.lst }
有关 ACL 的用法,请参见第 7 节。
根据第 4-7 层条件对新会话执行操作
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 是![]() |
<action> 定义了如果条件适用要执行的操作。见下文。<condition> 是一个标准的第 4-7 层基于 ACL 的条件(见第 7 节)。
请求的内容可以在请求处理的早期阶段进行分析,称为“TCP 内容检查”。在此阶段,每次请求内容更新时都会评估基于 ACL 的规则,直到“accept”或“reject”规则匹配,或者 TCP 请求检查延迟过期而没有匹配规则。这些规则与“tcp-request connection”规则的第一个区别是,“tcp-request content”规则可以利用内容来做决定。通常,这些决定会考虑协议识别或有效性。第二个区别是,基于内容的规则可以在前端和后端中使用。在与客户端进行 HTTP keep-alive 的情况下,所有 tcp-request content 规则都会再次评估,因此 haproxy 会记录由“tcp-request connection”规则与“tcp-request content”规则分配的粘性计数器,并在处理 HTTP 请求后刷新所有与内容相关的计数器,以便它们可以由为下一个请求再次评估的规则再次评估。当规则跟踪某些 L7 信息或其条件是基于 L7 的 ACL 时,这一点尤其重要,因为跟踪可能在请求之间发生变化。基于内容的规则按其确切的声明顺序进行评估。如果没有规则匹配或者没有规则,默认操作是接受内容。可以插入的规则数量没有具体限制。支持多种类型的操作:- accept:接受请求 - reject:拒绝请求并关闭连接 - capture:捕获指定的样本表达式 - { track-sc0 | track-sc1 | track-sc2 } <key> [table <table>] - sc-inc-gpc0(<sc-id>) - sc-set-gpt0(<sc-id>) <int> - set-var(<var-name>) <expr> - silent-drop 它们与“tcp-request connection”中的对应部分具有相同的含义,因此请参考该部分以获取完整描述。虽然没有强制性要求,但建议在“tcp-request connection”规则中使用 track-sc0,在前端的“tcp-request content”规则中使用 track-sc1,在后端的“tcp-request content”规则中使用 track-sc2,因为这使得配置更具可读性且更易于故障排除,但这只是一个指南,所有计数器都可以在任何地方使用。请注意,“if/unless”条件是可选的。如果操作上没有设置条件,则它只是无条件地执行。这对于“track-sc*”操作以及将默认操作更改为拒绝可能很有用。使用“tcp-request content”规则匹配第 7 层内容是完全可能的,因为特定于 HTTP 的 ACL 匹配能够在提取所需数据之前初步解析缓冲区的内容。如果缓冲的内容无法解析为有效的 HTTP 消息,则 ACL 不匹配。这里涉及的解析器与所有其他 HTTP 处理的解析器完全相同,因此不存在以不同方式解析某些内容的风险。在从 HTTP 前端连接的 HTTP 后端中,可以保证在首次评估规则时 HTTP 内容总是立即可用。只要信息在处理规则时存在,跟踪第 7 层信息也是可能的。当要跟踪的数据尚不可用时,规则处理引擎能够等到检查延迟过期。 "set-var" 用于设置变量的内容。变量是内联声明的。<var-name> 变量的名称以其作用域的指示开始。允许的作用域有:"sess":变量在整个会话中共享 "txn":变量在事务(请求和响应)中共享 "req":变量仅在请求处理期间共享 "res":变量仅在响应处理期间共享 此前缀后跟一个名称。分隔符是'.'。名称只能包含字符 'a-z'、'A-Z'、'0-9' 和 '_'。<expr> 是一个标准的 HAProxy 表达式,由一个样本获取后跟一些转换器组成。
tcp-request content set-var(sess.my_var) src
# 接受包含 Host 头部为 "example.com" 的 HTTP 请求 # 并拒绝所有其他请求。 acl is_host_com hdr(Host) -i example.com tcp-request inspect-delay 30s tcp-request content accept if is_host_com tcp-request content reject
# 如果客户端先发言,则拒绝 SMTP 连接 tcp-request inspect-delay 30s acl content_present req_len gt 0 tcp-request content reject if content_present # 仅在客户端发言时才转发 HTTPS 连接 tcp-request inspect-delay 30s acl content_present req_len gt 0 tcp-request content accept if content_present tcp-request content reject
# 跟踪 X-Forwarded-For 中的最后一个 IP(粘滞表类型为 string) tcp-request inspect-delay 10s tcp-request content track-sc0 hdr(x-forwarded-for,-1) # 或者跟踪 X-Forwarded-For 中的最后一个 IP(粘滞表类型为 ip|ipv6) tcp-request content track-sc0 req.hdr_ip(x-forwarded-for,-1)
# 按“base”(Host+URL 的串联)跟踪请求计数 tcp-request inspect-delay 10s tcp-request content track-sc0 base table req-rate
跟踪每个前端和每个后端的计数器,当后端检测到滥用(并标记 gpc0)时,在前端阻止滥用者。frontend http # 使用 SC0 中的通用计数器 0 作为全局滥用计数器 # 保护我们所有的站点 stick-table type ip size 1m expire 5m store gpc0 tcp-request connection track-sc0 src tcp-request connection reject if { sc0_get_gpc0 gt 0 } ... use_backend http_dynamic if { path_end .php } backend http_dynamic # 如果一个源对这个动态站点的请求过快(由 SC1 跟踪), # 则在前端全局阻止它。 stick-table type ip size 1m expire 5m store http_req_rate(10s) acl click_too_fast sc1_http_req_rate gt 10 acl mark_as_abuser sc0_inc_gpc0(http) gt 0 tcp-request content track-sc1 src tcp-request content reject if click_too_fast mark_as_abuser
有关 ACL 的用法,请参见第 7 节。
设置在内容检测期间等待数据的最大允许时间
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 是![]() |
<timeout> 是默认以毫秒为单位指定的超时值,但如果数字后缀有单位,则可以是任何其他单位,如本文档开头所述。
主要将 haproxy 用作 TCP 中继的用户通常担心在没有任何分析的情况下将任何类型的协议传递给服务器的风险。为了能够分析请求内容,我们必须首先暂留数据然后进行分析。此语句仅启用数据暂留,最长不超过指定的时间。TCP 内容检测在连接到达前端时很早应用,然后在连接转发到后端时也很早应用。这意味着如果前端和后端都有 tcp-request 规则,连接可能会在前端经历第一次延迟,在后端经历第二次延迟。请注意,在执行内容检测时,haproxy 会为每个进入的新数据块评估整个规则,并考虑到这些数据是部分的。如果在上述延迟之前没有规则匹配,则在到期时会执行最后一次检查,这次会认为内容是最终的。如果没有设置延迟,haproxy 将完全不等待,并立即根据可用信息应用判决。显然,这不太可能非常有用,甚至可能存在竞争条件,因此不推荐此类设置。一旦有规则匹配,请求就会被释放并照常继续。如果达到超时且没有规则匹配,默认策略是让其不受影响地通过。对于大多数协议,将其设置为几秒钟就足够了,因为大多数客户端在连接时会立即发送完整请求。增加 3 秒或更多时间以覆盖 TCP 重传,但仅此而已。对于某些协议,使用较大的值可能是有意义的,例如,确保客户端永远不会在服务器之前发言(例如:SMTP),或者在将数据传递给服务器之前等待客户端发言(例如:SSL)。请注意,客户端超时必须至少覆盖检测延迟,否则它将首先到期。如果客户端关闭连接或缓冲区已满,延迟会立即到期,因为内容将无法再更改。
根据第 4-7 层条件对会话响应执行操作
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 否![]() | 是![]() | 是![]() |
<action> 定义了如果条件适用要执行的操作。见下文。<condition> 是一个标准的第 4-7 层基于 ACL 的条件(见第 7 节)。
响应内容可以在响应处理的早期阶段进行分析,该阶段称为“TCP 内容检测”。在此阶段,每次响应内容更新时都会评估基于 ACL 的规则,直到匹配 "accept"、"close" 或 "reject" 规则,或者设置的 TCP 响应检测延迟到期且没有匹配规则。大多数情况下,这些决策会考虑协议识别或有效性。基于内容的规则按其确切声明顺序进行评估。如果没有规则匹配或没有规则,默认操作是接受内容。可插入的规则数量没有特定限制。支持多种类型的操作:- accept:如果条件为真(与 "if" 一起使用时)或为假(与 "unless" 一起使用时),则接受响应。第一个执行的此类规则会结束规则评估。- close:如果条件为真(与 "if" 一起使用时)或为假(与 "unless" 一起使用时),立即关闭与服务器的连接。第一个执行的此类规则会结束规则评估。此操作的主要目的是在应用程序协议期望一些长超时先到期时,强制在客户端和服务器之间的交换后结束连接。目标是消除在某些协议下占用服务器大量资源的空闲连接。- reject:如果条件为真(与 "if" 一起使用时)或为假(与 "unless" 一起使用时),则拒绝响应。第一个执行的此类规则会结束规则评估。被拒绝的会话会立即关闭。- set-var(<var-name>) <expr>:设置一个变量。- sc-inc-gpc0(<sc-id>):此操作根据由 <sc-id> 指定的粘性计数器递增 GPC0 计数器。如果发生错误,此操作会静默失败,并继续进行操作评估。- sc-set-gpt0(<sc-id>) <int>:此操作根据由 <sc-id> 指定的粘性计数器和 <int> 的值来设置 GPT0 标签。预期的结果是一个布尔值。如果发生错误,此操作会静默失败,并继续进行操作评估。- "silent-drop":此操作停止规则评估,并使用一种系统相关的方式使面向客户端的连接突然消失,该方式试图阻止客户端收到通知。其效果是,客户端仍然看到一个已建立的连接,而 HAProxy 上却没有任何连接。其目的是实现与 "tarpit" 类似的效果,只是它在运行 HAProxy 的机器上完全不使用任何本地资源。它比 "tarpit" 能抵抗更高的负载,并能减缓更强大的攻击者。理解使用此机制的影响很重要。所有放置在客户端和 HAProxy 之间的有状态设备(防火墙、代理、负载均衡器)也将长时间保持已建立的连接,并可能因此操作而受损。在具有足够权限的现代 Linux 系统上,使用 TCP_REPAIR 套接字选项来阻止 TCP 重置的发送。在其他系统上,套接字的 TTL 被减少到 1,以便 TCP 重置不会通过第一个路由器,尽管它仍然会传递到本地网络。除非你完全理解其工作原理,否则不要使用它。请注意,"if/unless" 条件是可选的。如果操作上没有设置条件,它将无条件地执行。这对于将默认操作更改为拒绝可能很有用。使用 "tcp-response content" 规则匹配第 7 层内容是完全可能的,但必须确保已缓冲完整的响应,否则没有任何内容会匹配。为了实现这一点,最好的解决方案是在检测期间检测 HTTP 协议。"set-var" 用于设置变量的内容。变量是内联声明的。<var-name> 变量的名称以其作用域的指示开始。允许的作用域有:"sess":变量在整个会话中共享;"txn":变量在事务(请求和响应)中共享;"req":变量仅在请求处理期间共享;"res":变量仅在响应处理期间共享。此前缀后跟一个名称。分隔符是'.'。名称只能包含字符 'a-z'、'A-Z'、'0-9' 和 '_'。<expr> 是一个标准的 HAProxy 表达式,由一个样本获取后跟一些转换器组成。
tcp-request content set-var(sess.my_var) src
有关 ACL 的用法,请参见第 7 节。
设置内容检测期间等待响应的最大允许时间
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 否![]() | 是![]() | 是![]() |
<timeout> 是默认以毫秒为单位指定的超时值,但如果数字后缀有单位,则可以是任何其他单位,如本文档开头所述。
设置额外的检查超时,但仅在连接已经建立之后。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
<timeout> 是默认以毫秒为单位指定的超时值,但如果数字后缀有单位,则可以是任何其他单位,如本文档开头所述。
如果设置,haproxy 使用 min("timeout connect", "inter") 作为检查的连接超时,并使用 "timeout check" 作为额外的读取超时。使用 "min" 是为了让那些运行着 *非常* 长的 "timeout connect" 的用户(例如,那些由于队列或tarpit而需要这样做的人)不会减慢他们的检查。(请注意,没有有效的理由设置如此长的连接超时,因为总是可以使用 "timeout queue" 和 "timeout tarpit" 来避免这种情况)。如果未设置 "timeout check",haproxy 将使用 "inter" 作为完整的检查超时(连接+读取),这与所有 <1.3.15 版本的行为完全相同。在大多数情况下,检查请求比正常请求更简单、处理速度更快,人们可能希望踢出有延迟的服务器,所以此超时应小于 "timeout server"。此参数特定于后端,但可以在 "defaults" 部分中一次性为所有后端指定。这实际上是确保不忘记它的最简单解决方案之一。
设置客户端侧的最大不活动时间。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 否![]() |
<timeout> 是默认以毫秒为单位指定的超时值,但如果数字后缀有单位,则可以是任何其他单位,如本文档开头所述。
当期望客户端确认或发送数据时,适用此不活动超时。在 HTTP 模式下,此超时在第一阶段(客户端发送请求时)和响应期间(客户端读取服务器发送的数据时)尤其重要。尽管如此,对于第一阶段,最好设置 "timeout http-request" 以更好地保护 HAProxy 免受类似 Slowloris 的攻击。默认情况下,该值以毫秒为单位指定,但如果数字后跟单位后缀,也可以是任何其他单位,如本文档开头所述。在 TCP 模式下(以及在较小程度上,在 HTTP 模式下),强烈建议客户端超时与服务器超时保持相等,以避免调试复杂的情况。通过指定略高于 3 秒倍数(例如:4 或 5 秒)的超时来覆盖一个或多个 TCP 数据包丢失是一种很好的做法。如果一些长连接与短连接混合在一起(例如:WebSocket 和 HTTP),则值得考虑 "timeout tunnel"(它会覆盖隧道中的 "timeout client" 和 "timeout server")以及 "timeout client-fin"(用于半关闭连接)。此参数特定于前端,但可以在 "defaults" 部分中为所有前端指定一次。这实际上是确保不忘记它的最简单解决方案之一。未指定的超时会导致无限超时,这是不推荐的。虽然这种用法被接受并且可以工作,但它会在启动时报告警告,因为如果系统的超时也未配置,可能会导致系统中过期的会话累积。此参数取代了旧的、已弃用的 "clitimeout"。建议在编写新配置时使用它。" timeout clitimeout" 形式仅为向后兼容而提供,但强烈不鼓励使用。
为半关闭连接设置客户端侧的不活动超时。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 否![]() |
<timeout> 是默认以毫秒为单位指定的超时值,但如果数字后缀有单位,则可以是任何其他单位,如本文档开头所述。
当一个方向已经关闭,但期望客户端确认或发送数据时,适用此不活动超时。此超时与 "timeout client" 的不同之处在于,它仅适用于单向关闭的连接。这对于避免在客户端未正常断开连接时将连接长时间保持在 FIN_WAIT 状态特别有用。此问题在 RDP 或 WebSocket 等长连接中尤为常见。请注意,当连接在一个方向上关闭时,此超时可以覆盖 "timeout tunnel"。此参数特定于前端,但可以在 "defaults" 部分中为所有前端一次性指定。默认情况下不设置,因此半关闭连接将使用其他超时(timeout.client 或 timeout.tunnel)。
设置等待服务器连接尝试成功的最大时间。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
<timeout> 是默认以毫秒为单位指定的超时值,但如果数字后缀有单位,则可以是任何其他单位,如本文档开头所述。
如果服务器与 haproxy 位于同一局域网中,连接应该是即时的(少于几毫秒)。无论如何,通过指定略高于 3 秒倍数(例如:4 或 5 秒)的超时来覆盖一个或多个 TCP 数据包丢失是一种很好的做法。默认情况下,如果未指定队列和tarpit超时,连接超时也会将它们预设为相同的值。此参数特定于后端,但可以在 "defaults" 部分中一次性为所有后端指定。这实际上是确保不忘记它的最简单解决方案之一。未指定的超时会导致无限超时,这是不推荐的。虽然这种用法被接受并且可以工作,但它会在启动时报告警告,因为如果系统的超时也未配置,可能会导致系统中失败的会话累积。此参数取代了旧的、已弃用的 "contimeout"。建议在编写新配置时使用它。" timeout contimeout" 形式仅为向后兼容而提供,但强烈不鼓励使用。
设置等待新 HTTP 请求出现的最大允许时间
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
<timeout> 是默认以毫秒为单位指定的超时值,但如果数字后缀有单位,则可以是任何其他单位,如本文档开头所述。
默认情况下,在 keep-alive 情况下等待新请求的时间由 "timeout http-request" 设置。然而,这并不总是方便,因为有些人希望 keep-alive 超时非常短以便更快地释放连接,而另一些人则希望有更长的超时,但在请求开始出现后仍然有短超时。"http-keep-alive" 超时满足了这些需求。它将定义在发送响应后等待新的 HTTP 请求开始到来的时间。一旦看到请求的第一个字节,就会使用 "http-request" 超时来等待完整请求的到来。请注意,新请求之前的空行不会刷新超时,也不会被计为新请求。这两个超时之间还有另一个区别:当连接在 timeout http-keep-alive 期间到期时,不会返回错误,连接只是关闭。如果连接在 "http-request" 期间等待连接完成时到期,则会返回 HTTP 408 错误。通常,将此值设置为几十到几百毫秒是最佳的,以允许用户一次性获取页面的所有对象,但无需等待进一步的点击。此外,如果设置为一个非常小的值(例如:1 毫秒),它可能只接受流水线请求,而不接受非流水线请求。对于拥有数万到数十万客户端的非常大的网站来说,这可能是一个很好的权衡。如果未设置此参数,则应用 "http-request" 超时,如果两者都未设置,"timeout client" 仍然在较低级别适用。应在前端设置此参数以使其生效,除非前端处于 TCP 模式,在这种情况下将使用 HTTP 后端的超时。
设置等待完整 HTTP 请求的最大允许时间
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
<timeout> 是默认以毫秒为单位指定的超时值,但如果数字后缀有单位,则可以是任何其他单位,如本文档开头所述。
为了提供 DoS 保护,可能需要降低接收完整 HTTP 请求的最大允许时间,而不影响客户端超时。这有助于防止在已建立的连接上不发送任何内容的情况。客户端超时无法很好地防范这种滥用,因为它是一个不活动超时,这意味着如果攻击者时不时发送一个字符,超时将不会触发。有了 HTTP 请求超时,无论客户端输入速度如何,如果请求未在规定时间内完成,它都将被中止。当超时到期时,会向客户端发送一个 HTTP 408 响应以告知问题,并关闭连接。日志将报告终止代码 "cR"。一些最近的浏览器对这种标准的、有据可查的行为存在问题,因此可能需要使用 "option http-ignore-probes" 或 "errorfile 408 /dev/null" 来隐藏 408 代码。更多详细信息请参见 第 8.5 节 中关于 "cR" 终止代码的解释。默认情况下,此超时仅适用于请求的头部部分,不适用于任何数据。一旦接收到空行,此超时就不再使用。当与 "option http-buffer-request" 结合使用时,此超时也适用于请求的主体部分。如果未设置 "timeout http-keep-alive",它会在 keep-alive 连接上再次用于等待第二个请求。通常,将其设置为几秒钟就足够了,因为大多数客户端在连接时会立即发送完整请求。增加 3 秒或更多时间以覆盖 TCP 重传,但仅此而已。将其设置为非常低的值(例如:50 毫秒)通常在本地网络上可以工作,只要没有数据包丢失。这将阻止人们使用 telnet 发送裸 HTTP 请求。如果未设置此参数,客户端超时仍然在传入请求的每个数据块之间适用。应在前端设置此参数以使其生效,除非前端处于 TCP 模式,在这种情况下将使用 HTTP 后端的超时。
设置在队列中等待可用连接槽的最大时间
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
<timeout> 是默认以毫秒为单位指定的超时值,但如果数字后缀有单位,则可以是任何其他单位,如本文档开头所述。
当服务器的 maxconn 达到时,连接会留在队列中等待,该队列可能是服务器特定的或后端全局的。为了避免无限期等待,会对队列中的待处理请求应用超时。如果达到超时,则认为该请求几乎永远不会被处理,因此会丢弃它并向客户端返回 503 错误。" timeout queue" 语句允许固定请求在队列中等待的最长时间。如果未指定,则使用与后端连接超时("timeout connect")相同的值,以与没有 "timeout queue" 参数的旧版本向后兼容。
设置服务器端的最大不活动时间。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
<timeout> 是默认以毫秒为单位指定的超时值,但如果数字后缀有单位,则可以是任何其他单位,如本文档开头所述。
当期望服务器确认或发送数据时,适用此不活动超时。在 HTTP 模式下,此超时在服务器响应的第一阶段(必须发送头部时)尤其重要,因为它直接代表了服务器对请求的处理时间。要确定在此处设置什么值,通常最好从被认为是不可接受的响应时间开始,然后检查日志以观察响应时间分布,并相应地调整该值。默认情况下,该值以毫秒为单位指定,但如果数字后跟单位后缀,也可以是任何其他单位,如本文档开头所述。在 TCP 模式下(以及在较小程度上,在 HTTP 模式下),强烈建议客户端超时与服务器超时保持相等,以避免调试复杂的情况。无论预期的服务器响应时间如何,通过指定略高于 3 秒倍数(例如:最少 4 或 5 秒)的超时来覆盖至少一个或多个 TCP 数据包丢失是一种很好的做法。如果一些长连接与短连接混合在一起(例如:WebSocket 和 HTTP),则值得考虑 "timeout tunnel",它会覆盖隧道中的 "timeout client" 和 "timeout server"。此参数特定于后端,但可以在 "defaults" 部分中为所有后端一次性指定。这实际上是确保不忘记它的最简单解决方案之一。未指定的超时会导致无限超时,这是不推荐的。虽然这种用法被接受并且可以工作,但它会在启动时报告警告,因为如果系统的超时也未配置,可能会导致系统中过期的会话累积。此参数取代了旧的、已弃用的 "srvtimeout"。建议在编写新配置时使用它。" timeout srvtimeout" 形式仅为向后兼容而提供,但强烈不鼓励使用。
为半关闭连接设置服务器侧的不活动超时。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
<timeout> 是默认以毫秒为单位指定的超时值,但如果数字后缀有单位,则可以是任何其他单位,如本文档开头所述。
当一个方向已经关闭,但期望服务器确认或发送数据时,适用此不活动超时。此超时与 "timeout server" 的不同之处在于,它仅适用于单向关闭的连接。这对于避免在远程服务器未正常断开连接时将连接长时间保持在 FIN_WAIT 状态特别有用。此问题在 RDP 或 WebSocket 等长连接中尤为常见。请注意,当连接在一个方向上关闭时,此超时可以覆盖 "timeout tunnel"。提供此设置是为了完整性,但在大多数情况下,应该不需要它。此参数特定于后端,但可以在 "defaults" 部分中为所有后端一次性指定。默认情况下不设置,因此半关闭连接将使用其他超时(timeout.server 或 timeout.tunnel)。
设置被tarpit的连接将维持的时间
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 是![]() |
<timeout> 是 tarpit 的持续时间,默认以毫秒为单位指定,但如果数字后跟单位后缀,也可以是任何其他单位,如本文档开头所述。
当使用 "http-request tarpit" 或 "reqtarpit" 对连接进行 tarpit 处理时,连接会在一段时间内保持打开状态但没有任何活动,然后关闭。" timeout tarpit" 定义了它将保持打开的时间。默认情况下,该值以毫秒为单位指定,但如果数字后跟单位后缀,也可以是任何其他单位,如本文档开头所述。如果未指定,则使用与后端连接超时("timeout connect")相同的值,以与没有 "timeout tarpit" 参数的旧版本向后兼容。
为隧道设置客户端和服务器侧的最大不活动时间。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
<timeout> 是默认以毫秒为单位指定的超时值,但如果数字后缀有单位,则可以是任何其他单位,如本文档开头所述。
当客户端和服务器之间建立双向连接,并且连接在两个方向上都保持不活动时,隧道超时适用。一旦连接成为隧道,此超时将取代客户端和服务器超时。在 TCP 中,一旦没有任何分析器附加到任一连接(例如:tcp content 规则被接受),就会使用此超时。在 HTTP 中,当连接升级时(例如:切换到 WebSocket 协议,或将 CONNECT 请求转发到代理),或者在第一个响应后未指定 keepalive/close 选项时,会使用此超时。由于此超时通常与长连接一起使用,通常最好也设置 "timeout client-fin" 来处理客户端突然从网络消失且不确认关闭,或者发送关闭请求但不再确认待处理数据的情况。这种情况可能发生在存在防火墙的有损网络中,并通过存在大量处于 FIN_WAIT 状态的会话来检测。默认情况下,该值以毫秒为单位指定,但如果数字后跟单位后缀,也可以是任何其他单位,如本文档开头所述。无论预期的正常空闲时间如何,通过指定略高于 3 秒倍数(例如:最少 4 或 5 秒)的超时来覆盖至少一个或多个 TCP 数据包丢失是一种很好的做法。此参数特定于后端,但可以在 "defaults" 部分中为所有后端一次性指定。这实际上是确保不忘记它的最简单解决方案之一。
defaults http option http-server-close timeout connect 5s timeout client 30s timeout client-fin 30s timeout server 30s timeout tunnel 1h # 用于 WebSocket 和 CONNECT 的超时
启用客户端透明代理
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 否![]() | 是![]() | 是![]() |
引入此关键字是为了向第 3 层负载均衡器提供第 7 层持久性。其思想是利用操作系统的能力将远程地址的传入连接重定向到本地进程(此处为 HAProxy),并让该进程知道最初请求的地址。使用此选项时,没有 cookie 的会话将被转发到传入请求的原始目标 IP 地址(该地址应与另一设备的地址匹配),而带有 cookie 的请求仍将被转发到适当的服务器。" transparent" 关键字已弃用,请改用 "option transparent"。请注意,与普遍看法相反,此选项在建立连接时并不会使 HAProxy 向服务器呈现客户端的 IP。
为每个请求生成一个唯一的 ID。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 否![]() |
<string> 是一个日志格式字符串。
此关键字使用自定义日志格式为每个请求创建一个 ID。唯一的 ID 对于跟踪通过复杂基础设施中许多组件的请求非常有用。新创建的 ID 也可以使用日志格式字符串中的 %ID 标签进行记录。格式应由组合在一起时保证唯一的元素组成。例如,如果涉及多个 haproxy 实例,则可能需要包含节点名称。通常需要记录传入连接的源地址和目标地址及端口。请注意,由于可以在同一连接上执行多个请求,因此包含请求计数器可能有助于区分它们。同样,时间戳可以防止计数器翻转。记录进程 ID 将避免服务重启后发生冲突。建议对许多字段使用十六进制表示法,因为它使它们更紧凑并节省日志空间。
unique-id-format %{+X}o\ %ci:%cp_%fi:%fp_%Ts_%rt:%pid 将生成: 7F000001:8296_7F00001E:1F90_4F7B0A69_0003:790A
在 HTTP 请求中添加一个唯一的 ID 头部。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
是![]() | 是![]() | 是![]() | 否![]() |
<name> 是头部的名称。
使用 unique-id-format 在发送到服务器的 HTTP 请求中添加一个 unique-id 头部。如果 unique-id-format 不存在,则无法工作。
unique-id-format %{+X}o\ %ci:%cp_%fi:%fp_%Ts_%rt:%pid unique-id-header X-Unique-ID 将生成: X-Unique-ID: 7F000001:8296_7F00001E:1F90_4F7B0A69_0003:790A 另请参阅: "unique-id-format"
如果/除非匹配基于 ACL 的条件,则切换到特定的后端。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 是![]() | 是![]() | 否![]() |
<backend> 是一个有效的后端或 "listen" 部分的名称,或一个解析为后端名称的 "log-format" 字符串。<condition> 是由 ACL 组成的条件,如 第 7 节 所述。如果省略,则无条件应用该规则。
在进行内容切换时,连接到达前端,然后根据多个条件分派到不同的后端。" use_backend" 关键字描述了条件和后端之间的关系。虽然它通常用于 HTTP 处理,但也可以在纯 TCP 中使用,可以使用无状态 ACL(例如:源地址验证),也可以与 "tcp-request" 规则结合使用以等待某些有效负载。可以有任意数量的 "use_backend" 规则。所有这些规则都按其声明顺序进行评估,第一个匹配的规则将分配后端。在第一种形式中,如果满足条件,则将使用后端。在第二种形式中,如果不满足条件,则将使用后端。如果没有条件有效,则将使用由 "default_backend" 定义的后端。如果没有定义默认后端,则要么使用同一部分中的服务器(如果是 "listen" 部分),要么(如果是前端)不使用任何服务器,并返回 503 服务不可用响应。请注意,可以从 TCP 前端切换到 HTTP 后端。在这种情况下,要么前端已经检查了协议是 HTTP,并且后端处理将立即进行,要么后端将等待一个完整的 HTTP 请求进入。当一个前端必须在一个唯一的端口上解码多个协议,其中一个是 HTTP 时,此功能非常有用。当 <backend> 是一个简单的名称时,它在配置时解析,如果指定的后端不存在,则报告错误。如果 <backend> 是一个日志格式字符串,则在配置时无法进行检查,因此后端名称在运行时动态解析。如果生成的后端名称与任何有效后端都不对应,则不会评估其他规则,而是应用 default_backend 指令。请注意,当使用动态后端名称时,强烈建议使用其他后端不使用的前缀,以确保无法从请求中强制使用未经授权的后端。值得一提的是,具有显式名称的 "use_backend" 规则用于检测前端和后端之间的关联,以计算后端的 "fullconn" 设置。对于动态名称,无法做到这一点。
仅在匹配/不匹配基于 ACL 的条件时才使用特定的服务器。
可在以下配置段中使用
| defaults | frontend | listen | backend |
|---|---|---|---|
否![]() | 否![]() | 是![]() | 是![]() |
<server> 是同一后端部分中有效服务器的名称。<condition> 是由 ACL 组成的条件,如 第 7 节 所述。
默认情况下,到达后端的连接会根据配置的算法在可用服务器之间进行负载均衡,除非使用了持久性机制(如 cookie)并在请求中找到。有时,希望将特定请求转发到特定服务器,而无需为此服务器声明专用后端。这可以使用 "use-server" 规则来实现。这些规则在 "redirect" 规则之后、评估 cookie 之前进行评估,并且它们优先于 cookie。可以有任意数量的 "use-server" 规则。所有这些规则都按其声明顺序进行评估,第一个匹配的规则将分配服务器。如果规则指定的服务器已关闭,并且未使用 "option persist" 且没有 force-persist 规则被验证,则会忽略该规则,并继续评估下一个规则直到匹配为止。在第一种形式中,如果满足条件,则将使用服务器。在第二种形式中,如果不满足条件,则将使用服务器。如果没有条件有效,则处理将继续,并根据其他持久性机制分配服务器。请注意,即使匹配了规则,仍然会执行 cookie 处理,但不会分配服务器。这允许带前缀的 cookie 去掉其前缀。" use-server" 语句在 HTTP 和 TCP 模式下都有效。这使其适用于基于内容的检测。例如,可以根据 TLS SNI 字段在服务器场中选择一个服务器。如果这些服务器的权重设置为零,它们将不会用于其他流量。
# 根据 SNI 字段拦截传入的 TLS 请求 use-server www if { req_ssl_sni -i www.example.com } server www 192.168.0.1:443 weight 0 use-server mail if { req_ssl_sni -i mail.example.com } server mail 192.168.0.1:587 weight 0 use-server imap if { req_ssl_sni -i imap.example.com } server imap 192.168.0.1:993 weight 0 # 所有其余的请求都转发到此服务器 server default 192.168.0.2:443 check
"bind"、"server" 和 "default-server" 关键字支持多个设置,具体取决于某些构建选项和 HAProxy 构建所在的系统。这些设置通常由一个单词组成,有时后面跟着一个值,写在与 "bind" 或 "server" 行相同的行上。本节描述了所有这些选项。
"bind" 关键字支持一定数量的设置,这些设置都作为参数在同一行上传递。这些参数出现的顺序无关紧要,只要它们出现在绑定地址之后即可。所有这些参数都是可选的。其中一些由单个单词组成(布尔值),而另一些则在其后需要一个值。在这种情况下,值必须紧跟在设置名称之后提供。当前支持的设置如下。
强制在由同一行上声明的任何套接字接受的任何连接上使用 PROXY 协议。PROXY 协议的版本 1 和 2 都受支持并能正确检测。PROXY 协议规定了传入连接的第 3/4 层地址,这些地址将在任何使用地址的地方使用,唯一的例外是 "tcp-request connection" 规则,它只会看到真实的连接地址。日志将反映协议中指示的地址,除非协议被违反,在这种情况下仍将使用真实地址。此关键字与外部组件的支持相结合,可以作为 X-Forwarded-For 机制的一种高效可靠的替代方案,该机制并非总是可靠,甚至并非总是可用。另请参阅 "tcp-request connection expect-proxy" 以更精细地设置允许哪些客户端使用该协议。
这会启用 TLS ALPN 扩展,并通告指定的协议列表作为 ALPN 之上支持的协议。协议列表由逗号分隔的协议名称列表组成,例如:"http/1.1,http/1.0"(不带引号)。这要求 SSL 库在构建时启用了对 TLS 扩展的支持(使用 haproxy -vv 检查)。ALPN 扩展取代了最初的 NPN 扩展。
将套接字的 backlog 设置为此值。如果未指定,则使用前端的 backlog,通常默认为 maxconn 值。
此设置仅在内置 OpenSSL 支持时可用。它设置用于生成 ECDH 临时密钥的命名曲线(RFC 4492)。默认情况下,使用的命名曲线是 prime256v1。
此设置仅在内置 OpenSSL 支持时可用。它指定一个 PEM 文件,用于加载验证客户端证书的 CA 证书。
此设置仅在内置 OpenSSL 支持时可用。设置一个逗号分隔的错误 ID 列表,在深度 > 0 的验证期间忽略这些错误。如果设置为 'all',则忽略所有错误。如果忽略了某个错误,SSL 握手不会中止。
此设置仅在内置 OpenSSL 支持时可用。它指定一个 PEM 文件,其中包含用于创建和签署服务器证书的 CA 证书和 CA 私钥。当启用证书动态生成时,这是一个强制性设置。有关详细信息,请参见 'generate-certificates'。
此设置仅在内置 OpenSSL 支持时可用。它是 CA 私钥的密码。此设置是可选的,仅在启用证书动态生成时使用。有关详细信息,请参见 'generate-certificates'。
此设置仅在内置 OpenSSL 支持时可用。它设置描述在 SSL/TLS 握手期间协商的密码算法列表(“密码套件”)的字符串。字符串的格式在 OpenSSL 手册页的 "man 1 ciphers" 中定义,例如可以是 "AES:ALL:!aNULL:!eNULL:+RC4:@STRENGTH" 这样的字符串(不带引号)。
此设置仅在内置 OpenSSL 支持时可用。它指定一个 PEM 文件,用于加载验证客户端证书的证书吊销列表。
此设置仅在内置 OpenSSL 支持时可用。它指定一个 PEM 文件,其中包含所需的证书和任何关联的私钥。此文件可以通过将多个 PEM 文件连接成一个来构建(例如 cat cert.pem key.pem > combined.pem)。如果您的 CA 需要中间证书,也可以将其连接到此文件中。如果使用的 OpenSSL 支持 Diffie-Hellman,则会加载此文件中的参数。如果使用目录名代替 PEM 文件,则目录中找到的所有文件都将按字母顺序加载,除非其名称以 '.issuer'、'.ocsp' 或 '.sctl' 结尾(保留扩展名)。此指令可以指定多次,以便从多个文件或目录加载证书。这些证书将呈现给提供有效 TLS 服务器名称指示(SNI)字段且该字段与其 CN 或 alt subjects 之一匹配的客户端。支持通配符,其中通配符 '*' 用于代替第一个主机名组件(例如:*.example.org 匹配 www.example.org 但不匹配 www.sub.example.org)。如果客户端未提供 SNI,或者 SSL 库不支持 TLS 扩展,或者客户端提供的 SNI 主机名与任何证书都不匹配,则将呈现第一个加载的证书。这意味着当从目录加载证书时,强烈建议首先将默认证书作为文件加载,或者确保它始终是目录中的第一个。请注意,同一证书可以多次加载而没有副作用。某些 CA(例如 Godaddy)在获取证书时会提供一个不包括 HAProxy 的服务器类型下拉列表。如果发生这种情况,请务必选择 CA 认为需要中间 CA 的 Web 服务器(对于 Godaddy,选择 Apache Tomcat 会得到正确的证书包,但许多其他服务器,例如 nginx,会导致错误的证书包,对某些客户端无效)。对于每个 PEM 文件,haproxy 会检查是否存在与 PEM 文件路径相同但后缀为 ".ocsp" 的文件。如果找到此类文件,则会自动启用对 TLS 证书状态请求扩展(也称为“OCSP stapling”)的支持。此文件的内容是可选的。如果非空,它必须包含一个有效的 DER 格式的 OCSP 响应。为了有效,OCSP 响应必须符合以下规则:它必须指示良好状态,它必须是 PEM 文件证书的单个响应,并且在添加时必须有效。如果不遵守这些规则,OCSP 响应将被忽略并发出警告。为了识别 OCSP 响应适用于哪个证书,需要颁发者的证书。如果在 PEM 文件中找不到颁发者的证书,它将从与 PEM 文件路径相同但后缀为 ".issuer" 的文件中加载(如果存在),否则将出错。对于每个 PEM 文件,haproxy 还会检查是否存在与 PEM 文件路径相同但后缀为 ".sctl" 的文件。如果找到此类文件,则启用对证书透明度(RFC6962)TLS 扩展的支持。该文件必须包含有效的签名证书时间戳列表,如 RFC 中所述。文件会被解析以检查基本语法,但不会验证签名。
此设置仅在内置 OpenSSL 支持时可用。设置一个逗号分隔的错误 ID 列表,在深度 == 0 的验证期间忽略这些错误。如果设置为 'all',则忽略所有错误。如果忽略了某个错误,SSL 握手不会中止。
此设置仅在内置 OpenSSL 支持时可用。它指定一个 PEM 文件列表,每个证书可以有可选的 SNI 过滤器列表,每行格式如下:<crtfile> [[!]<snifilter> ...] SNI 过滤器支持通配符。可以在配置中指定负向过滤器,但它们仅用作提示,不起任何作用。(这在较新的 haproxy 版本中有所改变)如果要从通配符中排除某个 SNI,请在另一行上使用此正向 SNI。(如示例中所示)。这些证书将呈现给提供有效 TLS 服务器名称指示(SNI)字段且该字段与其中一个 SNI 过滤器匹配的客户端。如果未指定 SNI 过滤器,则使用 CN 和 alt subjects。此指令可以指定多次。有关更多信息,请参见 "crt" 选项。仍然需要默认证书以满足 OpenSSL 的期望。如果不使用,可以使用 'strict-sni' 选项。是一个可选关键字,仅在某些 Linux 内核上受支持。它表示只有在连接上有数据到达时,或者最坏情况下在第一次重传后,才会接受连接。这只应在客户端首先发言的协议上使用(例如:HTTP)。通过确保在接受连接时大部分请求已经可用,它可以略微提高性能。另一方面,它将无法检测到不发言的连接。需要注意的是,此选项在所有内核版本直到 2.6.31 中都是有问题的,因为连接在客户端发言之前永远不会被接受。这可能会导致前置防火墙看到一个已建立的连接,而代理只会看到它处于 SYN_RECV 状态的问题。此选项仅在 TCPv4/TCPv6 套接字上受支持,并被其他套接字忽略。
此选项强制在此侦听器实例化的 SSL 连接上仅使用 SSLv3。对于高连接率,SSLv3 通常比 TLS 对应版本成本更低。此选项也可在全局语句 "ssl-default-bind-options" 中使用。另请参阅 "no-tlsv*" 和 "no-sslv3"。
此选项强制在此侦听器实例化的 SSL 连接上仅使用 TLSv1.0。此选项也可在全局语句 "ssl-default-bind-options" 中使用。另请参阅 "no-tlsv*" 和 "no-sslv3"。
此选项强制在此侦听器实例化的 SSL 连接上仅使用 TLSv1.1。此选项也可在全局语句 "ssl-default-bind-options" 中使用。另请参阅 "no-tlsv*" 和 "no-sslv3"。
此选项强制在此侦听器实例化的 SSL 连接上仅使用 TLSv1.2。此选项也可在全局语句 "ssl-default-bind-options" 中使用。另请参阅 "no-tlsv*" 和 "no-sslv3"。
此设置仅在内置 OpenSSL 支持时可用。它启用动态 SSL 证书生成。需要一个 CA 证书及其私钥(参见 'ca-sign-file')。当 HAProxy 配置为透明转发代理时,由于呈现给客户端的证书上的通用名称不匹配,SSL 请求会产生错误。启用此选项后,HAProxy 将尝试使用客户端指示的 SNI 主机名伪造一个证书。这仅在没有证书匹配 SNI 主机名时才会发生(参见 'crt-list')。如果发生错误,则使用默认证书,否则设置 'strict-sni' 选项。当 HAProxy 配置为反向代理以简化具有许多后端的架构部署时,也可以使用此选项。创建 SSL 证书是一项昂贵的操作,因此使用 LRU 缓存来存储伪造的证书(参见 'tune.ssl.ssl-ctx-cache-size')。它增加了 HAProxy 的内存占用,以减少多次使用同一证书时的延迟。
将 UNIX 套接字的组设置为指定的系统 gid。也可以在全局部分的 "unix-bind" 语句中默认设置。请注意,某些平台会直接忽略此设置。此设置与 "group" 设置等效,不同之处在于它使用组 ID 而不是组名。此设置对非 UNIX 套接字无效。
将 UNIX 套接字的组设置为指定的系统组。也可以在全局部分的 "unix-bind" 语句中默认设置。请注意,某些平台会直接忽略此设置。此设置与 "gid" 设置等效,不同之处在于它使用组名而不是组 ID。此设置对非 UNIX 套接字无效。
固定套接字 ID。默认情况下,套接字 ID 是自动分配的,但有时为了方便监控而固定它们会更方便。此值必须是严格正数,并且在侦听器/前端内是唯一的。此选项只能在定义单个套接字时使用。
将套接字限制到特定接口。指定后,只有从该特定接口接收的数据包才会由套接字处理。目前仅在 Linux 上受支持。该接口必须是主系统接口,而不是别名接口。如果多个前端绑定到不同的接口,也可以将它们绑定到同一地址。请注意,绑定到网络接口需要 root 权限。此参数仅与 TCPv4/TCPv6 套接字兼容。指定后,返回流量将使用与入站流量相同的接口及其关联的路由表,即使配置了通过不同接口的显式路由也是如此。当同一客户端 IP 地址需要能够访问托管在不同接口上的前端时,这对于解决非对称路由问题非常有用。
此设置仅与 stats 套接字一起使用,以限制可在套接字上发出的命令的性质。它被其他套接字忽略。<level> 可以是以下之一: - "user" 是权限最低的级别;只能读取非敏感统计信息,并且不允许任何更改。在不容易限制对套接字访问的系统上,这很有意义。 - "operator" 是默认级别,适合大多数常见用途。可以读取所有数据,并且只允许非敏感更改(例如:清除最大计数器)。 - "admin" 应谨慎使用,因为一切都是允许的(例如:清除所有计数器)。将套接字限制为此数量的并发连接。多余的连接将保留在系统的 backlog 中,直到释放一个连接。如果未指定,限制将与前端的 maxconn 相同。请注意,在端口范围或多个地址的情况下,相同的值将应用于每个套接字。此设置允许对昂贵的套接字进行不同的限制,例如 SSL 条目,它们很容易耗尽所有内存。
设置用于定义 UNIX 套接字访问权限的八进制模式。也可以在全局部分的 "unix-bind" 语句中默认设置。请注意,某些平台会直接忽略此设置。此设置对非 UNIX 套接字无效。
设置要在传入连接上通告的 TCP 最大段大小(MSS)值。这可用于为某些特定端口强制使用较低的 MSS,例如用于通过 VPN 的连接。请注意,这依赖于一个内核功能,理论上在 Linux 下受支持,但在 2.6.28 之前的所有版本中都有错误。它可能在其他操作系统上工作,也可能不工作。它也可能不改变通告的值,而是改变传出段的有效大小。在以太网网络上,TCPv4 的通常通告值为 1460 = 1500(MTU) - 40(IP+TCP)。如果此值为正,它将用作通告的 MSS。如果为负,它将指示传出段应比传入连接的通告 MSS 减少多少。此参数仅与 TCP v4/v6 套接字兼容。
为这些套接字设置一个可选名称,该名称将在统计页面上报告。
在 Linux 上,可以指定套接字将属于哪个网络命名空间。此指令使得可以显式地将侦听器绑定到不同于默认命名空间的命名空间。请参考您的操作系统文档以了解有关网络命名空间的更多详细信息。
设置从套接字发起的连接的“友好度”(niceness)。值必须在 -1024 到 1024(含)之间,默认为零。正值意味着此类连接对其他连接更友好,并且容易在调度器中让出位置。相反,负值意味着连接希望以比其他连接更高的优先级运行。这种差异仅在高负载下,当系统接近饱和时才会发生。负值适用于低延迟或管理服务,而高值通常推荐用于 CPU 密集型任务,如 SSL 处理或对延迟不那么敏感的批量传输。例如,为 SMTP 套接字使用正值,为 RDP 套接字使用负值可能是有意义的。
此设置仅在内置 OpenSSL 支持时可用。它在支持 SSL 的情况下,禁用侦听器实例化的任何套接字上的 SSLv3 支持。请注意,SSLv2 在代码中被强制禁用,无法使用任何配置选项启用。此选项也可在全局语句 "ssl-default-bind-options" 中使用。另请参阅 "force-tls*" 和 "force-sslv3"。
此设置仅在内置 OpenSSL 支持时可用。它禁用无状态会话恢复(RFC 5077 TLS Ticket 扩展)并强制使用有状态会话恢复。无状态会话恢复在 CPU 使用方面成本更高。此选项也可在全局语句 "ssl-default-bind-options" 中使用。
此设置仅在内置 OpenSSL 支持时可用。它在支持 SSL 的情况下,禁用侦听器实例化的任何套接字上的 TLSv1.0 支持。请注意,SSLv2 在代码中被强制禁用,无法使用任何配置选项启用。此选项也可在全局语句 "ssl-default-bind-options" 中使用。另请参阅 "force-tlsv*" 和 "force-sslv3"。
此设置仅在内置 OpenSSL 支持时可用。它在支持 SSL 的情况下,禁用侦听器实例化的任何套接字上的 TLSv1.1 支持。请注意,SSLv2 在代码中被强制禁用,无法使用任何配置选项启用。此选项也可在全局语句 "ssl-default-bind-options" 中使用。另请参阅 "force-tlsv*" 和 "force-sslv3"。
此设置仅在内置 OpenSSL 支持时可用。它在支持 SSL 的情况下,禁用侦听器实例化的任何套接字上的 TLSv1.2 支持。请注意,SSLv2 在代码中被强制禁用,无法使用任何配置选项启用。此选项也可在全局语句 "ssl-default-bind-options" 中使用。另请参阅 "force-tlsv*" 和 "force-sslv3"。
这会启用 NPN TLS 扩展,并通告指定的协议列表作为 NPN 之上支持的协议。协议列表由逗号分隔的协议名称列表组成,例如:"http/1.1,http/1.0"(不带引号)。这要求 SSL 库在构建时启用了对 TLS 扩展的支持(使用 haproxy -vv 检查)。请注意,NPN 扩展已被 ALPN 扩展取代(参见 "alpn" 关键字)。
这将限制此侦听器允许运行的进程列表。它不强制执行任何进程,但会排除不匹配的进程。如果前端使用 "bind-process" 设置,则应用两者的交集。如果最终侦听器不允许在任何剩余的进程上运行,则会发出警告,并且侦听器要么在侦听器的第一个进程上运行(如果指定了单个进程),要么在其所有进程上运行(如果指定了多个进程)。对于需要多个范围的不太可能的情况,可以重复此指令。此指令的主要目的是与 stats 套接字一起使用,并为每个进程提供一个不同的套接字。第二个目的是让多个绑定行共享相同的 IP:port 但不共享相同的进程,以便系统可以将传入的连接分配到多个队列中,并允许更平滑的进程间负载均衡。目前已知 Linux 3.9 及更高版本支持此功能。另请参阅 "bind-process" 和 "nbproc"。
此设置仅在内置 OpenSSL 支持时可用。它在此侦听器实例化的连接上启用 SSL 解密。需要一个证书(参见上面的 "crt")。缓冲区中的所有内容都将以明文形式显示,因此 ACL 和 HTTP 处理只能访问解密后的内容。此设置仅在内置 OpenSSL 支持时可用。仅当客户端提供的 SNI 与证书匹配时,才允许 SSL/TLS 协商。不使用默认证书。有关更多信息,请参见 "crt" 选项。为此侦听套接字实例化的所有传入连接设置 TCP 用户超时。此选项自 Linux 版本 2.6.37 起可用。它允许 haproxy 为包含数据的套接字配置一个超时,如果这些数据在配置的延迟内未收到确认。这对于经历长空闲期的长连接(例如远程终端或数据库连接池)尤其有用,在这些连接中,客户端和服务器的超时必须保持较高以允许长时间的空闲,但同时检测到客户端已消失以释放与其连接(以及服务器会话)相关的所有资源又非常重要。参数是默认以毫秒表示的延迟。这仅适用于常规 TCP 连接,对其他协议无效。
是一个可选关键字,仅在 Linux 内核版本 >= 3.7 上受支持。它在监听套接字上启用 TCP 快速打开(TCP Fast Open),这意味着支持此功能的客户端将能够在第二次连接开始的三次握手期间发送请求并接收响应,从而在第一次连接后节省一次往返时间。这仅对连接率高且每次往返都很重要的协议有意义。这可能会导致许多防火墙出现问题,因为它们不接受 SYN 数据包上的数据,因此只应在经过充分测试后才启用此选项。此选项仅在 TCPv4/TCPv6 套接字上受支持,并被其他套接字忽略。如果您的 libc 未定义 TCP_FASTOPEN,您可能需要使用 USE_TFO=1 来构建 HAProxy。
设置 TLS ticket 密钥文件以从中加载密钥。密钥长度需为 48 字节,并使用 base64 编码(例如 openssl rand -base64 48)。密钥数量由 TLS_TICKETS_NO 构建选项指定(默认为 3),并且文件中必须至少存在同样数量的密钥。最后的 TLS_TICKETS_NO 个密钥将用于解密,倒数第二个密钥用于加密。这使得通过简单地将新密钥附加到文件并重新加载进程即可轻松轮换密钥。密钥必须定期轮换(例如,每 12 小时一次),否则会危及完全正向保密性(Perfect Forward Secrecy)。将密钥保存在任何永久性存储(如硬盘)之外也是一个好主意(提示:使用 tmpfs 并且不要交换这些文件)。生命周期提示可以使用 tune.ssl.timeout 进行更改。
是一个可选关键字,仅在某些 Linux 内核上受支持。它表示即使地址不属于本地机器,也会绑定这些地址,并且目标为这些地址的数据包将被截获,就好像这些地址是本地配置的一样。这通常需要启用 IP 转发。注意!不要将此与默认地址 '*' 一起使用,因为它会重定向指定端口的所有流量。此关键字仅在 HAProxy 使用 USE_LINUX_TPROXY=1 构建时可用。此参数仅与 TCPv4 和 TCPv6 套接字兼容,具体取决于内核版本。一些发行版的内核包含该功能的向后移植版本,因此请向您的供应商查询支持情况。
是一个可选关键字,仅在包括 Linux 内核版本 >= 2.4.21 在内的大多数最新系统上受支持。它用于在使用默认地址时将套接字同时绑定到 IPv4 和 IPv6。在默认情况下仅绑定到 IPv6 的系统上,这样做有时是必要的。它对非 IPv6 套接字没有影响,并被“v6only”选项覆盖。
是一个可选关键字,仅在包括 Linux 内核版本 >= 2.4.21 在内的大多数最新系统上受支持。它用于在使用默认地址时将套接字仅绑定到 IPv6。这样做有时比系统范围的设置更受欢迎,因为它是针对每个监听器的。它对非 IPv6 套接字没有影响,并优先于“v4v6”选项。
将 UNIX 套接字的所有者设置为指定的系统 uid。它也可以在全局部分的“unix-bind”语句中默认设置。请注意,某些平台会直接忽略此设置。此设置与“user”设置等效,不同之处在于使用的是用户的数字 ID 而不是其名称。此设置被非 UNIX 套接字忽略。
将 UNIX 套接字的所有者设置为指定的系统用户。它也可以在全局部分的“unix-bind”语句中默认设置。请注意,某些平台会直接忽略此设置。此设置与“uid”设置等效,不同之处在于使用的是用户名而不是其 uid。此设置被非 UNIX 套接字忽略。
此设置仅在构建时包含 OpenSSL 支持时可用。如果设置为 'none',则不请求客户端证书。这是默认设置。在其他情况下,会请求客户端证书。如果客户端在请求后未提供证书,并且 'verify' 设置为 'required',则握手将中止,而如果设置为 'optional',则会成功。客户端提供的证书始终使用来自 'ca-file' 的 CA 和来自 'crl-file' 的可选 CRL 进行验证。验证失败时,握手将中止,无论 'verify' 选项如何设置,除非错误代码与 'ca-ignore-err' 或 'crt-ignore-err' 中列出的错误代码完全匹配。
“server”和“default-server”关键字支持一些设置,这些设置都作为参数在服务器行上传递。这些参数出现的顺序无关紧要,并且它们都是可选的。其中一些设置是单个词(布尔值),而另一些则在其后需要一个或多个值。在这种情况下,值必须紧跟在设置名称之后。除了 default-server,如果使用这些设置,它们都必须在服务器地址之后指定: server <name> <address>[:port] [settings ...] default-server [settings ...] 当前支持的设置如下。
使用“addr”参数,可以为发送健康检查或探测代理检查使用不同的 IP 地址。在某些服务器上,可能希望将一个 IP 地址专门用于能够执行比应用程序更适合健康检查的复杂测试的特定组件。如果未设置“check”参数,则此参数将被忽略。另请参阅“port”参数。在 default-server 中支持:否
启用一个辅助的代理检查,该检查独立于常规健康检查运行。代理健康检查通过与“agent-port”参数设置的端口建立 TCP 连接并读取一个 ASCII 字符串来执行。该字符串由一系列由空格、制表符或逗号分隔的单词组成,顺序不限,可选地以 '\r' 和/或 '\n' 结尾,每个单词包括: - 正整数百分比的 ASCII 表示,例如 "75%"。这种格式的值将根据 haproxy 启动时配置的服务器初始权重按比例设置权重。请注意,零权重在统计页面上报告为“DRAIN”,因为它对服务器具有相同的效果(从负载均衡服务器组中移除)。 - 单词 "ready"。这将把服务器的管理状态变为 READY 模式,从而取消任何 DRAIN 或 MAINT 状态。 - 单词 "drain"。这将把服务器的管理状态变为 DRAIN 模式,因此它将不接受除通过持久性接受的连接之外的任何新连接。 - 单词 "maint"。这将把服务器的管理状态变为 MAINT 模式,因此它将完全不接受任何新连接,并且健康检查将停止。 - 单词 "down"、"fail" 或 "stopped",可选地后跟一个井号('#')后的描述字符串。所有这些都将服务器的操作状态标记为 DOWN,但由于单词本身会在统计页面上报告,这种差异允许管理员知道情况是否是预期的:服务可能是有意停止的,可能看起来正常但未通过某些有效性测试,或者可能被视为关闭(例如:缺少进程或端口无响应)。 - 单词 "up" 在健康检查也报告服务可访问时,将服务器的操作状态设置回 UP。代理未通告的参数不会更改。例如,一个代理可能被设计为监视 CPU 使用情况,只报告一个相对权重,而从不与操作状态交互。同样,一个代理可以被设计为一个最终用户界面,有 3 个单选按钮,允许管理员只更改管理状态。然而,重要的是要考虑只有代理可以撤销其自己的操作,所以如果一个服务器通过代理被设置为 DRAIN 模式或 DOWN 状态,代理必须实现其他等效的操作才能使服务重新投入运行。无法连接到代理不被视为错误,因为连接性由通过“check”参数启用的常规健康检查来测试。但请注意,在代理报告 "down" 后停止代理不是一个好主意,因为只有报告 "up" 的代理才能再次将服务器设置为 UP。请注意,Unix 统计套接字上的 CLI 也能够强制代理的结果,以便在需要时解决代理故障问题。需要设置“agent-port”参数。另请参阅“agent-inter”参数。在 default-server 中支持:否
“agent-inter”参数设置两次代理检查之间的间隔为 <delay> 毫秒。如果未指定,延迟默认为 2000 毫秒。与所有其他基于时间的参数一样,它可以以任何其他明确的单位输入,如 { us, ms, s, m, h, d }。如果未设置“timeout check”,则“agent-inter”参数也用作代理检查的超时。为了减少多个服务器托管在同一硬件上时的“共振”效应,所有服务器的代理和健康检查都以一个小的时差启动。也可以使用全局“spread-checks”关键字在代理和健康检查间隔中添加一些随机噪声。这在许多后端使用相同服务器时很有意义。另请参阅“agent-check”和“agent-port”参数。在 default-server 中支持:是
“agent-port”参数设置用于代理检查的 TCP 端口。另请参阅“agent-check”和“agent-inter”参数。在 default-server 中支持:是
当服务器行上存在“backup”时,该服务器仅在所有其他非备份服务器都不可用时才用于负载均衡。但是,带有引用该服务器的持久性 cookie 的请求将始终被服务。默认情况下,只使用第一个可操作的备份服务器,除非在后端设置了“allbackups”选项。另请参阅“allbackups”选项。在 default-server 中支持:否
此设置仅在构建时包含 OpenSSL 支持时可用。它指定一个 PEM 文件,用于加载验证服务器证书的 CA 证书。在 default-server 中支持:否
此选项启用对服务器的健康检查。默认情况下,服务器始终被认为是可用的。如果设置了“check”,则服务器在接受定期的 TCP 连接时被视为可用,以确保它确实能够处理请求。发送测试的默认地址和端口是服务器的地址和端口,默认源地址与后端中定义的相同。可以使用“addr”参数更改地址,使用“port”参数更改端口,使用“source”地址更改源地址,以及使用“inter”、“rise”和“fall”参数更改间隔和计时器。请求方法在后端中使用“httpchk”、“smtpchk”、“mysql-check”、“pgsql-check”和“ssl-hello-chk”选项定义。有关更多信息,请参阅这些选项和参数。在 default-server 中支持:否
此选项强制在传出的健康检查中发送 PROXY 协议行,无论服务器是否为正常流量使用 send-proxy。默认情况下,如果 PROXY 协议已为正常流量启用并且没有“port”或“addr”指令存在,则为健康检查启用 PROXY 协议。但是,如果存在这样的指令,则需要使用“check-send-proxy”选项来强制使用该协议。有关更多信息,请参阅“send-proxy”选项。在 default-server 中支持:否
此选项强制通过 SSL 加密所有健康检查,无论服务器是否为正常流量使用 SSL。这通常在指定了显式的“port”或“addr”指令且未继承 SSL 健康检查时使用。重要的是要理解,此选项在检查下方插入一个 SSL 传输层,因此一个简单的 TCP 连接检查会变成一个 SSL 连接,这取代了旧的 ssl-hello-chk。最常见的用法是通过将“httpchk”与 SSL 检查结合来发送 HTTPS 检查。所有 SSL 设置对健康检查和流量都是通用的(例如:密码套件)。有关更多信息,请参阅“ssl”选项。在 default-server 中支持:否
此选项设置描述与服务器进行 SSL/TLS 握手时协商的密码算法列表的字符串。字符串的格式在 "man 1 ciphers" 中定义。当使用 SSL 与本地网络上的服务器通信时,通常会使用比在互联网上使用的更弱的算法集。这样做可以减少服务器和 haproxy 上的 CPU 使用率,同时仍能与已部署的软件兼容。一些算法,如 RC4-SHA1,相当便宜。如果完全不需要安全性,只需要连接性,使用 DES 可能是合适的。在 default-server 中支持:否
“cookie”参数将分配给服务器的 cookie 值设置为 <value>。此值将在传入请求中进行检查,并且将选择拥有相同值的第一个可操作服务器。反过来,在 cookie 插入或重写模式下,此值将分配给发送给客户端的 cookie。多个服务器共享相同的 cookie 值没有问题,实际上在正常服务器和备份服务器之间这很常见。另请参阅后端部分的“cookie”关键字。在 default-server 中支持:否
此设置仅在构建时包含 OpenSSL 支持时可用。它指定一个 PEM 文件,用于加载验证服务器证书的证书吊销列表。在 default-server 中支持:否
此设置仅在构建时包含 OpenSSL 支持时可用。它指定一个 PEM 文件,用于加载证书和关联的私钥。可以通过将两个 PEM 文件连接成一个来构建此文件。如果服务器发送客户端证书请求,则将发送此证书。在 default-server 中支持:否
“disabled”关键字以“disabled”状态启动服务器。这意味着它被标记为维护模式下的关闭状态,除了持久模式允许的连接外,没有连接会到达它。它非常适合设置新服务器,因为正常流量永远不会到达它们,同时仍然可以通过使用强制持久机制来测试服务。在 default-server 中支持:否
如果启用了健康观察,“error-limit”参数指定触发由“on-error”选项选择的事件的连续错误数。默认设置为 10 个连续错误。在 default-server 中支持:是。另请参阅“check”、“error-limit”和“on-error”。
“fall”参数指出,在 <count> 次连续不成功的健康检查后,服务器将被视为死亡。如果未指定,此值默认为 3。另请参阅“check”、“inter”和“rise”参数。在 default-server 中支持:是
此选项强制在与服务器通信时仅使用 SSLv3。对于高连接率,SSLv3 通常比 TLS 对应版本成本更低。此选项也可在全局语句“ssl-default-server-options”中使用。另请参阅 "no-tlsv*", "no-sslv3"。在 default-server 中支持:否
此选项强制在与服务器通信时仅使用 TLSv1.0。此选项也可在全局语句“ssl-default-server-options”中使用。另请参阅 "no-tlsv*", "no-sslv3"。在 default-server 中支持:否
此选项强制在与服务器通信时仅使用 TLSv1.1。此选项也可在全局语句“ssl-default-server-options”中使用。另请参阅 "no-tlsv*", "no-sslv3"。在 default-server 中支持:否
此选项强制在与服务器通信时仅使用 TLSv1.2。此选项也可在全局语句“ssl-default-server-options”中使用。另请参阅 "no-tlsv*", "no-sslv3"。在 default-server 中支持:否
为服务器设置一个持久 ID。此 ID 必须为正数且在代理中唯一。如果未设置,将自动分配一个未使用的 ID。第一个分配的值将是 1。此 ID 目前仅在统计信息中返回。在 default-server 中支持:否
“inter”参数将两次连续健康检查之间的间隔设置为 <delay> 毫秒。如果未指定,延迟默认为 2000 毫秒。也可以使用“fastinter”和“downinter”根据服务器状态优化检查之间的延迟
| 服务器状态 | 使用的间隔 |
|---|---|
| UP 100% (非过渡状态) | “inter” |
| 过渡性 UP (正在变为 down "fall"), 过渡性 DOWN (正在变为 up "rise"), 或尚未检查。 | 如果设置了“fastinter”,则使用它, 否则使用“inter”。 |
| DOWN 100% (非过渡状态) | 如果设置了“downinter”,则使用它, 否则使用“inter”。 |
与所有其他基于时间的参数一样,它们可以以任何其他明确的单位输入,如 { us, ms, s, m, h, d }。如果未设置“timeout check”,则“inter”参数也用作发送到服务器的健康检查的超时。为了减少多个服务器托管在同一硬件上时的“共振”效应,所有服务器的代理和健康检查都以一个小的时差启动。也可以使用全局“spread-checks”关键字在代理和健康检查间隔中添加一些随机噪声。这在许多后端使用相同服务器时很有意义。在 default-server 中支持:是“maxconn”参数指定将发送到此服务器的最大并发连接数。如果传入的并发请求数高于此值,它们将被排队,等待连接被释放。此参数非常重要,因为它可以防止脆弱的服务器在极端负载下宕机。如果指定了“minconn”参数,则限制变为动态的。默认值为“0”,表示无限制。另请参阅“minconn”和“maxqueue”参数,以及后端的“fullconn”关键字。在 default-server 中支持:是
“maxqueue”参数指定将在此服务器队列中等待的最大连接数。如果达到此限制,下一个请求将被重新分派到其他服务器,而不是无限期地等待服务。这将破坏持久性,但可能允许人们在他们试图连接的服务器即将崩溃时快速重新登录。默认值为“0”,表示队列无限制。另请参阅“maxconn”和“minconn”参数。在 default-server 中支持:是
当设置了“minconn”参数时,maxconn 限制将成为一个根据后端负载动态变化的限制。服务器将始终接受至少 <minconn> 个连接,绝不会超过 <maxconn> 个,并且当后端并发连接数少于 <fullconn> 时,限制将在这两个值之间平滑过渡。这使得在正常负载期间可以限制服务器上的负载,但在重要负载时可以进一步推高负载,而不会在异常负载期间使服务器过载。另请参阅“maxconn”和“maxqueue”参数,以及“fullconn”后端关键字。在 default-server 中支持:是
在 Linux 上,可以指定套接字属于哪个网络命名空间。此指令使得可以明确地将服务器绑定到不同于默认命名空间的命名空间。有关网络命名空间的更多详细信息,请参阅您的操作系统文档。
此选项在与服务器通信使用 SSL 时禁用 SSL 会话重用。它将强制服务器为每个新连接执行完整的握手。这可能仅对基准测试、故障排除和偏执的用户有用。在 default-server 中支持:否
此选项在与服务器通信使用 SSL 时禁用对 SSLv3 的支持。请注意,SSLv2 在代码中被禁用,不能通过任何配置选项启用。另请参阅“force-sslv3”、“force-tlsv*”。在 default-server 中支持:否此设置仅在构建时包含 OpenSSL 支持时可用。它禁用无状态会话恢复(RFC 5077 TLS Ticket 扩展)并强制使用有状态会话恢复。无状态会话恢复对服务器的 CPU 使用率更高。此选项也可在全局语句“ssl-default-server-options”中使用。在 default-server 中支持:否
此选项在与服务器通信使用 SSL 时禁用对 TLSv1.0 的支持。请注意,SSLv2 在代码中被禁用,不能通过任何配置选项启用。TLSv1 比 SSLv3 更昂贵,因此在与本地服务器通信时禁用它通常是有意义的。此选项也可在全局语句“ssl-default-server-options”中使用。另请参阅“force-sslv3”、“force-tlsv*”。在 default-server 中支持:否
此选项在与服务器通信使用 SSL 时禁用对 TLSv1.1 的支持。请注意,SSLv2 在代码中被禁用,不能通过任何配置选项启用。TLSv1 比 SSLv3 更昂贵,因此在与本地服务器通信时禁用它通常是有意义的。此选项也可在全局语句“ssl-default-server-options”中使用。另请参阅“force-sslv3”、“force-tlsv*”。在 default-server 中支持:否
此选项在与服务器通信使用 SSL 时禁用对 TLSv1.2 的支持。请注意,SSLv2 在代码中被禁用,不能通过任何配置选项启用。TLSv1 比 SSLv3 更昂贵,因此在与本地服务器通信时禁用它通常是有意义的。此选项也可在全局语句“ssl-default-server-options”中使用。另请参阅“force-sslv3”、“force-tlsv*”。在 default-server 中支持:否
从不将分配给此服务器的连接添加到粘性表中。这可以与 backup 结合使用,以确保对备份服务器禁用粘性表持久性。在 default-server 中支持:否
此选项启用基于观察与服务器通信的健康状况调整。默认情况下,此功能是禁用的,启用它还需要启用健康检查。支持两种模式:“layer4”和“layer7”。在 layer4 模式下,只有成功/不成功的 tcp 连接是重要的。在 layer7 模式下(仅适用于 http 代理),将验证从服务器收到的响应,例如有效/错误的 http 代码、无法解析的头部、超时等。有效的状态码包括 100 到 499、501 和 505。在 default-server 中支持:否。另请参阅“check”、“on-error”和“error-limit”。
选择当检测到足够多的连续错误时应该发生什么。目前有四种模式可用: - fastinter:强制快速间隔 - fail-check:模拟一次失败的检查,并强制快速间隔(默认) - sudden-death:模拟一次致命前失败的健康检查,再多一次失败的检查将标记服务器为关闭,并强制快速间隔 - mark-down:立即将服务器标记为关闭并强制快速间隔。在 default-server 中支持:是。另请参阅“check”、“observe”和“error-limit”。
修改服务器被标记为关闭时发生的操作。目前有一个可用的操作: - shutdown-sessions:关闭对端会话。当启用此设置时,当服务器宕机时,所有到该服务器的连接将立即终止。如果健康检查检测到的情况比简单的连接状态更复杂,并且长超时会导致服务在太长时间内无响应,则可以使用此设置。例如,健康检查可能检测到数据库卡住,并且没有机会再重用现有连接。以这种方式终止的连接将以 'D' 终止代码(表示“Down”)记录。默认情况下禁用操作。在 default-server 中支持:是
修改服务器被标记为启动时发生的操作。目前有一个可用的操作: - shutdown-backup-sessions:关闭所有备份服务器上的会话。这仅在该服务器不处于备份状态且未被禁用(其有效权重必须 > 0)时执行。在处理长会话(例如:LDAP、SQL 等)时,有时可以使用此选项来强制活动服务器在恢复后重新接管所有流量。这样做可能比它试图解决的问题带来更多麻烦(例如:不完整的事务),所以请极其谨慎地使用此功能。因服务器启动而被终止的会话将以 'U' 终止代码(表示“Up”)记录。默认情况下禁用操作。在 default-server 中支持:是
使用“port”参数,可以使用不同的端口来发送健康检查。在某些服务器上,可能希望将一个端口专门用于一个能够执行比应用程序更适合健康检查的复杂测试的特定组件。例如,在 inetd 中运行一个简单的脚本是很常见的。如果未设置“check”参数,此参数将被忽略。另请参阅“addr”参数。在 default-server 中支持:是
“redir”参数为所有发往此服务器的 GET 和 HEAD 请求启用重定向模式。这意味着 HAProxy 将不会将请求转发到服务器,而是会发送一个“HTTP 302”响应,其“Location”头部由该前缀紧跟请求的 URI(从路径组件的开头的'/'开始)组成。这意味着在 <prefix> 之后不应使用尾部斜杠。所有无效请求都将被拒绝,所有非 GET 或 HEAD 请求将由服务器正常处理。请注意,由于响应是完全伪造的,因此响应中不可能进行任何头部修改或 cookie 插入。然而,请求中的 cookie 仍然会被分析,这使得该解决方案完全适用于在本地灾难发生时将用户引导到远程位置。主要用途是通过让客户端直接连接到静态服务器来增加其带宽。注意:此处切勿使用相对位置,这会导致客户端和 HAProxy 之间的循环!
server srv1 192.168.1.1:80 redir http://image1.mydomain.com check
在 default-server 中支持:否
“rise”参数指出,在 <count> 次连续成功的健康检查后,服务器将被视为可操作。如果未指定,此值默认为 2。另请参阅“check”、“inter”和“fall”参数。在 default-server 中支持:是
当为服务器启用 DNS 解析并返回来自不同地址族的多个 IP 地址时,HAProxy 将优先使用在“resolve-prefer”参数中提到的地址族的 IP 地址。可用地址族:“ipv4”和“ipv6”。默认值:ipv6。在 default-server 中支持:是
server s1 app1.domain.com:80 resolvers mydns resolve-prefer ipv6
指向一个现有的“resolvers”部分,以解析当前服务器的主机名。为了能够正常工作,DNS 解析要求在服务器上启用健康检查。实际上,是健康检查触发了 DNS 解析。您必须在每个需要 DNS 解析的服务器行上指定一个 'resolvers' 参数。在 default-server 中支持:否server s1 app1.domain.com:80 check resolvers mydns
另请参见 第 5.3 节
“send-proxy”参数强制在与此服务器建立的任何连接上使用 PROXY 协议。PROXY 协议会告知另一端传入连接的第 3/4 层地址,以便无论上层协议是什么,它都可以知道客户端的地址或其访问的公共地址。对于由“accept-proxy”监听器接受的连接,将使用通告的地址。仅支持 TCPv4 和 TCPv6 地址族。其他地址族,如 Unix 套接字,将报告一个 UNKNOWN 地址族。使用此选项的服务器可以完全链接到另一个带有“accept-proxy”设置的 haproxy 实例。如果服务器不支持该协议,则不应使用此设置。当向服务器发送健康检查时,如果设置了此选项,会自动使用 PROXY 协议,除非有明确的“port”或“addr”指令,在这种情况下,也需要一个明确的“check-send-proxy”指令来使用 PROXY 协议。另请参阅“bind”关键字的“accept-proxy”选项。在 default-server 中支持:否
“send-proxy-v2”参数强制在与此服务器建立的任何连接上使用 PROXY 协议版本 2。PROXY 协议会告知另一端传入连接的第 3/4 层地址,以便无论上层协议是什么,它都可以知道客户端的地址或其访问的公共地址。如果服务器不支持此版本的协议,则不应使用此设置。另请参阅“bind”关键字的“send-proxy”选项。在 default-server 中支持:否
“send-proxy-v2-ssl”参数强制在与此服务器建立的任何连接上使用 PROXY 协议版本 2。PROXY 协议会告知另一端传入连接的第 3/4 层地址,以便无论上层协议是什么,它都可以知道客户端的地址或其访问的公共地址。此外,PROXY 协议的 SSL 信息扩展会被添加到 PROXY 协议头中。如果服务器不支持此版本的协议,则不应使用此设置。另请参阅“bind”关键字的“send-proxy-v2”选项。在 default-server 中支持:否
“send-proxy-v2-ssl”参数强制在与此服务器建立的任何连接上使用 PROXY 协议版本 2。PROXY 协议会告知另一端传入连接的第 3/4 层地址,以便无论上层协议是什么,它都可以知道客户端的地址或其访问的公共地址。此外,PROXY 协议的 SSL 信息扩展以及客户端证书主题中的通用名称(如果有)会被添加到 PROXY 协议头中。如果服务器不支持此版本的协议,则不应使用此设置。另请参阅“bind”关键字的“send-proxy-v2”选项。在 default-server 中支持:否
服务器的“slowstart”参数接受一个以毫秒为单位的值,该值指示一个刚刚恢复的服务器需要多长时间才能达到全速运行。与所有其他基于时间的参数一样,它可以以任何其他明确的单位输入,如 { us, ms, s, m, h, d }。在此期间,速度从 0 线性增长到 100%。该限制适用于两个参数: - maxconn:服务器接受的连接数将从 1 增长到由 (minconn,maxconn,fullconn) 定义的通常动态限制的 100%。 - weight:当后端使用动态加权算法时,权重从 1 线性增长到 100%。在这种情况下,权重在每次健康检查时更新。因此,重要的是“inter”参数要小于“slowstart”,以最大化步数。slowstart 在 haproxy 启动时从不应用,否则会对正在运行的服务器造成麻烦。它仅在服务器之前被视为失败时应用。在 default-server 中支持:是
“sni”参数评估样本获取表达式,将其转换为字符串,并将结果用作发送到服务器的 SNI TLS 扩展中的主机名。一个典型的用例是在桥接的 HTTPS 场景中发送从客户端收到的 SNI,使用“ssl_fc_sni”样本获取表达式,尽管诸如 req.hdr(host) 之类的替代方案也可能合理。在 default-server 中支持:否
“source”参数设置连接到服务器时将使用的源地址。它遵循与后端“source”关键字完全相同的参数和原则,只是它只适用于引用它的服务器。有关详细信息,请查阅“source”关键字。此外,服务器行上的“source”语句允许通过指示由短划线('-')分隔的下限和上限来指定源端口范围。某些操作系统可能要求在指定源端口范围时提供有效的 IP 地址。允许多个服务器具有相同的 IP/范围。这样做可以绕过 64k 总并发连接的最大限制。届时限制将达到每个服务器 64k 连接。在 default-server 中支持:否
此选项在到服务器的出站连接上启用 SSL 加密。在使用 SSL 连接到服务器时,使用“verify”验证服务器证书至关重要,否则通信容易受到简单的中间人攻击,从而使 SSL 无效。当使用此选项时,除非有“port”或“addr”指令指示应将检查发送到不同位置,否则健康检查也会自动以 SSL 方式发送。要强制进行 SSL 健康检查,请参阅“check-ssl”选项。在 default-server 中支持:否
为所有到此服务器的出站连接设置 TCP 用户超时。此选项自 Linux 版本 2.6.37 起可用。它允许 haproxy 为包含未在配置的延迟内收到确认的数据的套接字配置超时。这对于经历长时间空闲期的长连接特别有用,例如远程终端或数据库连接池,其中客户端和服务器的超时必须保持较高以允许长时间空闲,但同时检测到服务器已消失以释放与其连接(和客户端会话)相关的所有资源又非常重要。一个典型的用例也是在健康检查太慢或软重载期间强制终止死掉的服务器连接,因为此时健康检查被禁用。参数是默认以毫秒表示的延迟。这仅适用于常规 TCP 连接,对其他协议无效。
此选项启用了通过跟踪另一个服务器来设置当前服务器状态的能力。可以跟踪一个本身也在跟踪另一个服务器的服务器,前提是在链的末端,有一个服务器启用了健康检查。如果省略 <proxy>,则使用当前的代理。如果使用了 disable-on-404,则必须在两个代理上都启用它。在 default-server 中支持:否
此设置仅在构建时包含 OpenSSL 支持时可用。如果设置为 'none',则不验证服务器证书。在其他情况下,使用来自 'ca-file' 的 CA 和来自 'crl-file' 的可选 CRL 来验证服务器提供的证书。如果在全局部分未指定 'ssl_server_verify',则这是默认设置。验证失败时,握手将中止。在使用 SSL 连接到服务器时,验证服务器证书至关重要,否则通信容易受到简单的中间人攻击,从而使 SSL 完全无效。在 default-server 中支持:否
此设置仅在构建时包含 OpenSSL 支持时可用,并且仅在同时指定了 'verify required' 时生效。设置后,将检查服务器提供的证书的主题和主题备用名称中的主机名。如果证书中的主机名都不匹配指定的主机名,则握手将中止。服务器提供的证书中的主机名可能包含通配符。在 default-server 中支持:否
“weight”参数用于调整服务器相对于其他服务器的权重。所有服务器将接收与其权重相对于所有权重总和成比例的负载,因此权重越高,负载越高。默认权重为 1,最大值为 256。值为 0 表示服务器不参与负载均衡,但仍会接受持久连接。如果此参数用于根据服务器容量分配负载,建议从既可以增长也可以缩小的值开始,例如在 10 到 100 之间,以便为以后的调整留出足够的空间。在 default-server 中支持:是
HAProxy 允许在服务器行上使用主机名,通过名称服务器来检索其 IP 地址。默认情况下,HAProxy 在解析配置文件时、启动时解析名称,并为进程的生命周期缓存结果。在某些情况下,这还不够,例如在亚马逊环境中,服务器的 IP 可能会在重启后更改,或者 ELB 虚拟 IP 可能会根据当前工作负载而更改。本章介绍如何配置 HAProxy 以在运行时处理服务器名称解析。无论是否启用了运行时服务器名称解析,HAProxy 在解析配置时都会继续进行首次解析。请记住,DNS 解析是由健康检查触发的。这使得健康检查成为允许 DNS 解析的必要条件。
正如我们在引言中看到的,HAProxy 中的名称解析发生在进程生命周期的两个不同阶段: 1. 启动时,HAProxy 解析服务器行定义并匹配一个主机名。它使用 libc 函数来解析主机名。此解析依赖于 /etc/resolv.conf 文件。 2. 运行时,当 HAProxy 准备对服务器进行健康检查时,它会验证当前的名称解析是否仍被视为有效。如果无效,它会在健康检查的同时处理一个新的解析。一些其他事件也可以在运行时触发名称解析: - 当服务器的健康检查最终导致连接超时时:这可能是因为服务器有了新的 IP 地址。因此我们需要触发名称解析以了解这个新 IP。一些重要的事情需要注意: - 所有的名称服务器都会同时被查询。HAProxy 将处理第一个有效的响应。 - 当所有服务器都返回错误时,一个解析被认为是无效的(NX、超时、拒绝)。
此部分专门用于与 HAProxy 中名称解析相关的主机信息。可以根据需要设置任意数量的 resolvers 部分。每个部分可以包含多个名称服务器。当一个 resolvers 部分配置了多个名称服务器时,HAProxy 会使用第一个有效的响应。如果响应无效,则只处理最后一个响应。目的是给一个慢速服务器机会,在一个快速但有故障或过时的服务器之后提供一个有效的答案。当每个服务器返回不同的错误类型时,只有最后一个错误被 HAProxy 用来决定应用哪种行为。可以应用两种类型的行为: 1. 停止 DNS 解析 2. 使用新的查询类型重试 DNS 查询 在这种情况下,将按以下确切顺序应用以下类型: 1. ANY 查询类型 2. 对应于 resolve-prefer 服务器参数所指向的地址族的查询类型 3. 剩余的地址族类型 当发生以下错误时,HAProxy 会停止 DNS 解析: - 无效的 DNS 响应包 - 响应的查询部分名称错误 - NX 域 - 服务器拒绝查询 - CNAME 未指向 IP 地址 当发生以下错误时,HAProxy 会尝试新的查询类型: - 响应中没有 Answer 记录 - DNS 响应被截断 - DNS 响应中存在错误 - 响应中未找到预期的 DNS 记录 - 名称服务器超时 例如,在一个 resolvers 部分配置了 2 个名称服务器: - 第一个响应有效并直接应用,第二个响应被忽略 - 第一个响应无效而第二个响应有效,则应用第二个响应; - 第一个响应是 NX 域而第二个响应是截断的响应,则 HAProxy 使用新的类型重试查询; - 第一个响应被截断而第二个响应是 NX 域,则 HAProxy 停止解析。
创建一个标记为 <resolvers id> 的新名称服务器列表。一个 resolvers 部分接受以下参数:
DNS 服务器描述: <id> :服务器的标签,应唯一 <ip> :服务器的 IP 地址 <port> :DNS 服务实际运行的端口
根据最后的解析 <status> 定义应保留最后一次名称解析的 <period> 时间。 <status> :最后的名称解析状态。目前只接受 "valid"。 <period> :当最后一次应答处于 <status> 状态时,两次连续名称解析之间的间隔。它遵循 HAProxy 时间格式。 <period> 默认以毫秒为单位。 "valid" 的默认值为 10s。 注意:由于名称解析是由健康检查触发的,新的解析在 <period> 模健康检查的 <inter> 参数后触发。
定义在放弃之前为解析服务器名称而发送的查询次数 <nb>。默认值:3。当名称服务器超时或完整的 DNS 查询类型故障转移序列结束并且我们需要从默认的 ANY 查询类型重新开始时,会发生重试。
定义与名称解析相关的超时。 <event> :<time> 超时期限适用的事件。可用的事件有: - retry:当未收到响应时,两次 DNS 查询之间的时间。默认值:1s <time> :与事件相关的时间。它遵循 HAProxy 时间格式。 <time> 以毫秒表示。
resolvers mydns nameserver dns1 10.0.0.1:53 nameserver dns2 10.0.0.2:53 resolve_retries 3 timeout retry 1s hold valid 10s
在 HTTP 模式下,可以基于正则表达式重写、添加或删除请求和响应的某些标头。如果某个特定的标头与正则表达式匹配,也可以阻止请求或响应,这足以阻止大多数基本的协议攻击,并防止内部网络信息泄露。如果 HAProxy 遇到一个“信息性响应”(状态码 1xx),它能够处理所有的 rsp* 规则,这些规则可以允许、拒绝、重写或删除标头,但它会拒绝向任何此类消息添加标头,因为这不符合 HTTP 规范。在这种响应中仍然处理标头的原因是,为了阻止和/或修复任何可能发生的信息泄露,例如,因为下游的另一个设备会无条件地添加一个标头,或者因为一个服务器名称出现在那里。当看到此类消息时,正常的处理仍会在下一个非信息性消息上进行。本节涵盖了以下关键字的常见用法,这些关键字在 第 4.2 节 中有详细描述: - reqadd <string> - reqallow <search> - reqiallow <search> - reqdel <search> - reqidel <search> - reqdeny <search> - reqideny <search> - reqpass <search> - reqipass <search> - reqrep <search> <replace> - reqirep <search> <replace> - reqtarpit <search> - reqitarpit <search> - rspadd <string> - rspdel <search> - rspidel <search> - rspdeny <search> - rspideny <search> - rsprep <search> <replace> - rspirep <search> <replace> 所有这些关键字都使用相同的约定。<search> 参数是一个 POSIX 扩展正则表达式(regex),它支持通过括号进行分组(不带反斜杠)。空格和其他分隔符必须用反斜杠('\')前缀,以避免与字段分隔符混淆。其他字符也可以用反斜杠前缀来改变它们的含义: \t 表示制表符 \r 表示回车符(CR) \n 表示换行符(LF) \ 用于标记空格并与分隔符区分开 \# 用于标记井号并与注释区分开 \\ 在正则表达式中使用一个反斜杠 \\\\ 在文本中使用一个反斜杠(*2 用于正则表达式,*2 用于 haproxy) \xXX 用于以 C 语言的方式写入 ASCII 十六进制代码 XX <replace> 参数包含用于替换与正则表达式匹配的最大文本部分的字符串。它可以使用上述特殊字符,并且可以通过紧跟一个从 0 到 9 的数字的反斜杠('\')来引用正则表达式中由括号界定的子字符串,该数字表示分组位置(0 表示整行)。这种做法对“sed”程序的用户来说非常普遍。<string> 参数表示将系统地添加到最后一个标头行之后的字符串。它也可以使用上述特殊字符序列。
- 这些关键字在基于标头内容允许/拒绝时并不总是很方便。强烈建议使用带有“block”关键字的 ACL,这样可以得到更灵活、更易于管理的规则。 - 行总是被视为一个整体。不可能只引用一个标头名称或一个值。这一点很重要,因为标头的写入方式(特别是冒号后的空格数)。 - 第一行总是被视为一个标头,这使得重写或过滤 HTTP 请求 URI 或响应代码成为可能,但反过来也使得区分标头和请求行变得更加困难。正则表达式前缀 ^[^\ \t]*[\ \t] 匹配任何后跟空格的 HTTP 方法,而前缀 ^[^ \t:]*: 匹配任何后跟冒号的标头名称。 - 出于性能原因,添加到请求或响应中的字符数在构建时被限制在 1 到 4 kB 之间。这对于大多数用途来说通常应该绰绰有余。如果在某些偶尔的用法中太短,可以通过在添加新标头之前删除一些无用的标头来获得一些空间。 - 以“reqi”和“rspi”开头的关键字与其不带'i'字母的对应关键字相同,只是它们在匹配模式时忽略大小写。 - 当一个请求先通过一个前端再通过一个后端时,所有来自前端的 req* 规则将被评估,然后所有来自后端的 req* 规则将被评估。响应则应用相反的路径。 - req* 语句在“block”语句之后应用,因此“block”总是第一个,但在“use_backend”之前,以便在切换之前允许重写。
Haproxy 能够从请求或响应流、客户端或服务器信息、表、环境信息等中提取数据……提取此类数据的操作称为获取样本。一旦检索到,这些样本可以用于各种目的,例如作为粘性表(stick-table)的键,但最常见的用法是将其与称为模式(pattern)的预定义常量数据进行匹配。
访问控制列表(ACL)的使用提供了一种灵活的解决方案,用于执行内容切换,并通常基于从请求、响应或任何环境状态中提取的内容来做出决策。其原理很简单: - 从流、表或环境中提取数据样本 - (可选)对提取的样本应用一些格式转换 - 对此样本应用一个或多个模式匹配方法 - 仅当模式与样本匹配时才执行操作 操作通常包括阻止请求、选择后端或添加标头。为了定义一个测试,使用“acl”关键字。语法是: acl <aclname> <criterion> [flags] [operator] [<value>] ... 这会创建一个新的 ACL <aclname>,或者用新的测试来完善一个现有的 ACL。这些测试应用于在 <criterion> 中指定的请求/响应部分,并可以使用可选的标志 [flags] 进行调整。一些标准还支持一个操作符,可以在值集之前指定。可选地,可以对样本应用一些转换操作符,它们将在第一个关键字之后以逗号分隔的关键字列表形式指定。这些值是该标准所支持的类型,并用空格分隔。ACL 名称必须由大写和小写字母、数字、'-'(破折号)、'_'(下划线)、'.'(点)和':'(冒号)组成。ACL 名称是大小写敏感的,这意味着 "my_acl" 和 "My_Acl" 是两个不同的 ACL。ACL 的数量没有强制限制。未使用的 ACL 不会影响性能,它们只消耗少量内存。标准(criterion)通常是一个样本获取方法的名称,或者是其 ACL 特定的变体之一。默认的测试方法由该样本获取方法的输出类型决定。ACL 变体可以描述同一样本获取方法的备用匹配方法。样本获取方法是唯一支持转换的方法。样本获取方法返回的数据可以是以下类型之一: - 布尔值(boolean) - 整数(有符号或无符号) - IPv4 或 IPv6 地址 - 字符串 - 数据块 转换器可以将这些数据中的任何一种转换为任何一种。例如,一些转换器可能将字符串转换为小写字符串,而另一些则将字符串转换为 IPv4 地址,或将网络掩码应用于 IP 地址。最终的样本类型是列表中最后一个转换器应用的类型,默认为样本获取方法的类型。每个样本或转换器返回特定类型的数据,其类型由本文档中的关键字指定。当使用标准样本获取方法声明 ACL 时,某些类型会自动涉及一个默认的匹配方法,如下表所示: +---------------------+-----------------+ | 样本或转换器 | 默认 | | 输出类型 | 匹配方法 | +---------------------+-----------------+ | boolean(布尔值) | bool | +---------------------+-----------------+ | integer(整数) | int | +---------------------+-----------------+ | ip | ip | +---------------------+-----------------+ | string(字符串) | str | +---------------------+-----------------+ | binary(二进制) | 无,使用 "-m" | +---------------------+-----------------+ 请注意,为了匹配二进制样本,必须指定一个匹配方法,见下文。ACL 引擎可以将这些类型与以下类型的模式进行匹配: - 布尔值 - 整数或整数范围 - IP 地址/网络 - 字符串(精确、子串、后缀、前缀、子目录、域) - 正则表达式 - 十六进制块 当前支持以下 ACL 标志: -i:在匹配所有后续模式时忽略大小写。 -f:从文件中加载模式。 -m:使用特定的模式匹配方法 -n:禁止 DNS 解析 -M:像 map 文件一样加载由 -f 指向的文件。 -u:强制 ACL 的唯一 ID --:强制标志结束。当一个字符串看起来像某个标志时很有用。 "-f" 标志后跟一个文件名,该文件中的所有行都将被读取为单个值。如果模式需要从多个文件加载,甚至可以传递多个 "-f" 参数。空行以及以井号('#')开头的行将被忽略。所有前导的空格和制表符都将被剥离。如果绝对需要插入一个以井号开头的有效模式,只需在其前面加一个空格,这样它就不会被当作注释。根据数据类型和匹配方法,haproxy 可能会将行加载到二叉树中,从而实现非常快速的查找。这对于 IPv4 和精确字符串匹配是成立的。在这种情况下,重复项将被自动删除。 "-M" 标志允许 ACL 使用 map 文件。如果设置了此标志,文件将被解析为两列文件。第一列包含 ACL 使用的模式,第二列包含样本。该样本稍后可以被 map 使用。这在某些罕见情况下可能很有用,例如在应用映射之前,ACL 仅用于检查 map 中是否存在某个模式。 "-u" 标志强制 ACL 的唯一 ID。此唯一 ID 与套接字接口一起使用,以识别 ACL 并动态更改其值。请注意,即使设置了 ID,文件也始终由其名称标识。另外,请注意 "-i" 标志适用于后续条目,而不适用于在其之前从文件加载的条目。例如: acl valid-ua hdr(user-agent) -f exact-ua.lst -i -f generic-ua.lst test 在这个例子中,“exact-ua.lst” 的每一行都将与请求的 "user-agent" 标头进行精确匹配。然后,“generic-ua” 的每一行都将进行不区分大小写的匹配。然后,单词 "test" 也将进行不区分大小写的匹配。 "-m" 标志用于在输入样本上选择一个特定的模式匹配方法。所有特定于 ACL 的标准都隐含了一个模式匹配方法,通常不需要这个标志。然而,这个标志对于通用的样本获取方法很有用,可以描述它们将如何与模式进行匹配。这对于返回没有明显匹配方法的数据类型(例如:字符串或二进制)的样本获取是必需的。当指定了 "-m" 并后跟一个模式匹配方法名称时,将使用此方法而不是该标准的默认方法。这使得可以用最初未计划的方式或使用返回字符串的样本获取方法来匹配内容。匹配方法也影响模式的解析方式。 "-n" 标志禁止 DNS 解析。它与加载 IP 文件一起使用。默认情况下,如果解析器无法解析 IP 地址,它会认为解析的字符串可能是一个域名并尝试进行 DNS 解析。"-n" 标志禁用了这种解析。这对于检测格式错误的 IP 列表很有用。请注意,如果 DNS 服务器无法访问,haproxy 配置解析可能会持续数分钟等待超时。在此期间不会显示任何错误消息。"-n" 标志禁用了这种行为。另请注意,在运行时,此功能对于动态 ACL 修改是禁用的。然而,存在一些限制。并非所有方法都可以与所有样本获取方法一起使用。此外,如果 "-m" 与 "-f" 一起使用,则必须放在前面。模式匹配方法必须是以下之一: - "found":只检查请求的样本是否能在流中找到,但不与任何模式进行比较。建议不传递任何模式以避免混淆。这种匹配方法在检测某些内容(如标头、cookie 等)是否存在时特别有用,即使它们是空的且不与任何东西比较或计数。 - "bool":将值作为布尔值检查。它只能应用于返回布尔值或整数值的获取,并且不接受任何模式。值零或 false 不匹配,所有其他值都匹配。 - "int":将值作为整数匹配。它可以与整数和布尔样本一起使用。布尔值 false 是整数 0,true 是整数 1。 - "ip":将值作为 IPv4 或 IPv6 地址匹配。它仅与 IP 地址样本兼容,因此它是隐含的,从不需要。 - "bin":将内容与表示二进制序列的十六进制字符串进行匹配。这可以与二进制或字符串样本一起使用。 - "len":将样本的长度作为整数匹配。这可以与二进制或字符串样本一起使用。 - "str":精确匹配:将内容与字符串进行匹配。这可以与二进制或字符串样本一起使用。 - "sub":子串匹配:检查内容是否至少包含所提供的字符串模式之一。这可以与二进制或字符串样本一起使用。 - "reg":正则表达式匹配:将内容与正则表达式列表进行匹配。这可以与二进制或字符串样本一起使用。 - "beg":前缀匹配:检查内容是否以所提供的字符串模式开头。这可以与二进制或字符串样本一起使用。 - "end":后缀匹配:检查内容是否以所提供的字符串模式结尾。这可以与二进制或字符串样本一起使用。 - "dir":子目录匹配:检查内容的斜杠分隔部分是否与所提供的字符串模式之一完全匹配。这可以与二进制或字符串样本一起使用。 - "dom":域匹配:检查内容的点分隔部分是否与所提供的字符串模式之一完全匹配。这可以与二进制或字符串样本一起使用。例如,要快速检测 HTTP 请求中是否存在 cookie "JSESSIONID",可以这样做: acl jsess_present cook(JSESSIONID) -m found 为了在缓冲区的前 500 字节数据上应用正则表达式,可以使用以下 acl: acl script_tag payload(0,500) -m reg -i <script> 在正则表达式库使用 "-i" 时速度慢得多的系统上,可以在匹配前将样本转换为小写,如下所示: acl script_tag payload(0,500),lower -m reg <script> 所有特定于 ACL 的标准都隐含一个默认的匹配方法。大多数情况下,这些标准是通过连接原始样本获取方法的名称和匹配方法组成的。例如,“hdr_beg” 将 “beg” 匹配应用于使用 “hdr” 获取方法检索的样本。由于所有特定于 ACL 的标准都依赖于一个样本获取方法,因此总是可以使用原始样本获取方法和使用 “-m” 的显式匹配方法来替代。如果在特定于 ACL 的标准上使用 “-m” 指定了备用匹配,则该匹配方法将简单地应用于底层的样本获取方法。例如,下面所有的 ACL 都是完全等价的: acl short_form hdr_beg(host) www. acl alternate1 hdr_beg(host) -m beg www. acl alternate2 hdr_dom(host) -m beg www. acl alternate3 hdr(host) -m beg www. 下表总结了样本或转换器类型与要获取的模式类型之间的兼容性矩阵。它为每个兼容的组合指出了要使用的匹配方法的名称,当该方法是默认方法并且在没有 "-m" 的情况下默认工作时,用尖括号 ">" 和 "<" 括起来。 +-------------------------------------------------+ | 输入样本类型 | +----------------------+---------+---------+---------+---------+---------+ | 模式类型 | 布尔值 | 整数 | ip | 字符串 | 二进制 | +----------------------+---------+---------+---------+---------+---------+ | 无(仅存在性) | found | found | found | found | found | +----------------------+---------+---------+---------+---------+---------+ | 无(布尔值) |> bool <| bool | | bool | | +----------------------+---------+---------+---------+---------+---------+ | 整数(值) | int |> int <| int | int | | +----------------------+---------+---------+---------+---------+---------+ | 整数(长度) | len | len | len | len | len | +----------------------+---------+---------+---------+---------+---------+ | IP 地址 | | |> ip <| ip | ip | +----------------------+---------+---------+---------+---------+---------+ | 精确字符串 | str | str | str |> str <| str | +----------------------+---------+---------+---------+---------+---------+ | 前缀 | beg | beg | beg | beg | beg | +----------------------+---------+---------+---------+---------+---------+ | 后缀 | end | end | end | end | end | +----------------------+---------+---------+---------+---------+---------+ | 子串 | sub | sub | sub | sub | sub | +----------------------+---------+---------+---------+---------+---------+ | 子目录 | dir | dir | dir | dir | dir | +----------------------+---------+---------+---------+---------+---------+ | 域 | dom | dom | dom | dom | dom | +----------------------+---------+---------+---------+---------+---------+ | 正则表达式 | reg | reg | reg | reg | reg | +----------------------+---------+---------+---------+---------+---------+ | 十六进制块 | | | | bin | bin | +----------------------+---------+---------+---------+---------+---------+
为了匹配布尔值,不需要任何值,所有值都会被忽略。布尔匹配默认用于所有类型为“boolean”的获取方法。当使用布尔匹配时,获取的值会按原样返回,这意味着布尔值“true”将始终匹配,而布尔值“false”将永远不匹配。布尔匹配也可以通过在返回整数值的获取方法上使用“-m bool”来强制执行。然后,整数值 0 会被转换为布尔值“false”,所有其他值都会被转换为“true”。
整数匹配默认应用于整数获取方法。它也可以通过使用“-m int”强制应用于布尔值获取。在这种情况下,“false”被转换为整数 0,“true”被转换为整数 1。整数匹配还支持整数范围和运算符。请注意,整数匹配仅适用于正值。范围是用冒号分隔的下限和上限表示的值,两者都可以省略。例如,“1024:65535”是表示非特权端口范围的有效范围,“1024:”也可以。 “0:1023”是特权端口的有效表示,“:1023”也可以。作为一个特例,一些 ACL 函数支持小数,实际上是两个由点分隔的整数。这在某些版本检查中会用到。所有整数属性都适用于这些小数,包括范围和运算符。为了更方便使用,还支持比较运算符。请注意,将运算符与范围一起使用没有太大意义,强烈不建议这样做。同样,对一组值进行顺序比较也没有太大意义。可用于整数匹配的运算符有: eq:如果测试值等于至少一个值,则为 true ge:如果测试值大于或等于至少一个值,则为 true gt:如果测试值大于至少一个值,则为 true le:如果测试值小于或等于至少一个值,则为 true lt:如果测试值小于至少一个值,则为 true 例如,以下 ACL 匹配任何负的 Content-Length 标头: acl negative-length hdr_val(content-length) lt 0 这一个匹配 3.0 到 3.1(含)之间的 SSL 版本: acl sslv3 req_ssl_ver 3:3.1
字符串匹配适用于字符串或二进制获取方法,并存在 6 种不同的形式: - 精确匹配 (-m str):提取的字符串必须与模式完全匹配; - 子串匹配 (-m sub):在提取的字符串中查找模式,如果找到任何一个,则 ACL 匹配; - 前缀匹配 (-m beg):将模式与提取的字符串的开头进行比较,如果任何一个匹配,则 ACL 匹配。 - 后缀匹配 (-m end):将模式与提取的字符串的结尾进行比较,如果任何一个匹配,则 ACL 匹配。 - 子目录匹配 (-m dir):在以斜杠("/")分隔的提取字符串中查找模式,如果任何一个匹配,则 ACL 匹配。 - 域匹配 (-m dom):在以点(".")分隔的提取字符串中查找模式,如果任何一个匹配,则 ACL 匹配。 字符串匹配适用于按字面传递的字符串,但反斜杠("\")除外,它使得可以转义某些字符,如空格。如果在第一个字符串之前传递了“-i”标志,则匹配将忽略大小写。为了匹配字符串“-i”,要么将其放在第二个位置,要么在第一个字符串之前传递“--”标志。当然,匹配字符串“--”也适用相同的原则。不要对可能包含空字节(0x00)的二进制获取使用字符串匹配,因为比较会在遇到第一个空字节时停止。相反,应首先使用 hex 转换器将二进制获取转换为十六进制字符串。# 如果字符串 <tag> 存在于二进制样本中,则匹配 acl tag_found req.payload(0,0),hex -m sub 3C7461673E
与字符串匹配一样,正则表达式匹配也适用于按字面传递的字符串,但反斜杠("\")除外,它使得可以转义某些字符,如空格。如果在第一个正则表达式之前传递了“-i”标志,则匹配将忽略大小写。为了匹配字符串“-i”,要么将其放在第二个位置,要么在第一个正则表达式之前传递“--”标志。当然,匹配字符串“--”也适用相同的原则。
可以将一些提取的样本与一个可能无法安全地表示为字符串的二进制块进行匹配。为此,当匹配方法设置为二进制时,模式必须以偶数个十六进制数字的形式传递。每两个数字的序列将代表一个字节。十六进制数字可以使用大写或小写。
# 在输入流中匹配 "Hello\n" (\x48 \x65 \x6c \x6c \x6f \x0a) acl hello payload(0,6) -m bin 48656c6c6f0a
IPv4 地址值可以指定为普通地址或附加网络掩码的地址,在这种情况下,只要 IPv4 地址在网络内就匹配。普通地址也可以替换为可解析的主机名,但通常不鼓励这种做法,因为它会使配置更难阅读和调试。如果使用主机名,您至少应确保它们存在于 /etc/hosts 中,这样配置就不会依赖于解析配置时任何随机的 DNS 匹配。点分十进制 IPv4 表示法支持常规形式以及省略全 0 八位字节的缩写形式: +------------------+------------------+------------------+ | 示例 1 | 示例 2 | 示例 3 | +------------------+------------------+------------------+ | 192.168.0.1 | 10.0.0.12 | 127.0.0.1 | | 192.168.1 | 10.12 | 127.1 | | 192.168.0.1/22 | 10.0.0.12/8 | 127.0.0.1/8 | | 192.168.1/22 | 10.12/8 | 127.1/8 | +------------------+------------------+------------------+ 注意,这与 RFC 4632 CIDR 地址表示法不同,在后者中 192.168.42/24 等同于 192.168.42.0/24。IPv6 可以以其通常的形式输入,带或不带网络掩码。IPv6 网络掩码只接受位数。为了避免任何因随机解析的 IP 地址而引起的麻烦风险,IPv6 模式中绝不允许使用主机名。HAProxy 还能够在以下情况下将 IPv4 地址与 IPv6 地址进行匹配: - 测试地址是 IPv4,模式地址是 IPv4,匹配在 IPv4 中应用,使用提供的掩码(如果有)。 - 测试地址是 IPv6,模式地址是 IPv6,匹配在 IPv6 中应用,使用提供的掩码(如果有)。 - 测试地址是 IPv6,模式地址是 IPv4,如果 IPv6 地址与 2002:IPV4::, ::IPV4 或 ::ffff:IPV4 匹配,则匹配在 IPv4 中应用,使用模式的掩码,否则失败。 - 测试地址是 IPv4,模式地址是 IPv6,首先将 IPv4 地址通过在其前面加上 ::ffff: 转换为 IPv6,然后在 IPv6 中应用匹配,使用提供的 IPv6 掩码。
某些操作仅在条件有效时执行。条件是 ACL 与运算符的组合。支持 3 种运算符: - AND(隐式) - OR(使用“or”关键字或“||”运算符显式表示) - 使用感叹号(“!”)进行否定 条件以析取范式形成: [!]acl1 [!]acl2 ... [!]acln { or [!]acl1 [!]acl2 ... [!]acln } ... 此类条件通常用在 "if" 或 "unless" 语句之后,指示条件何时触发操作。例如,要阻止对 "*" URL 的除 "OPTIONS" 以外的方法的 HTTP 请求,以及没有 content-length 的 POST 请求,以及 content-length 大于 0 的 GET 或 HEAD 请求,最后是除 GET/HEAD/POST/OPTIONS 之外的每个请求! acl missing_cl hdr_cnt(Content-length) eq 0 http-request deny if HTTP_URL_STAR !METH_OPTIONS || METH_POST missing_cl http-request deny if METH_GET HTTP_CONTENT http-request deny unless METH_GET or METH_POST or METH_OPTIONS 为 "www" 站点上的静态内容请求以及 "img"、"video"、"download" 和 "ftp" 主机上的每个请求选择不同的后端: acl url_static path_beg /static /images /img /css acl url_static path_end .gif .png .jpg .css .js acl host_www hdr_beg(host) -i www acl host_static hdr_beg(host) -i img. video. download. ftp. # 现在为所有仅静态的主机使用后端 "static",以及 # 主机 "www" 的静态 url。其余的则使用后端 "www"。 use_backend static if host_static or host_www url_static use_backend www if host_www 也可以使用“匿名 ACL”来形成规则。这些是未命名的 ACL 表达式,它们是即时构建的,无需声明。它们必须用大括号括起来,每个大括号前后都有一个空格(因为大括号必须被视为空格分隔的独立单词)。示例: 以下规则: acl missing_cl hdr_cnt(Content-length) eq 0 http-request deny if METH_POST missing_cl 也可以这样写: http-request deny if METH_POST { hdr_cnt(Content-length) eq 0 } 通常不建议使用这种结构,因为以这种方式编写配置时更容易出错。然而,对于仅匹配一个源 IP 地址的非常简单的规则,使用它们可能比声明带有随机名称的 ACL 更有意义。另一个好的用法示例是: 使用命名 ACL: acl site_dead nbsrv(dynamic) lt 2 acl site_dead nbsrv(static) lt 2 monitor fail if site_dead 使用匿名 ACL: monitor fail if { nbsrv(dynamic) lt 2 } || { nbsrv(static) lt 2 } 有关 "http-request deny" 和 "use_backend" 关键字的详细帮助,请参见 第 4.2 节。
历史上,样本获取方法仅用于检索数据以使用 ACL 与模式进行匹配。随着粘性表(stick-tables)的出现,创建了一类新的样本获取方法,它们通常与其 ACL 对应部分共享相同的语法。这些样本获取方法也称为“获取”(fetches)。到目前为止,ACL 和获取已经趋于一致。所有 ACL 获取方法都已作为获取方法提供,并且 ACL 也可以使用任何样本获取方法。本节详细介绍所有可用的样本获取方法及其输出类型。一些样本获取方法具有已弃用的别名,用于保持与现有配置的兼容性。它们会被明确标记为已弃用,不应在新设置中使用。当可用时,ACL 的派生形式也会被指出,并附带它们各自的匹配方法。这些派生形式都有一个明确定义的默认模式匹配方法,因此永远不需要(尽管允许)传递 "-m" 选项来指示如何使用 ACL 匹配样本。如上文样本类型与匹配兼容性矩阵所示,当在 ACL 中使用通用样本获取方法时,除非样本类型是布尔值、整数、IPv4 或 IPv6 之一,否则 "-m" 选项是强制性的。当同一个关键字作为 ACL 关键字和标准获取方法存在时,ACL 引擎默认会自动选择仅限 ACL 的那个。其中一些关键字支持一个或多个强制性参数,以及一个或多个可选参数。这些参数是强类型的,在解析配置时会进行检查,因此不存在使用不正确参数(例如:未解析的后端名称)运行的风险。获取函数的参数在括号之间传递,并用逗号分隔。当一个参数是可选的,它将在下面用方括号('[ ]')表示。当所有参数都是可选的时,可以省略括号。因此,标准样本获取方法的语法是以下之一: - name - name(arg1) - name(arg1,arg2)
样本获取方法可以与应用于所获取样本的转换(也称为“转换器”)相结合。这些组合形成了所谓的“样本表达式”,其结果是一个“样本”。最初,这只被“stick on”和“stick store-request”指令支持,但现在已经扩展到所有可以使用样本的地方(ACL、log-format、unique-id-format、add-header 等)。这些转换在样本获取方法之后以一系列特定关键字的形式列出。这些关键字也可以紧跟在获取关键字的参数之后,用逗号分隔。这些关键字也可以支持一些参数(例如:网络掩码),这些参数必须在括号中传递。一类特定的转换器是位运算和算术运算符,它们支持对整数执行基本操作。支持一些位运算(and、or、xor、cpl)和一些算术运算(add、sub、mul、div、mod、neg)。还提供了一些比较器(odd、even、not、bool),它们使得可以在不必编写 ACL 的情况下报告匹配。当前可用的转换关键字列表包括
将 <value> 添加到类型为有符号整数的输入值中,并以有符号整数的形式返回结果。<value> 可以是数值或变量名。变量名以其作用域的指示开头。允许的作用域有: "sess":变量在整个会话中共享 "txn":变量在事务(请求和响应)中共享 "req":变量仅在请求处理期间共享 "res":变量仅在响应处理期间共享 该前缀后跟一个名称。分隔符是'.'。名称只能包含字符 'a-z'、'A-Z'、'0-9' 和 '_'。
在 <value> 和类型为有符号整数的输入值之间执行按位“与”操作,并以有符号整数的形式返回结果。<value> 可以是数值或变量名。变量名以其作用域的指示开头。允许的作用域有: "sess":变量在整个会话中共享 "txn":变量在事务(请求和响应)中共享 "req":变量仅在请求处理期间共享 "res":变量仅在响应处理期间共享 该前缀后跟一个名称。分隔符是'.'。名称只能包含字符 'a-z'、'A-Z'、'0-9' 和 '_'。
将二进制输入样本转换为 base64 字符串。它用于以可靠传输的方式记录或传输二进制内容(例如:可以将 SSL ID 复制到标头中)。
如果类型为有符号整数的输入值为非空,则返回布尔值 TRUE,否则返回 FALSE。与 and() 结合使用,可用于报告输入值的位测试的真/假(例如:验证某个标志是否存在)。
从输入二进制样本中提取一些字节。结果是一个二进制样本,从原始样本的偏移量(以字节为单位)开始,并可选地在给定长度处截断。
获取类型为有符号整数的输入值,应用取反(翻转所有位)并以有符号整数的形式返回结果。
使用 CRC32 哈希函数将二进制输入样本哈希成一个无符号 32 位量。可选地,如果可选的 <avalanche> 参数等于 1,则可以对输出应用一个完整的雪崩哈希函数。此转换器使用与各种基于哈希的负载均衡算法相同的函数,因此它将提供完全相同的结果。它提供与希望在某些输入键上计算 CRC32 的其他软件的兼容性,因此它遵循在以太网、Gzip、PNG 等中最常见的实现。它比其他算法慢,但可能提供更好或至少更难预测的分布。它不能用于安全目的,因为 32 位哈希很容易被破解。另请参阅 "djb2"、"sdbm"、"wt6" 和 "hash-type" 指令。
要求 DeviceAtlas 转换器识别输入的 User Agent 字符串,并发出一个由参数中枚举的属性连接而成的字符串,由全局关键字“deviceatlas-property-separator”定义的分隔符或默认的管道符('|')分隔。haproxy 配置语言强制限制为 5 个不同的属性。
frontend www bind *:8881 default_backend servers http-request set-header X-DeviceAtlas-Data %[req.fhdr(User-Agent),da-csv(primaryHardwareType,osName,osVersion,browserName,browserVersion)]
此转换器用作调试工具。它在屏幕上转储输入样本的内容和类型。样本在其输出上按原样返回。此转换器仅在 haproxy 启用调试构建时存在。
将类型为有符号整数的输入值除以 <value>,并以有符号整数的形式返回结果。如果 <value> 为空,则返回最大的无符号整数(通常为 2^63-1)。<value> 可以是数值或变量名。变量名以其作用域的指示开头。允许的作用域有: "sess":变量在整个会话中共享 "txn":变量在事务(请求和响应)中共享 "req":变量仅在请求处理期间共享 "res":变量仅在响应处理期间共享 该前缀后跟一个名称。分隔符是'.'。名称只能包含字符 'a-z'、'A-Z'、'0-9' 和 '_'。
使用 DJB2 哈希函数将二进制输入样本哈希成一个无符号 32 位量。可选地,如果可选的 <avalanche> 参数等于 1,则可以对输出应用一个完整的雪崩哈希函数。此转换器使用与各种基于哈希的负载均衡算法相同的函数,因此它将提供完全相同的结果。它主要用于调试,但可以用作粘性表条目以收集粗略的统计信息。它不能用于安全目的,因为 32 位哈希很容易被破解。另请参阅 "crc32"、"sdbm"、"wt6" 和 "hash-type" 指令。
如果类型为有符号整数的输入值为偶数,则返回布尔值 TRUE,否则返回 FALSE。它在功能上等同于 "not,and(1),bool"。
根据给定的分隔符从输入字符串中提取给定索引处的子字符串。索引从 1 开始,分隔符是格式化为字符列表的字符串。
将二进制输入样本转换为十六进制字符串,每个输入字节包含两个十六进制数字。它用于以可靠传输的方式记录或传输某些二进制输入数据的十六进制转储(例如:可以将 SSL ID 复制到标头中)。
将一个应包含自纪元以来日期的整数转换为表示该日期的字符串,格式适用于 HTTP 标头字段。如果指定了偏移值,则它是在转换操作之前添加到日期的秒数。这在发出 Date 标头字段、响应中的 Expires 值(当与正偏移结合时)或 Last-Modified 值(当偏移为负时)时特别有用。
使用输入样本的字符串表示形式在指定的表中执行查找。如果在表中找不到键,则返回布尔值 false。否则返回布尔值 true。这可用于验证某个键是否存在于跟踪某些元素的表中(例如:某个源 IP 地址或 Authorization 标头是否已出现过)。
将掩码应用于 IPv4 地址,并使用结果进行查找和存储。这可用于使某个掩码内的所有主机共享相同的表条目,从而使用相同的服务器。掩码可以以点分形式(例如:255.255.255.0)或 CIDR 形式(例如:24)传递。
对输入字符串进行转义,并生成一个可作为 JSON 字符串使用的 ASCII 输出字符串。转换器尝试根据 <input-code> 参数解码输入字符串。它可以是 "ascii"、"utf8"、"utf8s"、"utf8p" 或 "utf8ps"。"ascii" 解码器从不失败。"utf8" 解码器检测 3 种类型的错误: - 错误的 UTF-8 序列(单独的连续字节、错误的连续字节数...) - 无效范围(解码后的值在 UTF-8 禁止的范围内), - 编码过长(值用比必要更多的字节编码)。当 UTF-8 字符大于 0xffff 时,UTF-8 JSON 编码可能会产生“值过长”的错误,因为 JSON 字符串转义规范仅授权 4 个十六进制数字用于值编码。UTF-8 解码器有 4 种变体,由两个后缀字母的组合指定:"p" 表示“permissive”(宽容),"s" 表示“silently ignore”(静默忽略)。解码器的行为是: - "ascii":从不失败; - "utf8":在任何检测到的错误上失败; - "utf8s":从不失败,但删除与错误对应的字符; - "utf8p":接受并修复过长错误,但在任何其他错误上失败; - "utf8ps":从不失败,接受并修复过长错误,但删除与其余错误对应的字符。此转换器对于构建正确转义的 JSON 特别有用,用于记录到消费 JSON 格式流量日志的服务器。
capture request header user-agent len 150 capture request header Host len 15 log-format {"ip":"%[src]","user-agent":"%[capture.req.hdr(1),json("utf8s")]"}
来自客户端 127.0.0.1 的输入请求: GET / HTTP/1.0 User-Agent: Very "Ugly" UA 1/2 输出日志: {"ip":"127.0.0.1","user-agent":"Very \"Ugly\" UA 1\/2"}从 "accept-language" 标头中使用 "req.fhdr" 提取的列表中返回具有最高 q-factor 的值。没有 q-factor 的值其 q-factor 为 1。q-factor 为 0 的值被丢弃。只有属于分号分隔的 <values> 列表中的值才会被考虑。<value> 参数的语法是 "lang[;lang[;lang[;...]]]"。如果没有值与给定列表匹配,并且提供了默认值,则返回默认值。请注意,语言名称在破折号('-')后可能有变体。如果此变体存在于列表中,它将被匹配,但如果不存在,则只检查基础语言。匹配是区分大小写的,输出字符串始终是参数中提供的字符串之一。参数的顺序没有意义,只有请求中值的顺序有意义,因为在共享相同 q-factor 的多个值中,第一个值被使用。
# 此配置根据请求切换到匹配 # 给定语言的后端: acl es req.fhdr(accept-language),language(es;fr;en) -m str es acl fr req.fhdr(accept-language),language(es;fr;en) -m str fr acl en req.fhdr(accept-language),language(es;fr;en) -m str en use_backend spanish if es use_backend french if fr use_backend english if en default_backend choose_your_language
将字符串样本转换为小写。这只能放在字符串样本获取函数之后或返回字符串类型的转换关键字之后。结果类型为字符串。
将一个应包含自纪元以来日期的整数转换为表示该日期的本地时间的字符串,使用 strftime(3) 定义的 <format> 字符串。目的是允许在日志中使用任何日期格式。可以对输入日期应用一个可选的 <offset>(正或负,以秒为单位)。有关操作系统支持的格式,请参阅 strftime() 手册页。另请参阅 utime 转换器。
# 输出两个字段,一个带有本地时间,另一个带有 ip:port # 例如:20140710162350 127.0.0.1:57325 log-format %[date,ltime(%Y%m%d%H%M%S)]\ %ci:%cp
map_<match_type>(<map_file>[,<default_value>]) map_<match_type>_<output_type>(<map_file>[,<default_value>]) 使用 <match_type> 匹配方法从 <map_file> 中搜索输入值,并返回转换为 <output_type> 类型的关联值。如果在 <map_file> 中找不到输入值,转换器返回 <default_value>。如果未设置 <default_value>,转换器将失败,并表现为好像无法获取任何输入值。如果未设置 <match_type>,则默认为 "str"。同样,如果未设置 <output_type>,则默认为 "str"。为方便起见,“map” 关键字是 “map_str” 的别名,用于将一个字符串映射到另一个字符串。重要的是要避免键之间的重叠:IP 地址和字符串存储在树中,因此将使用最精确匹配的第一个。其他键存储在列表中,因此将使用第一个匹配的项。下表包含按输入类型、匹配类型和输出类型排序的所有可用 map 函数的列表。
| 输入类型 | 匹配方法 | 输出类型 str | 输出类型 int | 输出类型 ip |
|---|---|---|---|---|
| str | str | map_str | map_str_int | map_str_ip |
| str | beg | map_beg | map_beg_int | map_end_ip |
| str | sub | map_sub | map_sub_int | map_sub_ip |
| str | dir | map_dir | map_dir_int | map_dir_ip |
| str | dom | map_dom | map_dom_int | map_dom_ip |
| str | end | map_end | map_end_int | map_end_ip |
| str | reg | map_reg | map_reg_int | map_reg_ip |
| int | int | map_int | map_int_int | map_int_ip |
| ip | ip | map_ip | map_ip_int | map_ip_ip |
文件每行包含一个键 + 值。以 '#' 开头的行和空行都会被忽略。前导的制表符和空格会被去除。键是第一个“单词”(一系列非空格/制表符字符),值是这串空格/制表符之后直到行尾的所有内容,不包括尾部的空格/制表符。
# 这是一条注释,会被忽略 2.22.246.0/23 United Kingdom \n <-><-----------><--><------------><----> | | | | `- 尾部空格被忽略 | | | `---------- 值 | | `-------------------- 中间空格被忽略 | `---------------------------- 键 `------------------------------------ 前导空格被忽略
将类型为有符号整数的输入值除以 <value>,并以有符号整数的形式返回余数。如果 <value> 为空,则返回零。<value> 可以是数值或变量名。变量名以其作用域的指示开头。允许的作用域有: "sess":变量在整个会话中共享 "txn":变量在事务(请求和响应)中共享 "req":变量仅在请求处理期间共享 "res":变量仅在响应处理期间共享 该前缀后跟一个名称。分隔符是'.'。名称只能包含字符 'a-z'、'A-Z'、'0-9' 和 '_'。
将类型为有符号整数的输入值乘以 <value>,并以有符号整数的形式返回乘积。如果发生溢出,则返回该符号可能的最大值,以使操作不会回绕。<value> 可以是数值或变量名。变量名以其作用域的指示开头。允许的作用域有: "sess":变量在整个会话中共享 "txn":变量在事务(请求和响应)中共享 "req":变量仅在请求处理期间共享 "res":变量仅在响应处理期间共享 该前缀后跟一个名称。分隔符是'.'。名称只能包含字符 'a-z'、'A-Z'、'0-9' 和 '_'。
获取类型为有符号整数的输入值,计算其相反值,并以有符号整数的形式返回余数。0 是单位元。此运算符用于反向减法:为了从一个常量中减去输入值,只需执行 "neg,add(value)"。
如果类型为有符号整数的输入值为非空,则返回布尔值 FALSE,否则返回 TRUE。与 and() 结合使用,可用于报告输入值的位测试的真/假(例如:验证某个标志是否不存在)。
如果类型为有符号整数的输入值为奇数,则返回布尔值 TRUE,否则返回 FALSE。它在功能上等同于 "and(1),bool"。
在 <value> 和类型为有符号整数的输入值之间执行按位“或”操作,并以有符号整数的形式返回结果。<value> 可以是数值或变量名。变量名以其作用域的指示开头。允许的作用域有: "sess":变量在整个会话中共享 "txn":变量在事务(请求和响应)中共享 "req":变量仅在请求处理期间共享 "res":变量仅在响应处理期间共享 该前缀后跟一个名称。分隔符是'.'。名称只能包含字符 'a-z'、'A-Z'、'0-9' 和 '_'。
对输入字符串应用基于正则表达式的替换。它执行与著名的 "sed" 工具的 "s/<regex>/<subst>/" 相同的操作。默认情况下,它将替换输入字符串中与正则表达式 <regex> 匹配的最大部分的第一次出现,替换为替换字符串 <subst>。通过在第三个参数 <flags> 中添加标志 "g",可以替换所有出现。通过在 <flags> 中添加标志 "i",也可以使正则表达式不区分大小写。由于 <flags> 是一个字符串,它由所有所需标志的连接组成。因此,如果同时需要 "i" 和 "g",使用 "gi" 或 "ig" 将具有相同的效果。需要注意的是,由于当前配置解析器的限制,某些字符如右括号、右方括号或逗号不能在参数中使用。此转换器的第一个用途是替换某些字符或字符序列。
# 在标头 "x-path" 中去重 "/"。 # 输入:x-path: /////a///b/c/xzxyz/ # 输出:x-path: /a/b/c/xzxyz/ http-request set-header x-path %[hdr(x-path),regsub(/+,/,g)]
捕获请求槽 <id> 中的字符串条目,并按原样返回该条目。如果槽不存在,捕获将静默失败。
捕获响应槽 <id> 中的字符串条目,并按原样返回该条目。如果槽不存在,捕获将静默失败。
使用 SDBM 哈希函数将二进制输入样本哈希成一个无符号 32 位量。可选地,如果可选的 <avalanche> 参数等于 1,则可以对输出应用一个完整的雪崩哈希函数。此转换器使用与各种基于哈希的负载均衡算法相同的函数,因此它将提供完全相同的结果。它主要用于调试,但可以用作粘性表条目以收集粗略的统计信息。它不能用于安全目的,因为 32 位哈希很容易被破解。另请参阅 "crc32"、"djb2"、"wt6" 和 "hash-type" 指令。 set-var(<var name>) 使用输入内容设置一个变量,并按原样在输出上返回内容。该变量保留值和相关的输入类型。变量名以其作用域的指示开头。允许的作用域有: "sess":变量在整个会话中共享 "txn":变量在事务(请求和响应)中共享, "req":变量仅在请求处理期间共享, "res":变量仅在响应处理期间共享。 该前缀后跟一个名称。分隔符是'.'。名称只能包含字符 'a-z'、'A-Z'、'0-9' 和 '_'。
从类型为有符号整数的输入值中减去 <value>,并以有符号整数的形式返回结果。注意:为了从一个常量中减去输入值,只需执行 "neg,add(value)"。<value> 可以是数值或变量名。变量名以其作用域的指示开头。允许的作用域有: "sess":变量在整个会话中共享 "txn":变量在事务(请求和响应)中共享, "req":变量仅在请求处理期间共享, "res":变量仅在响应处理期间共享。 该前缀后跟一个名称。分隔符是'.'。名称只能包含字符 'a-z'、'A-Z'、'0-9' 和 '_'。
使用输入样本的字符串表示形式在指定的表中执行查找。如果在表中找不到键,则返回整数值零。否则,转换器返回与指定表中输入样本关联的平均客户端到服务器字节速率,以字节量/周期(在表中配置)衡量。另请参阅 sc_bytes_in_rate 样本获取关键字。
使用输入样本的字符串表示形式在指定的表中执行查找。如果在表中找不到键,则返回整数值零。否则,转换器返回与指定表中输入样本关联的平均服务器到客户端字节速率,以字节量/周期(在表中配置)衡量。另请参阅 sc_bytes_out_rate 样本获取关键字。
使用输入样本的字符串表示形式在指定的表中执行查找。如果在表中找不到键,则返回整数值零。否则,转换器返回与指定表中输入样本关联的累积传入连接数。另请参阅 sc_conn_cnt 样本获取关键字。
使用输入样本的字符串表示形式在指定的表中执行查找。如果在表中找不到键,则返回整数值零。否则,转换器返回与指定表中输入样本关联的当前并发跟踪连接数。另请参阅 sc_conn_cur 样本获取关键字。
使用输入样本的字符串表示形式在指定的表中执行查找。如果在表中找不到键,则返回整数值零。否则,转换器返回与指定表中输入样本关联的平均传入连接速率。另请参阅 sc_conn_rate 样本获取关键字。
使用输入样本的字符串表示形式在指定的表中执行查找。如果在表中找不到键,则返回布尔值零。否则,转换器返回与指定表中输入样本关联的第一个通用目的标签的当前值。另请参阅 sc_get_gpt0 样本获取关键字。
使用输入样本的字符串表示形式在指定的表中执行查找。如果在表中找不到键,则返回整数值零。否则,转换器返回与指定表中输入样本关联的第一个通用目的计数器的当前值。另请参阅 sc_get_gpc0 样本获取关键字。
使用输入样本的字符串表示形式在指定的表中执行查找。如果在表中找不到键,则返回整数值零。否则,转换器返回在表中配置的周期内 gpc0 计数器递增的频率,与指定表中输入样本相关联。另请参阅 sc_get_gpc0_rate 样本获取关键字。
使用输入样本的字符串表示形式在指定的表中执行查找。如果在表中找不到键,则返回整数值零。否则,转换器返回与指定表中输入样本关联的累积 HTTP 错误数。另请参阅 sc_http_err_cnt 样本获取关键字。
使用输入样本的字符串表示形式在指定表中执行查找。如果在表中找不到键,则返回整数值零。否则,返回与指定表中的输入样本关联的 HTTP 错误的平均速率,以表中配置的时间段内的错误数量来衡量。另请参阅 sc_http_err_rate 样本提取关键字。
使用输入样本的字符串表示形式在指定表中执行查找。如果在表中找不到键,则返回整数值零。否则,转换器返回与指定表中的输入样本关联的 HTTP 请求的累积数量。另请参阅 sc_http_req_cnt 样本提取关键字。
使用输入样本的字符串表示形式在指定表中执行查找。如果在表中找不到键,则返回整数值零。否则,返回与指定表中的输入样本关联的 HTTP 请求的平均速率,以表中配置的时间段内的请求数量来衡量。另请参阅 sc_http_req_rate 样本提取关键字。
使用输入样本的字符串表示形式在指定表中执行查找。如果在表中找不到键,则返回整数值零。否则,转换器返回与指定表中的输入样本关联的从客户端到服务器的累积数据量,以千字节为单位。该测试目前在 32 位整数上执行,这将值限制为 4 TB。另请参阅 sc_kbytes_in 样本提取关键字。
使用输入样本的字符串表示形式在指定表中执行查找。如果在表中找不到键,则返回整数值零。否则,转换器返回与指定表中的输入样本关联的从服务器到客户端的累积数据量,以千字节为单位。该测试目前在 32 位整数上执行,这将值限制为 4 TB。另请参阅 sc_kbytes_out 样本提取关键字。
使用输入样本的字符串表示形式在指定表中执行查找。如果在表中找不到键,则返回整数值零。否则,转换器返回与指定表中的输入样本关联的服务器 ID。当与服务器的连接成功时,服务器 ID 通过“stick”规则与样本关联。服务器 ID 为零表示没有服务器与此键关联。
使用输入样本的字符串表示形式在指定表中执行查找。如果在表中找不到键,则返回整数值零。否则,转换器返回与指定表中的输入样本关联的传入会话的累积数量。请注意,此处的会话指的是被“tcp-request connection”规则集接受的传入连接。另请参阅 sc_sess_cnt 样本提取关键字。
使用输入样本的字符串表示形式在指定表中执行查找。如果在表中找不到键,则返回整数值零。否则,转换器返回与指定表中的输入样本关联的平均传入会话速率。请注意,此处的会话指的是被“tcp-request connection”规则集接受的传入连接。另请参阅 sc_sess_rate 样本提取关键字。
使用输入样本的字符串表示形式在指定表中执行查找。如果在表中找不到键,则返回整数值零。否则,转换器返回在指定表中跟踪与输入样本相同键的当前并发连接数。它与 table_conn_cur 的不同之处在于,它不依赖任何存储的信息,而是依赖于表的引用计数(即在 CLI 上通过“show table”返回的“use”值)。这有时可能更适合于第 7 层跟踪。例如,它可以用来告诉服务器来自给定地址的并发连接数。另请参阅 sc_trackers 样本提取关键字。
将字符串样本转换为大写。这只能放在字符串样本提取函数之后或返回字符串类型的转换关键字之后。结果为字符串类型。
接收一个 URL 编码的字符串作为输入,并返回解码后的版本作为输出。输入和输出都是字符串类型。
将一个假定包含自纪元以来日期的整数,使用 strftime(3) 定义的 <format> 字符串格式,转换为表示该日期的 UTC 时间字符串。目的是允许在日志中使用任何日期格式。可以对输入日期应用一个可选的 <offset>(以秒为单位,可正可负)。有关您的操作系统支持的格式,请参阅 strftime() 手册页。另请参阅 ltime 转换器。
# 发出两个部分,一个带有 UTC 时间,另一个带有 ip:port # 例如:20140710162350 127.0.0.1:57325 log-format %[date,utime(%Y%m%d%H%M%S)]\ %ci:%cp
根据给定的分隔符从输入字符串中提取第 n 个单词。索引从 1 开始,分隔符是一个字符串格式的字符列表。
使用 WT6 哈希函数将二进制输入样本哈希为一个无符号 32 位整数。可选地,如果可选的 <avalanche> 参数等于 1,则可以对输出应用完全雪崩哈希函数。此转换器使用的函数与各种基于哈希的负载均衡算法所使用的函数相同,因此它将提供完全相同的结果。它主要用于调试,但可以用作粘性表条目来收集粗略的统计信息。由于 32 位哈希很容易被破解,因此不得用于安全目的。另请参阅“crc32”、“djb2”、“sdbm”以及“hash-type”指令。
在 <value> 和有符号整数类型的输入值之间执行按位“XOR”(异或)操作,并返回结果为有符号整数。<value> 可以是数值或变量名。变量名以其作用域的指示符开头。允许的作用域有:“sess”:变量在整个会话中共享;“txn”:变量在事务(请求和响应)中共享;“req”:变量仅在请求处理期间共享;“res”:变量仅在响应处理期间共享。此前缀后跟一个名称。分隔符是“.”。名称只能包含字符“a-z”、“A-Z”、“0-9”和“_”。
第一组样本提取方法适用于甚至不涉及任何客户端信息的内部信息。这些方法有时与“monitor-fail”指令一起使用,向外部监视器报告内部状态。本节描述的样本提取方法可在任何地方使用。
始终返回布尔值“false”。在调整配置时,它可以与 ACL 一起用作另一个 ACL 的临时替代品。
始终返回布尔值“true”。在调整配置时,它可以与 ACL 一起用作另一个 ACL 的临时替代品。
返回指定后端的排队连接总数除以活动服务器的数量。如果未指定后端,则使用当前后端。这与“queue”非常相似,但考虑了服务器场的规模,以便更准确地衡量新连接可能需要多长时间才能被处理。主要用途是与 ACL 结合使用,在确定新用户将获得降级服务时向他们返回一个“抱歉”页面,或者在请求头中传递给后端服务器,以便它们决定以降级模式工作或禁用某些功能以加快处理速度。请注意,如果没有任何活动服务器,排队连接数的两倍将被视为测量值。这是一个公平的估计,因为我们预计一台服务器很快就会恢复,但我们仍然倾向于将新流量发送到状态更好的另一个后端。另请参阅“queue”、“be_conn”和“be_sess_rate”样本提取。
适用于后端上当前已建立的连接数,可能包括正在评估的连接。如果未指定后端名称,则使用当前后端。但也可以检查另一个后端。当标称服务器场已满时,它可用于使用特定的服务器场。另请参阅“fe_conn”、“queue”和“be_sess_rate”标准。
返回一个整数值,对应于后端上的会话创建速率,单位为每秒新会话数。这与 ACL 一起使用,以便在昂贵或脆弱的后端达到过高的会话速率时切换到备用后端,或限制服务滥用(例如防止在线词典被爬取)。将此元素添加到日志中(使用 log-format 指令)也很有用。
# 如果字典请求过于频繁,则重定向到错误页面 backend dynamic mode http acl being_scanned be_sess_rate gt 100 redirect location /denied.html if being_scanned
返回一个二进制链。输入是字符串的十六进制表示。
返回一个布尔值。<bool> 可以是 'true'、'false'、'1' 或 '0'。'false' 和 '0' 相同。'true' 和 '1' 相同。
返回一个整数值,对应于后端中仍然可用的连接槽位数,通过将所有服务器上的最大连接数和最大队列大小相加得出。这可能只与 ACL 一起使用。这里的基本思想是能够测量仍然可用的连接“槽位”(连接 + 队列)数量,以便任何超出此范围的(预期用途;请参阅“use_backend”关键字)都可以重定向到不同的后端。'connslots' = 可用服务器连接槽位数 + 可用服务器队列槽位数。请注意,虽然可以使用“fe_conn”,但当流量流向单个 IP,然后分流到多个后端(可能使用 ACL 进行基于名称的负载均衡)并且您希望能够区分不同后端及其可用的“connslots”时,“connslots”特别有用。此外,尽管“nbsrv”只测量实际 *宕机* 的服务器,但此提取更为精细,还会查看可用连接槽位的数量。另请参阅“queue”和“avg_queue”。其他注意事项和说明:目前,代码不处理动态连接。此外,如果任何服务器的 maxconn 或 maxqueue 为 0,那么此提取显然没有意义,在这种情况下返回的值将为 -1。
以纪元(自 1970 年 1 月 1 日以来的秒数)形式返回当前日期。如果指定了偏移值,则它是在返回值之前添加到当前日期的秒数。这对于计算相对日期特别有用,因为允许正负偏移。与 http_date 转换器结合使用很有用。
# 在每个响应中设置一个过期头为现在+1小时 http-response set-header Expires %[date(3600),http_date]
返回一个包含环境变量 <name> 值的字符串。提醒一下,环境变量是每个进程的,并在进程启动时采样。这对于将一些信息传递给下一跳服务器,或者与 ACL 结合使用以在进程以特定方式启动时采取特定操作很有用。
# 将带有本地主机名的 Via 头传递给下一跳 http-request add-header Via 1.1\ %[env(HOSTNAME)] # 当设置了 STOP 环境变量时,拒绝无 cookie 的请求 http-request deny if !{ cook(SESSIONID) -m found } { env(STOP) -m found }
返回前端上当前已建立的连接数,可能包括正在评估的连接。如果未指定前端名称,则使用当前前端。但也可以检查另一个前端。它可用于在硬阻塞之前返回一个“抱歉”页面,或者在服务器场被认为已满时使用特定的后端来处理新请求。这主要与 ACL 一起使用,但也可以用于在 HTTP 头中将一些统计信息传递给服务器。另请参阅“dst_conn”、“be_conn”、“fe_sess_rate”提取。
返回一个整数值,对应于每秒发送到前端的 HTTP 请求数。在启用客户端保持连接(keep-alive)的情况下,此数字可能与“fe_sess_rate”不同。
返回一个整数值,对应于前端上的会话创建速率,单位为每秒新会话数。这与 ACL 一起使用,将传入会话速率限制在可接受的范围内,以便尽早防止服务滥用,例如,当与其他第 4 层 ACL 结合使用时,以强制客户端等待一段时间,直到速率下降到限制以下。使用 log-format 指令将此元素添加到日志中也很有用。另请参阅前端中使用的“rate-limit sessions”指令。
# 此前端将传入邮件限制为 10/s,最多 100 个 # 并发连接。我们接受低于 10/s 的任何连接,并 # 强制超出的客户端等待 100 毫秒。由于客户端限制为 # 最多 100 个,因此每秒传入的邮件不能超过 10 封。 frontend mail bind :25 mode tcp maxconn 100 acl too_fast fe_sess_rate ge 10 tcp-request inspect-delay 100ms tcp-request content accept if ! too_fast tcp-request content accept if WAIT_END
返回一个有符号整数。
返回一个 IPv4 地址。
返回一个 IPv6 地址。
返回一个方法。
返回一个整数值,对应于已启动的进程数(它等于全局“nbproc”设置)。这对于日志记录和调试目的很有用。返回一个整数值,对应于当前后端或指定后端的可用服务器数量。这主要与 ACL 一起使用,但在添加到日志中时也很有用。这通常用于在服务器数量过低而无法处理某些负载时切换到备用后端。当与“monitor fail”结合使用时,报告故障很有用。
返回一个整数值,对应于调用该函数的进程的位置,介于 1 和 global.nbproc 之间。这对于日志记录和调试目的很有用。
返回指定后端的排队连接总数,包括服务器队列中的所有连接。如果未指定后端名称,则使用当前后端,但也可以检查另一个后端。这对于 ACL 或将统计信息传递给后端服务器很有用。这可用于在排队超过已知水平时采取行动,这通常表示流量激增或服务器大规模减速。一个可能的操作是拒绝新用户但仍然接受老用户。另请参阅“avg_queue”、“be_conn”和“be_sess_rate”提取。
返回一个在 <range> 个可能值范围内的随机整数值,从零开始。如果未指定范围,则默认为 2^32,即数字介于 0 和 4294967295 之间。例如,传递一些需要用于做出某些路由决策的值可能很有用,或者仅仅用于调试目的。此随机数不得用于安全目的。
返回一个整数值,对应于指定服务器上当前已建立的连接数,可能包括正在评估的连接。如果省略 <backend>,则在当前后端中查找服务器。当一台服务器已满时,它可用于使用特定的服务器场,或通知服务器我们对其活动连接数的看法。另请参阅“fe_conn”、“be_conn”和“queue”提取方法。
当指定服务器为 UP 时返回 true,当其为 DOWN 或处于维护模式时返回 false。如果省略 <backend>,则在当前后端中查找服务器。它主要用于根据通过健康检查报告的外部状态采取行动(例如:地理站点的可用性)。另一种可能的用途更像是一种技巧,即将虚拟服务器用作布尔变量,可以从 CLI 启用或禁用,以便可以实时调整依赖于这些 ACL 的规则。
返回一个整数,对应于指定服务器上的会话创建速率,单位为每秒新会话数。如果省略 <backend>,则在当前后端中查找服务器。这主要与 ACL 一起使用,但与日志一起使用也很有意义。这用于在昂贵或脆弱的后端达到过高的会话速率时切换到备用后端,或限制服务滥用(例如防止潜在请求使服务器过载)。
# 重定向到单独的后端 acl srv1_full srv_sess_rate(be1/srv1) gt 50 acl srv2_full srv_sess_rate(be1/srv2) gt 50 use_backend be2 if srv1_full or srv2_full
如果调用该函数的进程当前正在停止,则返回 TRUE。这对于日志记录,或在优雅关闭时放宽某些检查或帮助关闭某些连接很有用。
返回一个字符串。
返回当前代理的粘性表或指定粘性表中可用条目的总数。另请参阅 table_cnt。
返回当前代理的粘性表或指定粘性表中当前使用的条目总数。有关其他条目计数方法,请参阅 src_conn_cnt 和 table_avl。
返回一个带有存储类型的变量。如果未设置变量,则样本提取失败。变量的名称以其作用域的指示开头。允许的作用域是:“sess”:变量与整个会话共享;“txn”:变量与事务(请求和响应)共享;“req”:变量仅在请求处理期间共享;“res”:变量仅在响应处理期间共享。此前缀后跟一个名称。分隔符是“.”。名称只能包含字符“a-z”、“A-Z”、“0-9”和“_”。
第 4 层通常仅描述传输层,在 haproxy 中最接近连接,此时尚无内容可用。此处描述的提取方法可低至“tcp-request connection”规则集使用,除非它们需要某些未来的信息。这些通常包括 TCP/IP 地址和端口,以及与传入连接相关的粘性表中的元素。为了从粘性计数器中检索值,可以使用预定义的“sc0_”、“sc1_”或“sc2_”前缀将计数器编号显式设置为 0、1 或 2。这三个预定义的前缀只能在 MAX_SESS_STKCTR 值不超过 3 的情况下使用,否则在使用“sc_”前缀时可以将计数器编号指定为第一个整数参数。从“sc_0”到“sc_N”,其中 N 是 (MAX_SESS_STKCTR-1)。可以使用“sc*”形式指定一个可选的表,在这种情况下,将在该备用表中查找当前跟踪的键,而不是当前正在跟踪的表。
返回一个包含当前后端 ID 的整数。它可以在前端的响应中使用,以检查哪个后端处理了请求。
这是客户端侧连接的目标 IPv4 地址,即客户端连接到的地址。在透明模式下运行时可能很有用。它是 IP 类型,适用于 IPv4 和 IPv6 表。在 IPv6 表上,IPv4 地址根据 RFC 4291 映射到其等效的 IPv6 地址。
返回一个整数值,对应于同一套接字上当前建立的连接数,包括正在评估的连接。它通常与 ACL 一起使用,但也可以用于在 HTTP 头中或日志中将信息传递给服务器。它可以用于在硬阻塞之前返回一个“抱歉”页面,或者在套接字被认为饱和时使用特定的后端来处理新请求。这提供了为不同的侦听端口或地址分配不同限制的能力。另请参阅“fe_conn”和“be_conn”提取。
返回一个整数值,对应于客户端侧连接的目标 TCP 端口,即客户端连接到的端口。这可能在透明模式下运行、为某些客户端的整个应用程序会话分配动态端口、将所有用户粘滞到同一台服务器,或使用 HTTP 头将目标端口信息传递给服务器时使用。
返回一个包含当前前端 ID 的整数。它可以在后端使用,以检查它是从哪个前端调用的,或将通过同一前端进入的所有用户粘滞到同一台服务器。
返回当前跟踪的计数器中客户端到服务器的平均字节速率,以表中配置的时间段内的字节量来衡量。另请参阅 src_bytes_in_rate。
返回当前跟踪的计数器中服务器到客户端的平均字节速率,以表中配置的时间段内的字节量来衡量。另请参阅 src_bytes_out_rate。
清除与当前跟踪的计数器关联的第一个通用计数器(General Purpose Counter),并返回其先前的值。在第一次调用之前,存储的值为零,因此第一次调用将始终返回零。这通常用作表达式中的第二个 ACL,以便在第一个 ACL 被验证时标记一个连接。
# 如果连续 5 个请求的速率持续高于每秒 10 个会话,则阻止, # 并在流量减慢时立即重置计数器。 acl abuse sc0_http_req_rate gt 10 acl kill sc0_inc_gpc0 gt 5 acl save sc0_clr_gpc0 ge 0 tcp-request connection accept if !abuse save tcp-request connection reject if abuse kill
返回当前跟踪的计数器中传入连接的累积数量。另请参阅 src_conn_cnt。
返回跟踪相同跟踪计数器的当前并发连接数。此数字在跟踪开始时自动递增,在跟踪停止时自动递减。另请参阅 src_conn_cur。
返回当前跟踪的计数器中的平均连接速率,以表中配置的时间段内的连接数量来衡量。另请参阅 src_conn_rate。
返回与当前跟踪的计数器关联的第一个通用计数器的值。另请参阅 src_get_gpc0 和 sc/sc0/sc1/sc2_inc_gpc0。
返回与当前跟踪的计数器关联的第一个通用标签(General Purpose Tag)的值。另请参阅 src_get_gpt0。
返回与当前跟踪的计数器关联的第一个通用计数器的平均增量速率。它报告在配置的时间段内 gpc0 计数器递增的频率。另请参阅 src_gpc0_rate、sc/sc0/sc1/sc2_get_gpc0 和 sc/sc0/sc1/sc2_inc_gpc0。请注意,必须在粘性表中存储“gpc0_rate”计数器才能返回值,因为“gpc0”仅保存事件计数。
返回当前跟踪的计数器中 HTTP 错误的累积数量。这包括请求错误和 4xx 错误响应。另请参阅 src_http_err_cnt。
返回当前跟踪的计数器中 HTTP 错误的平均速率,以表中配置的时间段内的错误数量来衡量。这包括请求错误和 4xx 错误响应。另请参阅 src_http_err_rate。
返回当前跟踪的计数器中 HTTP 请求的累积数量。这包括每个已启动的请求,无论其有效与否。另请参阅 src_http_req_cnt。
返回当前跟踪的计数器中 HTTP 请求的平均速率,以表中配置的时间段内的请求数量来衡量。这包括每个已启动的请求,无论其有效与否。另请参阅 src_http_req_rate。
递增与当前跟踪的计数器关联的第一个通用计数器,并返回其新值。在第一次调用之前,存储的值为零,因此第一次调用会将其增加到 1 并返回 1。这通常用作表达式中的第二个 ACL,以便在第一个 ACL 被验证时标记一个连接。
acl abuse sc0_http_req_rate gt 10 acl kill sc0_inc_gpc0 gt 0 tcp-request connection reject if abuse kill
返回当前跟踪的计数器中客户端到服务器的总数据量,以千字节为单位。该测试目前在 32 位整数上执行,这将值限制为 4 TB。另请参阅 src_kbytes_in。
返回当前跟踪的计数器中服务器到客户端的总数据量,以千字节为单位。该测试目前在 32 位整数上执行,这将值限制为 4 TB。另请参阅 src_kbytes_out。
返回从当前跟踪的计数器中,被转换为会话的传入连接的累积数量,这意味着它们被“tcp-request connection”规则接受。一个后端可能会计算比连接更多的会话,因为如果通过与客户端的连接执行了 HTTP 保持连接(keep-alive),每个连接可能会导致多个后端会话。另请参阅 src_sess_cnt。
返回当前跟踪的计数器中的平均会话速率,以表中配置的时间段内的会话数量来衡量。会话是通过早期“tcp-request connection”规则的连接。一个后端可能会计算比连接更多的会话,因为如果通过与客户端的连接执行了 HTTP 保持连接(keep-alive),每个连接可能会导致多个后端会话。另请参阅 src_sess_rate。
如果指定的会话计数器当前正被当前会话跟踪,则返回 true。这在决定是否要在传递给服务器的头中设置某些值时很有用。
返回跟踪相同跟踪计数器的当前并发连接数。此数字在跟踪开始时自动递增,在跟踪停止时自动递减。它与 sc0_conn_cur 的不同之处在于,它不依赖于任何存储的信息,而是依赖于表的引用计数(即在 CLI 上通过“show table”返回的“use”值)。这有时可能更适合于第 7 层跟踪。例如,它可以用来告诉服务器来自给定地址的并发连接数。
返回一个包含当前侦听套接字 ID 的整数。在涉及许多“bind”行的前端中,或将通过同一套接字进入的所有用户粘滞到同一台服务器时,这很有用。
这是会话客户端的源 IPv4 地址。它是 IP 类型,适用于 IPv4 和 IPv6 表。在 IPv6 表上,IPv4 地址根据 RFC 4291 映射到其等效的 IPv6 地址。请注意,使用的是 TCP 级别的源地址,而不是代理后面客户端的地址。但是,如果使用了“accept-proxy”绑定指令,对于除“tcp-request connection”(它看到的是真实地址)之外的所有规则集,它都可以是另一个 PROXY 协议兼容组件后面的客户端地址。
# 在请求中添加一个带有源地址国家的 HTTP 头 http-request set-header X-Country %[src,map_ip(geoip.lst)]
返回当前代理的粘性表或指定粘性表中,来自传入连接源地址的平均字节速率,以表中配置的时间段内的字节量来衡量。如果找不到地址,则返回零。另请参阅 sc/sc0/sc1/sc2_bytes_in_rate。
返回当前代理的粘性表或指定粘性表中,发往传入连接源地址的平均字节速率,以表中配置的时间段内的字节量来衡量。如果找不到地址,则返回零。另请参阅 sc/sc0/sc1/sc2_bytes_out_rate。
清除与当前代理的粘性表或指定粘性表中传入连接的源地址关联的第一个通用计数器,并返回其先前的值。如果找不到地址,则会创建一个条目并返回 0。这通常用作表达式中的第二个 ACL,以便在第一个 ACL 被验证时标记一个连接。
# 如果连续 5 个请求的速率持续高于每秒 10 个会话,则阻止, # 并在流量减慢时立即重置计数器。 acl abuse src_http_req_rate gt 10 acl kill src_inc_gpc0 gt 5 acl save src_clr_gpc0 ge 0 tcp-request connection accept if !abuse save tcp-request connection reject if abuse kill
返回当前代理的粘性表或指定粘性表中,从当前传入连接的源地址发起的连接的累积数量。如果找不到地址,则返回零。另请参阅 sc/sc0/sc1/sc2_conn_cnt。
返回当前代理的粘性表或指定粘性表中,从当前传入连接的源地址发起的当前并发连接数。如果找不到地址,则返回零。另请参阅 sc/sc0/sc1/sc2_conn_cur。
返回当前代理的粘性表或指定粘性表中,来自传入连接源地址的平均连接速率,以表中配置的时间段内的连接数量来衡量。如果找不到地址,则返回零。另请参阅 sc/sc0/sc1/sc2_conn_rate。
返回与当前代理的粘性表或指定粘性表中传入连接的源地址关联的第一个通用计数器的值。如果找不到地址,则返回零。另请参阅 sc/sc0/sc1/sc2_get_gpc0 和 src_inc_gpc0。
返回与当前代理的粘性表或指定粘性表中传入连接的源地址关联的第一个通用标签的值。如果找不到地址,则返回零。另请参阅 sc/sc0/sc1/sc2_get_gpt0。
返回与当前代理的粘性表或指定粘性表中传入连接的源地址关联的第一个通用计数器的平均增量速率。它报告在配置的时间段内 gpc0 计数器递增的频率。另请参阅 sc/sc0/sc1/sc2_gpc0_rate、src_get_gpc0 和 sc/sc0/sc1/sc2_inc_gpc0。请注意,必须在粘性表中存储“gpc0_rate”计数器才能返回值,因为“gpc0”仅保存事件计数。
返回当前代理的粘性表或指定粘性表中,来自传入连接源地址的 HTTP 错误的累积数量。这包括请求错误和 4xx 错误响应。另请参阅 sc/sc0/sc1/sc2_http_err_cnt。如果找不到地址,则返回零。
返回当前代理的粘性表或指定粘性表中,来自传入连接源地址的 HTTP 错误的平均速率,以表中配置的时间段内的错误数量来衡量。这包括请求错误和 4xx 错误响应。如果找不到地址,则返回零。另请参阅 sc/sc0/sc1/sc2_http_err_rate。
返回当前代理的粘性表或指定粘性表中,来自传入连接源地址的 HTTP 请求的累积数量。这包括每个已启动的请求,无论其有效与否。如果找不到地址,则返回零。另请参阅 sc/sc0/sc1/sc2_http_req_cnt。
返回当前代理的粘性表或指定粘性表中,来自传入连接源地址的 HTTP 请求的平均速率,以表中配置的时间段内的请求数量来衡量。这包括每个已启动的请求,无论其有效与否。如果找不到地址,则返回零。另请参阅 sc/sc0/sc1/sc2_http_req_rate。
递增与当前代理的粘性表或指定粘性表中传入连接的源地址关联的第一个通用计数器,并返回其新值。如果找不到地址,则会创建一个条目并返回 1。另请参阅 sc0/sc2/sc2_inc_gpc0。这通常用作表达式中的第二个 ACL,以便在第一个 ACL 被验证时标记一个连接。
acl abuse src_http_req_rate gt 10 acl kill src_inc_gpc0 gt 0 tcp-request connection reject if abuse kill
返回当前代理的粘性表或指定粘性表中,从传入连接源地址接收的总数据量,以千字节为单位。如果找不到地址,则返回零。该测试目前在 32 位整数上执行,这将值限制为 4 TB。另请参阅 sc/sc0/sc1/sc2_kbytes_in。
返回当前代理的粘性表或指定粘性表中,发送到传入连接源地址的总数据量,以千字节为单位。如果找不到地址,则返回零。该测试目前在 32 位整数上执行,这将值限制为 4 TB。另请参阅 sc/sc0/sc1/sc2_kbytes_out。
返回一个整数值,对应于客户端侧连接的 TCP 源端口,即客户端连接的来源端口。此函数的用途非常有限,因为现代协议如今不太关心源端口。
返回当前代理的粘性表或指定粘性表中,从传入连接的源 IPv4 地址发起的、被转换为会话的连接的累积数量,这意味着它们被“tcp-request”规则接受。如果找不到地址,则返回零。另请参阅 sc/sc0/sc1/sc2_sess_cnt。
返回当前代理的粘性表或指定粘性表中,来自传入连接源地址的平均会话速率,以表中配置的时间段内的会话数量来衡量。会话是通过早期“tcp-request”规则的连接。如果找不到地址,则返回零。另请参阅 sc/sc0/sc1/sc2_sess_rate。
在当前代理的粘滞表或指定的粘滞表中,为传入连接的源地址创建或更新关联的条目。此表必须配置为存储 "conn_cnt" 数据类型,否则匹配将被忽略。当前计数会加一,并且到期计时器会刷新。更新后的计数将被返回,因此此匹配不会返回零。这曾被用来根据源地址拒绝滥用服务的用户。注意:建议改用 "tcp-request" 规则中功能更完整的 "track-sc*" 操作。
# 此前端限制每个源地址的传入 SSH 连接为每 10 秒 3 次, # 并拒绝超出的连接,直到观察到 10 秒的静默期。最多跟踪 20 个地址。 listen ssh bind :22 mode tcp maxconn 100 stick-table type ip size 20 expire 10s store conn_cnt tcp-request content reject if { src_updt_conn_cnt gt 3 } server local 127.0.0.1:22
在处理响应时,返回一个包含服务器 ID 的整数。虽然它几乎只用于 ACL,但也可用于日志记录或调试。
第 5 层通常仅描述会话层,在 haproxy 中,这最接近于所有连接握手完成但尚无内容可用时的会话。这里描述的获取方法最低可在 "tcp-request content" 规则集使用,除非它们需要某些未来的信息。这些信息通常包括 SSL 协商的结果。
当后端连接通过 SSL/TLS 传输层建立并且在本地解密时,返回 true。这意味着传出连接是向带有 "ssl" 选项的服务器建立的。当传出连接通过 SSL/TLS 传输层建立时,返回支持的对称加密密钥大小(以位为单位)。
当传出连接通过 SSL/TLS 传输层建立时,返回所使用的加密套件的名称。
当传出连接通过 SSL/TLS 传输层建立时,返回所使用的协议的名称。
当传出连接通过 SSL/TLS 传输层建立时,返回 RFC5929 第 3 节中定义的 TLS 唯一 ID。该唯一 ID 可以使用转换器 "ssl_bc_unique_id,base64" 编码为 base64。
当传出连接通过 SSL/TLS 传输层建立时,返回后端连接的 SSL ID。如果我们想知道会话是否被重用,记录此信息会很有用。
当传出连接通过 SSL/TLS 传输层建立时,返回实际使用的对称加密密钥大小(以位为单位)。
当传入连接通过 SSL/TLS 传输层建立时,如果在验证深度 > 0 的客户端证书期间检测到第一个错误,则返回该错误的 ID;如果在此验证过程中未遇到错误,则返回 0。请参考您的 SSL 库文档以查找完整的错误代码列表。
当传入连接通过 SSL/TLS 传输层建立时,如果在验证客户端证书期间检测到第一个错误,则返回该错误在 CA 链中的深度。如果未遇到错误,则返回 0。
当传入连接通过 SSL/TLS 传输层建立时,返回由客户端提供的 DER 格式证书。当用于 ACL 时,用于匹配的值可以以十六进制形式传递。
当传入连接通过 SSL/TLS 传输层建立时,如果在深度为 0 的验证期间检测到第一个错误,则返回该错误的 ID;如果在此验证过程中未遇到错误,则返回 0。请参考您的 SSL 库文档以查找完整的错误代码列表。
当传入连接通过 SSL/TLS 传输层建立时,如果未指定 <entry>,则返回客户端证书颁发者的完整专有名称 (DN);否则返回从 DN 开头找到的第一个给定条目的值。如果指定了正/负出现次数作为可选的第二个参数,则返回从 DN 开头/结尾算起的第 n 个给定条目的值。例如,"ssl_c_i_dn(OU,2)" 获取第二个组织单位,而 "ssl_c_i_dn(CN)" 获取通用名称。
当传入连接通过 SSL/TLS 传输层建立时,返回用于生成客户端证书密钥的算法名称。
当传入连接通过 SSL/TLS 传输层建立时,返回客户端证书中显示的结束日期,格式为 YYMMDDhhmmss[Z] 字符串。
当传入连接通过 SSL/TLS 传输层建立时,返回客户端证书中显示的开始日期,格式为 YYMMDDhhmmss[Z] 字符串。
当传入连接通过 SSL/TLS 传输层建立时,如果未指定 <entry>,则返回客户端证书主体的完整专有名称 (DN);否则返回从 DN 开头找到的第一个给定条目的值。如果指定了正/负出现次数作为可选的第二个参数,则返回从 DN 开头/结尾算起的第 n 个给定条目的值。例如,"ssl_c_s_dn(OU,2)" 获取第二个组织单位,而 "ssl_c_s_dn(CN)" 获取通用名称。
当传入连接通过 SSL/TLS 传输层建立时,返回客户端证书的序列号。当用于 ACL 时,用于匹配的值可以以十六进制形式传递。
当传入连接通过 SSL/TLS 传输层建立时,返回客户端证书的 SHA-1 指纹。这可用于将客户端粘滞到某个服务器,或将此信息传递给服务器。请注意,输出是二进制格式,因此如果要将该签名传递给服务器,您需要将其编码为十六进制或 base64,如下例所示:
http-request set-header X-SSL-Client-SHA1 %[ssl_c_sha1,hex]
当传入连接通过 SSL/TLS 传输层建立时,返回用于签署客户端证书的算法名称。
如果当前 SSL 会话使用了客户端证书,则返回 true,即使当前连接使用的是 SSL 会话恢复。另请参阅 "ssl_fc_has_crt"。
当传入连接通过 SSL/TLS 传输层建立时,返回验证结果的错误 ID;如果未遇到错误,则返回零。有关完整的错误代码列表,请参考您的 SSL 库文档。
当传入连接通过 SSL/TLS 传输层建立时,返回客户端证书的版本。
当传入连接通过 SSL/TLS 传输层建立时,返回前端提供的 DER 格式证书。当用于 ACL 时,用于匹配的值可以以十六进制形式传递。
当传入连接通过 SSL/TLS 传输层建立时,如果未指定 <entry>,则返回前端证书颁发者的完整专有名称 (DN);否则返回从 DN 开头找到的第一个给定条目的值。如果指定了正/负出现次数作为可选的第二个参数,则返回从 DN 开头/结尾算起的第 n 个给定条目的值。例如,"ssl_f_i_dn(OU,2)" 获取第二个组织单位,而 "ssl_f_i_dn(CN)" 获取通用名称。
当传入连接通过 SSL/TLS 传输层建立时,返回用于生成前端证书密钥的算法名称。
当传入连接通过 SSL/TLS 传输层建立时,返回前端证书中显示的结束日期,格式为 YYMMDDhhmmss[Z] 字符串。
当传入连接通过 SSL/TLS 传输层建立时,返回前端证书中显示的开始日期,格式为 YYMMDDhhmmss[Z] 字符串。
当传入连接通过 SSL/TLS 传输层建立时,如果未指定 <entry>,则返回前端证书主体的完整专有名称 (DN);否则返回从 DN 开头找到的第一个给定条目的值。如果指定了正/负出现次数作为可选的第二个参数,则返回从 DN 开头/结尾算起的第 n 个给定条目的值。例如,"ssl_f_s_dn(OU,2)" 获取第二个组织单位,而 "ssl_f_s_dn(CN)" 获取通用名称。
当传入连接通过 SSL/TLS 传输层建立时,返回前端证书的序列号。当用于 ACL 时,用于匹配的值可以以十六进制形式传递。
当传入连接通过 SSL/TLS 传输层建立时,返回前端证书的 SHA-1 指纹。这可用于了解使用 SNI 选择了哪个证书。
当传入连接通过 SSL/TLS 传输层建立时,返回用于签署前端证书的算法名称。
当传入连接通过 SSL/TLS 传输层建立时,返回前端证书的版本。
当前端连接通过 SSL/TLS 传输层建立并且在本地解密时,返回 true。这意味着它匹配了一个带有 "ssl" 选项的 "bind" 行声明的套接字。
# 当客户端通过 SSL 连接时,向服务器传递 "X-Proto: https" listen http-https bind :80 bind :443 ssl crt /etc/haproxy.pem http-request add-header X-Proto https if { ssl_fc }
当传入连接通过 SSL/TLS 传输层建立时,返回支持的对称加密密钥大小(以位为单位)。
此函数从通过 TLS 传输层建立并由 haproxy 本地解密的传入连接中提取应用层协议协商 (ALPN) 字段。结果是一个包含客户端通告的协议名称的字符串。SSL 库必须在构建时启用了对 TLS 扩展的支持(请检查 haproxy -vv)。请注意,除非在 "bind" 行上的 "alpn" 关键字指定了协议列表,否则不会通告 TLS ALPN 扩展。此外,没有任何机制强制客户端从此列表中选择一个协议,它可能会请求任何其他协议。TLS ALPN 扩展旨在取代 TLS NPN 扩展。另请参阅 "ssl_fc_npn"。
当传入连接通过 SSL/TLS 传输层建立时,返回所使用的加密套件的名称。
如果传入的 SSL/TLS 传输层连接中存在客户端证书,则返回 true。在 'verify' 语句设置为 'optional' 时很有用。注意:在使用会话 ID 或 TLS 票据进行 SSL 会话恢复时,当前连接中不存在客户端证书,但可以从缓存或票据中检索。因此,如果您想检查当前 SSL 会话是否使用了客户端证书,请优先使用 "ssl_c_used"。
此函数检查通过 SSL/TLS 传输层建立的传入连接中是否存在服务器名称指示 (SNI) TLS 扩展。当传入连接提供 TLS SNI 字段时返回 true。这要求 SSL 库在构建时启用了对 TLS 扩展的支持(请检查 haproxy -vv)。
如果通过 SSL/TLS 传输层传入的连接上,SSL/TLS 会话已通过使用 SSL 会话缓存或 TLS 票据得到恢复,则返回 true。
此函数从通过 TLS 传输层建立并由 haproxy 本地解密的传入连接中提取下一代协议协商 (NPN) 字段。结果是一个包含客户端通告的协议名称的字符串。SSL 库必须在构建时启用了对 TLS 扩展的支持(请检查 haproxy -vv)。请注意,除非在 "bind" 行上的 "npn" 关键字指定了协议列表,否则不会通告 TLS NPN 扩展。此外,没有任何机制强制客户端从此列表中选择一个协议,它可能会请求任何其他协议。请注意,TLS NPN 扩展已被 ALPN 取代。
当传入连接通过 SSL/TLS 传输层建立时,返回所使用的协议的名称。
当传入连接通过 SSL/TLS 传输层建立时,返回 RFC5929 第 3 节中定义的 TLS 唯一 ID。该唯一 ID 可以使用转换器 "ssl_bc_unique_id,base64" 编码为 base64。
当传入连接通过 SSL/TLS 传输层建立时,返回前端连接的 SSL ID。这对于将给定客户端粘滞到某个服务器很有用。需要注意的是,某些浏览器每隔几分钟就会刷新其会话 ID。
此函数从通过 SSL/TLS 传输层建立并由 haproxy 本地解密的传入连接中提取服务器名称指示 (SNI) TLS 扩展字段。结果(如果存在)通常是一个匹配 HTTPS 主机名的字符串(253 个字符或更少)。SSL 库必须在构建时启用了对 TLS 扩展的支持(请检查 haproxy -vv)。此获取方法与上面的 "req_ssl_sni" 不同,因为它适用于由 haproxy 解密的连接,而不是盲目转发的 SSL 内容。另请参阅下面的 "ssl_fc_sni_end" 和 "ssl_fc_sni_reg"。这要求 SSL 库在构建时启用了对 TLS 扩展的支持(请检查 haproxy -vv)。ACL 派生词:ssl_fc_sni_end:后缀匹配 ssl_fc_sni_reg:正则表达式匹配
当传入连接通过 SSL/TLS 传输层建立时,返回实际使用的对称加密密钥大小(以位为单位)。
从缓冲区内容获取样本与上述的样本获取方法有些不同,因为采样的数据是短暂的。这些数据只有在可用时才能使用,并且在转发后会丢失。因此,例如,在请求期间从缓冲区内容获取的样本不能在响应中使用。即使在获取数据时,它们也可能发生变化。有时需要设置一些延迟或组合多种样本获取方法,以确保预期的数据是完整和可用的,例如通过 TCP 请求内容检查。有关该主题的更多详细信息,请参阅 "tcp-request content" 关键字。
在请求上下文中使用时(例如:"stick on"、"stick match"),这是 "req.payload" 的别名;在响应上下文中使用时(例如在 "stick store response" 中),这是 "res.payload" 的别名。
在请求上下文中使用时(例如:"stick on"、"stick match"),这是 "req.payload_lv" 的别名;在响应上下文中使用时(例如在 "stick store response" 中),这是 "res.payload_lv" 的别名。
返回一个整数值,对应于请求缓冲区中存在的字节数。这主要用于 ACL。重要的是要理解,只要缓冲区在变化,此测试就不会返回 false。这意味着在会话开始时,等于零的检查几乎总是会立即匹配,而检查更多数据的测试将等待数据进入,并且仅当 haproxy 确定不会有更多数据进入时才会返回 false。此测试旨在与 TCP 请求内容检查一起使用。
此函数从请求缓冲区中提取一个从字节 <offset> 开始,长度为 <length> 字节的二进制块。作为特殊情况,如果 <length> 参数为零,则提取从 <offset> 到缓冲区末尾的整个部分。这可以与 ACL 一起使用,以检查缓冲区中任何位置是否存在某些内容。ACL 替代方案:payload(<offset>,<length>):十六进制二进制匹配
此函数提取一个二进制块,其大小在 <offset1> 处指定,长度为 <length> 字节,如果指定了 <offset2>,则从 <offset2> 开始,否则紧跟在长度之后开始。<offset2> 参数也支持相对偏移量,如果前缀为 '+' 或 '-' 符号。ACL 替代方案:payload_lv(<offset1>,<length>[,<offset2>]):十六进制二进制匹配
请参考 "stick store-response" 关键字中的示例。
当请求缓冲区中的数据看起来像 HTTP 并且能被正确解析时,返回 true。它与通用的 HTTP 请求解析器相同,因此应该不会有意外。在请求完成、失败或超时之前,此测试不会匹配。此测试可用于在 TCP 日志中报告协议,但最大的用途是阻止 TCP 请求分析,直到缓冲区中出现完整的 HTTP 请求,例如为了跟踪某个头部。
# 按 "base"(Host+URL 的拼接)跟踪请求计数 tcp-request inspect-delay 10s tcp-request content reject if !HTTP tcp-request content track-sc0 base table req-rate
当请求缓冲区看起来像 RDP 协议时,提取名为 <name> 的 RDP cookie;如果未指定名称,则提取任何 cookie。解析器只检查第一个 cookie,如 RDP 协议规范中所述。cookie 名称不区分大小写。通常会使用 "MSTS" cookie 名称,因为如果在客户端上正确配置,它可以包含连接到服务器的客户端的用户名。"MSTSHASH" cookie 也常用于到服务器的会话粘性。这与 "balance rdp-cookie" 的不同之处在于,可以使用任何平衡算法,因此客户端到后端服务器的分布与 RDP cookie 的哈希值无关。可以预见,使用诸如 "balance roundrobin" 或 "balance leastconn" 等平衡算法将比 "balance rdp-cookie" 使用的哈希算法更能均匀地将客户端分布到后端服务器。ACL 派生词:req_rdp_cookie([<name>]):精确字符串匹配
listen tse-farm bind 0.0.0.0:3389 # 在请求中等待 RDP cookie 最多 5 秒 tcp-request inspect-delay 5s tcp-request content accept if RDP_COOKIE # 应用 RDP cookie 持久性 persist rdp-cookie # 基于 mstshash cookie 进行持久化 # 仅在不使用 balance rdp-cookie 时 # 才有意义 stick-table type string size 204800 stick on req.rdp_cookie(mstshash) server srv1 1.1.1.1:3389 server srv1 1.1.1.2:3389
尝试将请求缓冲区解析为 RDP 协议,然后返回一个整数,对应于找到的 RDP cookie 的数量。如果传递了可选的 cookie 名称,则仅考虑与此名称匹配的 cookie。这主要用于 ACL。ACL 派生词:req_rdp_cookie_cnt([<name>]):整数匹配
返回一个布尔值,标识客户端是否在 SSL ClientHello 消息中发送了 RFC4492 第 5.1 节中定义的“支持的椭圆曲线扩展”。这可用于在同一 IP 地址上,向 ECC 兼容的客户端提供 EC 证书,并为所有其他客户端使用 RSA。请注意,这仅适用于请求缓冲区中找到的原始内容,而不适用于通过 SSL 数据层解密的内容,因此这不适用于带有 "ssl" 选项的 "bind" 行。
如果请求缓冲区中的数据可以解析为完整的 SSL(v3 或更高版本)客户端 hello 消息,则返回一个包含该 SSL hello 消息类型的整数值。请注意,这仅适用于请求缓冲区中找到的原始内容,而不适用于通过 SSL 数据层解密的内容,因此这不适用于带有 "ssl" 选项的 "bind" 行。这主要用于 ACL 中,以检测是否存在应该包含可用于粘性的 SSL 会话 ID 的 SSL hello 消息。
如果请求缓冲区中的数据可以解析为完整的 SSL(v3 或更高版本)客户端 hello 消息,则返回一个字符串,该字符串包含客户端在通过请求缓冲区的 TLS 流中发送的服务器名称 TLS 扩展的值。请注意,这仅适用于请求缓冲区中找到的原始内容,而不适用于通过 SSL 数据层解密的内容,因此这不适用于带有 "ssl" 选项的 "bind" 行。SNI 通常包含客户端尝试连接的主机名(对于现代浏览器)。当客户端使用 SSL/TLS 时,SNI 对于允许或拒绝访问特定主机很有用。此测试旨在与 TCP 请求内容检查一起使用。如果需要内容切换,建议首先等待一个完整的客户端 hello(类型 1),如下例所示。另请参阅 "ssl_fc_sni"。ACL 派生词:req_ssl_sni:精确字符串匹配
# 等待客户端 hello 最多 5 秒 tcp-request inspect-delay 5s tcp-request content accept if { req_ssl_hello_type 1 } use_backend bk_allow if { req_ssl_sni -f allowed_sites } default_backend bk_sorry_page
如果客户端未发送 SessionTicket TLS 扩展(RFC5077),则返回 0。如果客户端发送了 SessionTicket TLS 扩展,则返回 1。如果客户端还发送了非零长度的 TLS SessionTicket,则返回 2。请注意,这仅适用于请求缓冲区中找到的原始内容,而不适用于通过 SSL 数据层解密的内容,因此这不适用于带有 "ssl" 选项的 "bind" 行。例如,这可用于检测客户端是否发送了 SessionTicket 并相应地进行粘滞;如果没有 SessionTicket,则基于 SessionID 进行粘滞,或者在使用 SessionTicket 时由于没有服务器端状态而根本不进行粘滞。
返回一个整数值,该值包含请求缓冲区中流的 SSL/TLS 协议版本。支持 SSLv2 hello 消息和 SSLv3 消息。TLSv1 被通告为 SSL 版本 3.1。该值由主版本号乘以 65536,再加上次版本号组成。请注意,这仅适用于请求缓冲区中找到的原始内容,而不适用于通过 SSL 数据层解密的内容,因此这不适用于带有 "ssl" 选项的 "bind" 行。该测试的 ACL 版本以 MAJOR.MINOR 的十进制表示法进行匹配(例如:3.1)。此获取主要用于 ACL。ACL 派生词:req_ssl_ver:十进制匹配
返回一个整数值,对应于响应缓冲区中存在的字节数。这主要用于 ACL。重要的是要理解,只要缓冲区在变化,此测试就不会返回 false。这意味着在会话开始时,等于零的检查几乎总是会立即匹配,而检查更多数据的测试将等待数据进入,并且仅当 haproxy 确定不会有更多数据进入时才会返回 false。此测试旨在与 TCP 响应内容检查一起使用。
此函数从响应缓冲区中提取一个从字节 <offset> 开始,长度为 <length> 字节的二进制块。作为特殊情况,如果 <length> 参数为零,则提取从 <offset> 到缓冲区末尾的整个部分。这可以与 ACL 一起使用,以检查缓冲区中任何位置是否存在某些内容。
此函数提取一个二进制块,其大小在 <offset1> 处指定,长度为 <length> 字节,如果指定了 <offset2>,则从 <offset2> 开始,否则紧跟在长度之后开始。<offset2> 参数也支持相对偏移量,如果前缀为 '+' 或 '-' 符号。
请参考 "stick store-response" 关键字中的示例。
如果响应缓冲区中的数据可以解析为完整的 SSL(v3 或更高版本)hello 消息,则返回一个包含该 SSL hello 消息类型的整数值。请注意,这仅适用于响应缓冲区中找到的原始内容,而不适用于通过 SSL 数据层解密的内容,因此这不适用于带有 "ssl" 选项的 "server" 行。这主要用于 ACL 中,以检测是否存在应该包含可用于粘性的 SSL 会话 ID 的 SSL hello 消息。
此获取在检查周期结束时返回 true,否则不获取任何内容。它仅用于 ACL 中,与内容分析结合使用,以避免过早返回错误的判断。它也可用于延迟某些操作,例如对某些特殊地址进行延迟拒绝。由于它要么停止规则评估,要么立即返回 true,因此建议将此 acl 用作规则中的最后一个。请注意,默认的 ACL "WAIT_END" 始终可用,无需事先声明。此测试旨在与 TCP 请求内容检查一起使用。
# 将每个传入请求延迟 2 秒 tcp-request inspect-delay 2s tcp-request content accept if WAIT_END # 不要立即告诉坏家伙他们被拒绝了 tcp-request inspect-delay 10s acl goodguys src 10.0.0.0/24 acl badguys src 10.0.1.0/24 tcp-request content accept if goodguys tcp-request content reject if badguys WAIT_END tcp-request content reject
可以从 HTTP 内容、请求和响应中获取样本。这个应用层也称为第 7 层。只有当完整的 HTTP 请求或响应已从其各自的请求或响应缓冲区中解析出来时,才可能获取本节中的数据。对于所有 HTTP 特定规则和以 "mode http" 运行的部分,情况总是如此。使用 TCP 内容检查时,可能需要支持检查延迟,以便让请求或响应首先进入。这些获取可能需要比第 4 层获取更多的 CPU 资源,但由于请求和响应已被索引,所以不会多太多。
此函数返回第一个 Host 头部和请求路径部分的拼接,路径部分从第一个斜杠开始,到问号之前结束。在虚拟托管环境中,这对于检测 URL 滥用以及提高共享缓存效率很有用。将其与有限大小的粘滞表一起使用,还可以收集有关按主机/路径最常请求对象的数据。通过 ACL,它可以实现涉及主机和路径的简单内容切换规则,例如 "www.example.com/favicon.ico"。另请参阅 "path" 和 "uri"。ACL 派生词:base:精确字符串匹配 base_beg:前缀匹配 base_dir:子目录匹配 base_dom:域名匹配 base_end:后缀匹配 base_len:长度匹配 base_reg:正则表达式匹配 base_sub:子串匹配
此函数返回上面 "base" 获取方法返回值的 32 位哈希值。这对于在高流量网站上跟踪每个 URL 的活动很有用,而无需存储所有 URL。相反,存储一个更短的哈希值,可以节省大量内存。输出类型是无符号整数。使用的哈希函数是 SDBM,输出具有完全雪崩效应。技术上,base32 完全等同于 "base,sdbm(1)"。
此函数返回上面 base32 获取结果和下面 src 获取结果的拼接。结果类型为 binary,大小为 8 或 20 字节,具体取决于源地址族。这可用于跟踪每个 IP、每个 URL 的计数器。
此函数提取由 "capture request header" 捕获的头部内容,idx 是 capture 关键字在配置中的位置。
此函数提取 HTTP 请求的 METHOD。它可以在请求和响应中使用。与 "method" 不同,因为它被分配了内存,所以可以在请求和响应中使用。
capture.req.uri : string
此函数提取请求的 HTTP 版本,并返回 "HTTP/1.0" 或 "HTTP/1.1"。与 "req.ver" 不同,因为它依赖于一个持久性标志,所以可以在请求、响应和日志中使用。
此函数提取由 "capture response header" 捕获的头部内容,idx 是 capture 关键字在配置中的位置。第一个条目的索引为 0。
此函数提取响应的 HTTP 版本,并返回 "HTTP/1.0" 或 "HTTP/1.1"。与 "res.ver" 不同,因为它依赖于一个持久性标志,所以可以在日志中使用。
此函数以数据块形式返回 HTTP 请求的可用正文。它要求请求正文已使用 "option http-buffer-request" 进行了缓冲并可用。对于分块编码的正文,目前只分析第一个分块。
此获取假设 POST 请求的正文是 url-encoded 的。用户可以检查 "content-type" 是否包含值 "application/x-www-form-urlencoded"。此函数提取正文中参数 <name> 的第一次出现,该参数在 '&' 之前结束。参数名称区分大小写。如果未给出名称,则任何参数都会匹配,并返回第一个。结果是一个字符串,对应于请求正文中呈现的参数 <name> 的值(不执行 URL 解码)。请注意,此获取的 ACL 版本会遍历多个参数,如果未给出名称,则会迭代报告所有参数值。
此函数返回 HTTP 请求的可用正文长度(以字节为单位)。如果正文大于缓冲区,则该值可能低于通告的长度。它要求请求正文已使用 "option http-buffer-request" 进行了缓冲并可用。
此函数返回 HTTP 请求正文的通告长度(以字节为单位)。它将表示通告的 Content-Length 头部,或者在分块编码的情况下,表示第一个分块的大小。为了解析分块,它要求请求正文已使用 "option http-buffer-request" 进行了缓冲并可用。
此函数从请求的 "Cookie" 头部行中提取名为 <name> 的 cookie 的最后一次出现,并将其值作为字符串返回。如果未指定名称,则返回第一个 cookie 的值。与 ACL 一起使用时,将评估所有匹配的 cookie。根据 Cookie 头部规范 (RFC6265) 的要求,名称和值周围的空格将被忽略。cookie 名称区分大小写。空 cookie 是有效的,因此如果存在空 cookie,很可能会返回一个空值。使用 "found" 匹配来检测是否存在。对于服务器发送的响应 cookie,请使用 res.cook() 变体。ACL 派生词:cook([<name>]):精确字符串匹配 cook_beg([<name>]):前缀匹配 cook_dir([<name>]):子目录匹配 cook_dom([<name>]):域名匹配 cook_end([<name>]):后缀匹配 cook_len([<name>]):长度匹配 cook_reg([<name>]):正则表达式匹配 cook_sub([<name>]):子串匹配
返回一个整数值,表示名为 <name> 的 cookie 在请求中出现的次数;如果未指定 <name>,则表示所有 cookie 的数量。
此函数从请求的 "Cookie" 头部行中提取名为 <name> 的 cookie 的最后一次出现,并将其值转换为整数返回。如果未指定名称,则返回第一个 cookie 的值。在 ACL 中使用时,将遍历所有匹配的名称,直到找到一个匹配的值。
此函数从请求的 "Cookie" 头部行或响应的 "Set-Cookie" 头部中提取名为 <name> 的 cookie 的最后一次出现,并将其值作为字符串返回。一个典型的用途是让多个共享相同配置文件的客户端使用同一台服务器。这可能类似于 "appsession" 通过 "request-learn" 语句所做的,但支持多对等体同步和跨重启的状态保持。如果未指定名称,则返回第一个 cookie 的值。此获取不应再使用,应替换为 req.cook() 或 res.cook(),因为它根据使用上下文模糊地确定方向。
在请求上使用时,此函数等同于 req.hdr();在响应上使用时,等同于 res.hdr()。有关更多详细信息,请参考这些各自的获取。如果不确定获取方向,请使用明确的函数。请注意,与 hdr() 样本获取方法相反,hdr_* ACL 关键字明确地应用于请求头部。
此函数提取 HTTP 请求中名为 <name> 的头部的最后一次出现。从 ACL 使用时,将遍历所有出现,直到找到匹配项。可选地,可以指定一个特定的出现次数作为位置编号。正值表示从第一次出现开始的位置,1 是第一个。负值表示相对于最后一次出现的位置,-1 是最后一个。它与 req.hdr() 的不同之处在于,值中存在的任何逗号都会被返回,并且不会用作分隔符。这对于像 User-Agent 这样的头部有时很有用。
返回一个整数值,表示请求头字段名 <name> 的出现次数;如果未指定 <name>,则返回头字段的总数。与其 req.hdr_cnt() 类似函数不同,此函数返回完整行头部的数量,并且不会在逗号处停止。
此函数提取 HTTP 请求中名为 <name> 的头部的最后一次出现。从 ACL 使用时,将遍历所有出现,直到找到匹配项。可选地,可以指定一个特定的出现次数作为位置编号。正值表示从第一次出现开始的位置,1 是第一个。负值表示相对于最后一次出现的位置,-1 是最后一个。一个典型的用途是与 X-Forwarded-For 头部一起使用,一旦转换为 IP,就与 IP 粘滞表关联。该函数将任何逗号视为不同值的分隔符。如果需要完整的行头部,请使用 req.fhdr()。请仔细查阅 RFC7231,了解某些头部的解析方式。此外,其中一些是不区分大小写的(例如:Connection)。ACL 派生词:hdr([<name>[,<occ>]]):精确字符串匹配 hdr_beg([<name>[,<occ>]]):前缀匹配 hdr_dir([<name>[,<occ>]]):子目录匹配 hdr_dom([<name>[,<occ>]]):域名匹配 hdr_end([<name>[,<occ>]]):后缀匹配 hdr_len([<name>[,<occ>]]):长度匹配 hdr_reg([<name>[,<occ>]]):正则表达式匹配 hdr_sub([<name>[,<occ>]]):子串匹配
返回一个整数值,表示请求头字段名 <name> 的出现次数;如果未指定 <name>,则表示头字段值的总数。重要的是要记住,一个头部行如果包含多个值,可能会被计为多个头部。该函数将任何逗号视为不同值的分隔符。如果需要完整的行头部,应改用 req.fhdr_cnt()。通过 ACL,它可用于检测特定头部的存在、缺失或滥用,以及通过拒绝包含多个某些头部的请求来阻止请求走私攻击。有关头部匹配的更多信息,请参阅 "req.hdr"。
此函数提取 HTTP 请求中名为 <name> 的头部的最后一次出现,将其转换为 IPv4 或 IPv6 地址并返回该地址。与 ACL 一起使用时,会检查所有出现;如果省略 <name>,则会检查每个头部的每个值。可选地,可以指定一个特定的出现次数作为位置编号。正值表示从第一次出现开始的位置,1 是第一个。负值表示相对于最后一次出现的位置,-1 是最后一个。一个典型的用途是与 X-Forwarded-For 和 X-Client-IP 头部一起使用。
此函数提取 HTTP 请求中名为 <name> 的头部的最后一次出现,并将其转换为整数值。与 ACL 一起使用时,会检查所有出现;如果省略 <name>,则会检查每个头部的每个值。可选地,可以指定一个特定的出现次数作为位置编号。正值表示从第一次出现开始的位置,1 是第一个。负值表示相对于最后一次出现的位置,-1 是最后一个。一个典型的用途是与 X-Forwarded-For 头部一起使用。
返回一个布尔值,指示从客户端收到的身份验证数据是否与指定用户列表中存储的用户名和密码匹配。此获取函数在 ACL 之外并不真正有用。目前仅支持 http 基本身份验证。
如果从客户端收到的身份验证数据中的用户名和密码根据指定用户列表均有效,则返回一个对应于该用户名的字符串。其主要目的是在 ACL 中使用,然后检查该用户是否属于列表中的任何组。此获取函数在 ACL 之外并不真正有用。目前仅支持 http 基本身份验证。ACL 派生词:http_auth_group(<userlist>) : group ... 当从请求中提取的用户(其密码根据指定用户列表有效)属于至少一个组时返回 true。
当正在处理的请求是连接的第一个请求时返回 true。这可用于添加或删除在请求不是第一个时某些请求中可能缺少的头部,或帮助在日志中对请求进行分组。
返回一个对应于 HTTP 请求中方法的整数值。例如,"GET" 等于 1(检查源代码以确定匹配关系)。值 9 表示“其他方法”,并可能转换为从流中提取的字符串。这不应直接用作样本,它仅用于 ACL,ACL 会透明地将方法从模式转换为这些整数 + 字符串值。一些预定义的 ACL 已经检查了最常见的方法。ACL 派生词:method:不区分大小写的方法匹配
# 只接受 GET 和 HEAD 请求 acl valid_method method GET HEAD http-request deny if ! valid_method
此函数提取请求的 URL 路径,它从第一个斜杠开始,到问号之前结束(不包括主机部分)。一个典型的用途是与支持预取的缓存一起使用,以及需要从数据库聚合多种信息并将其保存在缓存中的门户网站。请注意,对于出站缓存,使用 "url" 会更明智。通过 ACL,它通常用于匹配确切的文件名(例如:"/login.php"),或使用派生形式匹配目录部分。另请参阅 "url" 和 "base" 获取方法。ACL 派生词:path:精确字符串匹配 path_beg:前缀匹配 path_dir:子目录匹配 path_dom:域名匹配 path_end:后缀匹配 path_len:长度匹配 path_reg:正则表达式匹配 path_sub:子串匹配
此函数提取请求的查询字符串,它从第一个问号之后开始。如果没有问号,此获取不返回任何内容。如果存在问号但后面没有任何内容,则返回一个空字符串。这意味着可以使用 "found" 匹配方法轻松地知道是否存在查询字符串。此获取是 "path" 的补充,后者在问号之前停止。
此函数构建一个字符串,该字符串由规则评估时请求中出现的所有头部名称拼接而成。默认分隔符是逗号 (','),但可以通过可选参数 <delim> 进行覆盖。在这种情况下,只考虑 <delim> 的第一个字符。从 HTTP 请求中返回版本字符串,例如 "1.1"。这对于日志很有用,但主要用于 ACL。一些预定义的 ACL 已经检查了版本 1.0 和 1.1。ACL 派生词:req_ver:精确字符串匹配
如果响应已被 HAProxy 压缩,则返回布尔值 "true",否则返回布尔值 "false"。这可用于在日志中添加信息。
如果响应被 HAProxy 压缩,则返回一个包含所用算法名称的字符串,例如:“deflate”。这可用于在日志中添加一些信息。
此函数从响应的 "Set-Cookie" 标头行中提取 cookie 名称 <name> 的最后一次出现,并将其值作为字符串返回。如果未指定名称,则返回第一个 cookie 的值。ACL 派生:scook([<name>] : 精确字符串匹配
返回一个整数值,表示 cookie <name> 在响应中出现的次数,如果未指定 <name>,则表示所有 cookie 的数量。这在与 ACL 结合使用以检测可疑响应时非常有用。
此函数从响应的 "Set-Cookie" 标头行中提取 cookie 名称 <name> 的最后一次出现,并将其值转换为整数后返回。如果未指定名称,则返回第一个 cookie 的值。
此函数提取 HTTP 响应中标头 <name> 的最后一次出现,如果未指定 <name>,则提取最后一个标头。可以选择性地将特定出现指定为位置编号。正值表示从第一次出现开始的位置,1 代表第一次。负值表示相对于最后一次出现的位置,-1 代表最后一次。它与 res.hdr() 的不同之处在于,值中存在的任何逗号都会被返回,而不会被用作分隔符。如果不需要此行为,应改用 res.hdr() 提取。这对于像 Date 或 Expires 这样的标头有时很有用。
返回一个整数值,表示响应标头字段名 <name> 的出现次数,如果未指定 <name>,则返回标头字段的总数。与其对应的 res.hdr_cnt() 函数不同,此函数返回完整行标头的数量,并且不会在逗号处停止。如果不需要此行为,应改用 res.hdr_cnt() 提取。
此函数提取 HTTP 响应中标头 <name> 的最后一次出现,如果未指定 <name>,则提取最后一个标头。可以选择性地将特定出现指定为位置编号。正值表示从第一次出现开始的位置,1 代表第一次。负值表示相对于最后一次出现的位置,-1 代表最后一次。这对于将一些数据学习到粘性表中很有用。该函数将任何逗号都视作不同值的分隔符。如果不需要此行为,应改用 res.fhdr() 提取。ACL 派生:shdr([<name>[,<occ>]]) : 精确字符串匹配 shdr_beg([<name>[,<occ>]]) : 前缀匹配 shdr_dir([<name>[,<occ>]]) : 子目录匹配 shdr_dom([<name>[,<occ>]]) : 域名匹配 shdr_end([<name>[,<occ>]]) : 后缀匹配 shdr_len([<name>[,<occ>]]) : 长度匹配 shdr_reg([<name>[,<occ>]]) : 正则表达式匹配 shdr_sub([<name>[,<occ>]]) : 子字符串匹配
返回一个整数值,表示响应标头字段名 <name> 的出现次数,如果未指定 <name>,则返回标头字段的总数。该函数将任何逗号都视作不同值的分隔符。如果不需要此行为,应改用 res.fhdr_cnt() 提取。
此函数提取 HTTP 响应中标头 <name> 的最后一次出现,将其转换为 IPv4 或 IPv6 地址并返回该地址。可以选择性地将特定出现指定为位置编号。正值表示从第一次出现开始的位置,1 代表第一次。负值表示相对于最后一次出现的位置,-1 代表最后一次。这对于将一些数据学习到粘性表中很有用。
此函数构建一个字符串,该字符串由规则评估时响应中出现的所有标头名称连接而成。默认分隔符是逗号 (','),但可以通过可选参数 <delim> 进行覆盖。在这种情况下,只考虑 <delim> 的第一个字符。此函数提取 HTTP 响应中标头 <name> 的最后一次出现,并将其转换为一个整数值。可以选择性地将特定出现指定为位置编号。正值表示从第一次出现开始的位置,1 代表第一次。负值表示相对于最后一次出现的位置,-1 代表最后一次。这对于将一些数据学习到粘性表中很有用。
从 HTTP 响应中返回版本字符串,例如 "1.1"。这对于日志很有用,但主要用于 ACL。ACL 派生:resp_ver : 精确字符串匹配
此函数从响应的 "Set-Cookie" 标头行中提取 cookie 名称 <name> 的最后一次出现,并使用相应的值进行匹配。这可以与 "appsession" 在默认选项下的行为相媲美,但支持多对等体同步和跨重启状态保持。此提取函数已弃用,并已被 "res.cook" 提取函数取代。此关键字将很快消失。
返回一个包含 HTTP 响应中 HTTP 状态码的整数,例如 302。它主要用于 ACL 和整数范围内,例如,如果响应不是 3xx,则移除任何 Location 标头。
此函数提取请求中呈现的 URL。典型用途是与支持预取功能的缓存一起使用,以及与需要从数据库聚合多个信息并将其保存在缓存中的门户网站一起使用。对于 ACL,首选使用 "path" 而不是 "url",因为客户端可能会发送完整的 URL,就像通常对代理所做的那样。唯一真正的用途是匹配 "*",这在 "path" 中不匹配,并且已经有预定义的 ACL。另请参阅 "path" 和 "base"。ACL 派生:url : 精确字符串匹配 url_beg : 前缀匹配 url_dir : 子目录匹配 url_dom : 域名匹配 url_end : 后缀匹配 url_len : 长度匹配 url_reg : 正则表达式匹配 url_sub : 子字符串匹配
当主机部分以 IP 地址形式呈现时,此函数从请求的 URL 中提取 IP 地址。其用途非常有限。例如,监控系统可能会使用此字段作为源 IP 的替代方案,以测试给定源地址将遵循的路径,或为给定源地址在表中强制创建一个条目。对于 ACL,它可以用于限制通过代理访问某些系统,例如与选项 "http_proxy" 结合使用时。
此函数从请求的 URL 中提取端口部分。请注意,如果请求中未指定端口,则假定为端口 80。对于 ACL,它可以用于限制通过代理访问某些系统,例如与选项 "http_proxy" 结合使用时。
此函数提取查询字符串中参数 <name> 的第一次出现,该查询字符串在 '?' 或 <delim> 之后开始,在 '&'、';' 或 <delim> 之前结束。参数名称区分大小写。如果未给出名称,则任何参数都会匹配,并返回第一个。结果是与请求中呈现的参数 <name> 的值相对应的字符串(不执行 URL 解码)。这可用于基于客户端 ID 的会话粘性,以提取作为 URL 参数传递的应用程序 cookie,或在 ACL 中应用某些检查。请注意,此提取的 ACL 版本会遍历多个参数,如果未给出名称,将迭代报告所有参数值。ACL 派生:urlp(<name>[,<delim>]) : 精确字符串匹配 urlp_beg(<name>[,<delim>]) : 前缀匹配 urlp_dir(<name>[,<delim>]) : 子目录匹配 urlp_dom(<name>[,<delim>]) : 域名匹配 urlp_end(<name>[,<delim>]) : 后缀匹配 urlp_len(<name>[,<delim>]) : 长度匹配 urlp_reg(<name>[,<delim>]) : 正则表达式匹配 urlp_sub(<name>[,<delim>]) : 子字符串匹配
# 匹配 http://example.com/foo?PHPSESSIONID=some_id stick on urlp(PHPSESSIONID) # 匹配 http://example.com/foo;JSESSIONID=some_id stick on urlp(JSESSIONID,;)
参见上面的 "urlp"。此函数提取请求中的 URL 参数 <name> 并将其转换为整数值。例如,这可用于基于用户 ID 的会话粘性,或与 ACL 一起匹配页码或价格。
此函数返回一个 32 位哈希值,该值由连接第一个 Host 标头和整个 URL(包括参数,而不仅仅是请求的路径部分,如上面的 "base32" 提取)得到。这对于跟踪每个 URL 的活动很有用。存储一个较短的哈希值可以节省大量内存。输出类型是无符号整数。
此函数返回 "url32" 提取和 "src" 提取的连接结果。结果类型为 binary,大小为 8 或 20 字节,具体取决于源地址族。这可用于跟踪每个 IP、每个 URL 的计数器。
一些预定义的 ACL 是硬编码的,因此不必在每个需要它们的前端中声明。它们的名称都使用大写字母,以避免混淆。下面提供了它们的等效项。
| ACL 名称 | 等效于 | 用法 |
|---|---|---|
| FALSE | always_false | 从不匹配 |
| HTTP | req_proto_http | 如果协议是有效的 HTTP 则匹配 |
| HTTP_1.0 | req_ver 1.0 | 匹配 HTTP 版本 1.0 |
| HTTP_1.1 | req_ver 1.1 | 匹配 HTTP 版本 1.1 |
| HTTP_CONTENT | hdr_val(content-length) gt 0 | 匹配一个存在的 content-length |
| HTTP_URL_ABS | url_reg ^[^/:]*:// | 匹配带协议方案的绝对 URL |
| HTTP_URL_SLASH | url_beg / | 匹配以 "/" 开头的 URL |
| HTTP_URL_STAR | url * | 匹配等于 "*" 的 URL |
| LOCALHOST | src 127.0.0.1/8 | 匹配来自本地主机的连接 |
| METH_CONNECT | method CONNECT | 匹配 HTTP CONNECT 方法 |
| METH_GET | method GET HEAD | 匹配 HTTP GET 或 HEAD 方法 |
| METH_HEAD | method HEAD | 匹配 HTTP HEAD 方法 |
| METH_OPTIONS | method OPTIONS | 匹配 HTTP OPTIONS 方法 |
| METH_POST | method POST | 匹配 HTTP POST 方法 |
| METH_TRACE | method TRACE | 匹配 HTTP TRACE 方法 |
| RDP_COOKIE | req_rdp_cookie_cnt gt 0 | 匹配 RDP cookie 的存在 |
| REQ_CONTENT | req_len gt 0 | 匹配请求缓冲区中的数据 |
| TRUE | always_true | 总是匹配 |
| WAIT_END | wait_end | 等待内容分析结束 |
HAProxy 的强大之处之一无疑在于其精确的日志。它可能为此类产品提供了最精细的信息级别,这对于排查复杂环境至关重要。日志中提供的标准信息包括客户端端口、TCP/HTTP 状态计时器、终止时的精确会话状态和精确终止原因、有关将流量引导至服务器的决策信息,当然还有捕获任意标头的能力。为了提高管理员的反应速度,它对遇到的内部和外部问题提供了极大的透明度,并且可以将不同级别的日志同时发送到不同的源,并使用不同的级别过滤器:- 全局进程级日志(系统错误、启动/停止等..)- 每个实例的系统和内部错误(资源不足、错误等...)- 每个实例的外部问题(服务器上线/下线、最大连接数)- 每个实例的活动(客户端连接),可以在建立时或终止时记录。- 每个请求的日志级别控制,例如:http-request set-log-level silent if sensitive_request 将不同级别的日志分发到不同的日志服务器的能力允许多个生产团队进行交互并尽快解决他们的问题。例如,系统团队可能会监控系统范围的错误,而应用程序团队可能会实时监控其服务器的上线/下线情况,安全团队可能会在一小时延迟后分析活动日志。
可以记录 TCP 和 HTTP 连接的信息,例如日期、时间、源 IP 地址、目标地址、连接持续时间、响应时间、HTTP 请求、HTTP 返回码、传输的字节数、会话结束的条件,甚至交换的 cookie 值。例如,跟踪特定用户的问题。所有消息最多可以发送到两个 syslog 服务器。有关日志设施的更多信息,请查看 第 4.2 节 中的 "log" 关键字。
HAProxy 支持 5 种日志格式。这些格式之间有几个字段是通用的,将在以下部分详细说明。其中一些可能会因配置而略有不同,这是由于某些选项特定的指示符造成的。支持的格式如下:- 默认格式,非常基本且很少使用。它仅在接受传入连接时提供非常基本的信息:源 IP:端口、目标 IP:端口和前端名称。此模式最终将消失,因此不会对其进行详细描述。- TCP 格式,更为高级。当在前端设置 "option tcplog" 时启用此格式。HAProxy 通常会等待连接终止后再记录日志。此格式提供更丰富的信息,例如计时器、连接计数、队列大小等。建议纯 TCP 代理使用此格式。- HTTP 格式,是用于 HTTP 代理的最先进格式。当在前端设置 "option httplog" 时启用此格式。它提供与 TCP 格式相同的信息,并带有一些 HTTP 特定的字段,例如请求、状态码以及标头和 cookie 的捕获。建议 HTTP 代理使用此格式。- CLF HTTP 格式,与 HTTP 格式等效,但字段的排列顺序与 CLF 格式相同。在此模式下,所有计时器、捕获、标志等...在通用字段结束后逐个字段出现,顺序与标准 HTTP 格式中出现的顺序相同。- 自定义日志格式,允许您创建自己的日志行。接下来的部分将深入探讨每种格式的细节。格式规范将基于“字段”进行。除非另有说明,字段是由任意数量的空格分隔的文本部分。由于 syslog 服务器可能会在行首插入字段,因此始终假定第一个字段是包含进程名称和标识符的字段。注意:由于日志行可能很长,下面章节中的日志示例可能会被分成多行。示例日志行将以 3 个右尖括号('>>>')为前缀,每次日志被分成多行时,每个非最后一行将以反斜杠('\')结尾,下一行将以两个空格缩进开始。
当没有设置特定选项时,使用此格式。日志在连接被接受后立即发出。需要注意的是,这目前是唯一记录请求目标 IP 和端口的格式。
listen www mode http log global server srv1 127.0.0.1:8000 >>> Feb 6 12:12:09 localhost \ haproxy[14385]: Connect from 10.0.1.2:33312 to 10.0.3.31:8012 \ (www/HTTP)
字段 格式 从以上示例中提取 1 process_name '[' pid ']:' haproxy[14385]: 2 'Connect from' Connect from 3 source_ip ':' source_port 10.0.1.2:33312 4 'to' to 5 destination_ip ':' destination_port 10.0.3.31:8012 6 '(' frontend_name '/' mode ')' (www/HTTP) 详细字段描述:- "source_ip" 是发起连接的客户端的 IP 地址。- "source_port" 是发起连接的客户端的 TCP 端口。- "destination_ip" 是客户端连接到的 IP 地址。- "destination_port" 是客户端连接到的 TCP 端口。- "frontend_name" 是接收并处理连接的前端(或监听器)的名称。- "mode" 是前端运行的模式(TCP 或 HTTP)。如果是 UNIX 套接字,源地址和目标地址标记为 "unix:",端口反映接受连接的套接字的内部 ID(与统计信息中报告的 ID 相同)。建议新安装不要使用这种已弃用的格式,因为它最终会消失。当在前端指定 "option tcplog" 时使用 TCP 格式,这是纯 TCP 代理的推荐格式。它为故障排除提供了许多宝贵的信息。由于此格式包含计时器和字节计数,日志通常在会话结束时发出。如果指定了 "option logasap",它可以更早发出,这在大多数具有长会话(如远程终端)的环境中是有意义的。匹配 "monitor" 规则的会话从不被记录。通过在前端指定 "option dontlognull",也可以不为客户端和服务器之间没有数据交换的会话发出日志。如果前端指定了 "option dontlog-normal",成功的连接将不会被记录。一些字段可能会因某些配置选项而略有不同,这些字段在下面的字段名称后用星号('*')标记。
frontend fnt mode tcp option tcplog log global default_backend bck backend bck server srv1 127.0.0.1:8000 >>> Feb 6 12:12:56 localhost \ haproxy[14387]: 10.0.1.2:33313 [06/Feb/2009:12:12:51.443] fnt \ bck/srv1 0/0/5007 212 -- 0/0/0/0/3 0/0
字段 格式 从以上示例中提取 1 process_name '[' pid ']:' haproxy[14387]: 2 client_ip ':' client_port 10.0.1.2:33313 3 '[' accept_date ']' [06/Feb/2009:12:12:51.443] 4 frontend_name fnt 5 backend_name '/' server_name bck/srv1 6 Tw '/' Tc '/' Tt* 0/0/5007 7 bytes_read* 212 8 termination_state -- 9 actconn '/' feconn '/' beconn '/' srv_conn '/' retries* 0/0/0/0/3 10 srv_queue '/' backend_queue 0/0 详细字段描述:- "client_ip" 是向 haproxy 发起 TCP 连接的客户端的 IP 地址。如果连接是在 UNIX 套接字上接受的,IP 地址将被替换为 "unix"。请注意,当连接在配置了 "accept-proxy" 的套接字上接受并且正确使用了 PROXY 协议时,日志将反映转发连接的信息。- "client_port" 是发起连接的客户端的 TCP 端口。如果连接是在 UNIX 套接字上接受的,端口将被替换为接受套接字的 ID,该 ID 也在统计信息界面中报告。- "accept_date" 是 haproxy 接收连接的确切日期(如果系统积压中存在一些排队,可能与网络上观察到的日期略有不同)。这通常与任何上游防火墙日志中可能出现的日期相同。- "frontend_name" 是接收并处理连接的前端(或监听器)的名称。- "backend_name" 是被选中用于管理到服务器连接的后端(或监听器)的名称。如果未应用切换规则,这将与前端相同,这在 TCP 应用中很常见。- "server_name" 是连接最后发送到的服务器的名称,如果发生连接错误并进行了重新分派,这可能与第一个服务器不同。请注意,此服务器属于处理请求的后端。如果在到达服务器之前连接被中止,则显示 "<NOSRV>" 而不是服务器名称。- "Tw" 是在各种队列中等待的总时间(毫秒)。如果连接在到达队列之前被中止,则可以为 "-1"。有关更多详细信息,请参见下面的“计时器”。- "Tc" 是等待与最终服务器建立连接的总时间(毫秒),包括重试。如果连接在建立连接之前被中止,则可以为 "-1"。有关更多详细信息,请参见下面的“计时器”。- "Tt" 是从接受到最后关闭所经过的总时间(毫秒)。它涵盖了所有可能的处理。有一个例外,如果指定了 "option logasap",则时间计数在发出日志时停止。在这种情况下,值前面会加上一个 '+' 符号,表示最终值会更大。有关更多详细信息,请参见下面的“计时器”。- "bytes_read" 是在发出日志时从服务器传输到客户端的总字节数。如果指定了 "option logasap",则此值将以 '+' 符号为前缀,表示最终值可能会更大。请注意,此值为 64 位计数器,因此日志分析工具必须能够处理它而不会溢出。- "termination_state" 是会话结束时会话所处的状态。这表示会话状态,哪一方导致会话结束,以及原因(超时、错误等)。正常标志应为 "--",表示会话由任一端关闭,缓冲区中没有剩余数据。有关更多详细信息,请参见下面的“断开连接时的会话状态”。- "actconn" 是记录会话时进程上的并发连接总数。它有助于检测何时达到某些每个进程的系统限制。例如,如果 actconn 在发生多个连接错误时接近 512,则很可能系统限制进程最多使用 1024 个文件描述符,并且它们都已被使用。请参阅 第 3 节“全局参数”以了解如何调整系统。- "feconn" 是记录会话时前端上的并发连接总数。它有助于估算维持高负载所需的资源量,并检测何时达到前端的 "maxconn"。通常当此值大幅增加时,是因为后端服务器出现拥塞,但有时也可能是由拒绝服务攻击引起的。- "beconn" 是记录会话时后端处理的并发连接总数。它包括服务器上活跃的并发连接总数以及在队列中等待的连接数。它有助于估算为支持给定应用程序的高负载所需的额外服务器数量。通常当此值大幅增加时,是因为后端服务器出现拥塞,但有时也可能是由拒绝服务攻击引起的。- "srv_conn" 是记录会话时服务器上仍然活跃的并发连接总数。它永远不会超过服务器配置的 "maxconn" 参数。如果此值经常接近或等于服务器的 "maxconn",则意味着流量调节经常被涉及,这表示服务器的 maxconn 值太低,或者没有足够的服务器以最佳响应时间处理负载。当只有一个服务器的 "srv_conn" 很高时,通常意味着该服务器存在一些问题,导致连接处理时间比其他服务器更长。- "retries" 是此会话在尝试连接服务器时遇到的连接重试次数。它通常应为零,除非在尝试连接时服务器正在被停止。频繁的重试通常表示 haproxy 和服务器之间存在网络问题,或者服务器上的系统积压配置不当,阻止新连接排队。此字段可以选择性地以 '+' 符号为前缀,表示会话在初始服务器上达到最大重试次数后经历了重新分派。在这种情况下,日志中出现的服务器名称是连接被重新分派到的服务器,而不是第一个服务器,尽管在哈希的情况下两者有时可能相同。因此,作为一般经验法则,当重试次数前存在 '+' 时,此计数不应归因于记录的服务器。- "srv_queue" 是在此请求之前在服务器队列中处理的请求总数。当请求未经过服务器队列时,它为零。它可以通过将队列中花费的时间除以队列中的请求数来估算近似的服务器响应时间。值得注意的是,如果一个会话经历重新分派并经过两个服务器队列,它们的位置将被累加。除非发生重新分派,否则请求不应同时通过服务器队列和后端队列。- "backend_queue" 是在此请求之前在后端的全局队列中处理的请求总数。当请求未经过全局队列时,它为零。它可以通过除以服务器的 "maxconn" 参数来估算平均队列长度,从而轻松转换为缺失的服务器数量。值得注意的是,如果一个会话经历重新分派,它可能会两次通过后端的队列,然后两个位置都将被累加。除非发生重新分派,否则请求不应同时通过服务器队列和后端队列。
HTTP 格式是最完整且最适合 HTTP 代理的格式。当在前端指定 "option httplog" 时启用此格式。它提供了与 TCP 格式相同级别的信息,并增加了 HTTP 协议特有的附加功能。与 TCP 格式一样,日志通常在会话结束时发出,除非指定了 "option logasap",这通常只对下载站点有意义。匹配 "monitor" 规则的会话永远不会被记录。通过在前端指定 "option dontlognull",也可以不记录客户端未发送数据的会话。如果前端指定了 "option dontlog-normal",成功的连接将不会被记录。大多数字段与 TCP 日志共享,有些则不同。一些字段可能会因某些配置选项而略有不同。这些字段在下面的字段名称后用星号('*')标记。
frontend http-in mode http option httplog log global default_backend bck backend static server srv1 127.0.0.1:8000 >>> Feb 6 12:14:14 localhost \ haproxy[14389]: 10.0.1.2:33317 [06/Feb/2009:12:14:14.655] http-in \ static/srv1 10/0/30/69/109 200 2750 - - ---- 1/1/1/1/0 0/0 {1wt.eu} \ {} "GET /index.html HTTP/1.1"
字段 格式 从以上示例中提取 1 process_name '[' pid ']:' haproxy[14389]: 2 client_ip ':' client_port 10.0.1.2:33317 3 '[' accept_date ']' [06/Feb/2009:12:14:14.655] 4 frontend_name http-in 5 backend_name '/' server_name static/srv1 6 Tq '/' Tw '/' Tc '/' Tr '/' Tt* 10/0/30/69/109 7 status_code 200 8 bytes_read* 2750 9 captured_request_cookie - 10 captured_response_cookie - 11 termination_state ---- 12 actconn '/' feconn '/' beconn '/' srv_conn '/' retries* 1/1/1/1/0 13 srv_queue '/' backend_queue 0/0 14 '{' captured_request_headers* '}' {haproxy.1wt.eu} 15 '{' captured_response_headers* '}' {} 16 '"' http_request '"' "GET /index.html HTTP/1.1" 详细字段描述:- "client_ip" 是向 haproxy 发起 TCP 连接的客户端的 IP 地址。如果连接是在 UNIX 套接字上接受的,IP 地址将被替换为 "unix"。请注意,当连接在配置了 "accept-proxy" 的套接字上接受并且正确使用了 PROXY 协议时,日志将反映转发连接的信息。- "client_port" 是发起连接的客户端的 TCP 端口。如果连接是在 UNIX 套接字上接受的,端口将被替换为接受套接字的 ID,该 ID 也在统计信息界面中报告。- "accept_date" 是 haproxy 接收 TCP 连接的确切日期(如果系统积压中存在一些排队,可能与网络上观察到的日期略有不同)。这通常与任何上游防火墙日志中可能出现的日期相同。这不取决于客户端是否发送了请求。- "frontend_name" 是接收并处理连接的前端(或监听器)的名称。- "backend_name" 是被选中用于管理到服务器连接的后端(或监听器)的名称。如果未应用切换规则,这将与前端相同。- "server_name" 是连接最后发送到的服务器的名称,如果发生连接错误并进行了重新分派,这可能与第一个服务器不同。请注意,此服务器属于处理请求的后端。如果请求在到达服务器之前被中止,则显示 "<NOSRV>" 而不是服务器名称。如果请求被统计子系统拦截,则显示 "<STATS>"。- "Tq" 是等待客户端发送完整 HTTP 请求的总时间(毫秒),不计数据。如果连接在接收到完整请求之前被中止,则可以为 "-1"。它通常应该非常小,因为请求通常适合单个数据包。此处时间过长通常表示客户端和 haproxy 之间的网络问题。有关更多详细信息,请参见下面的“计时器”。- "Tw" 是在各种队列中等待的总时间(毫秒)。如果连接在到达队列之前被中止,则可以为 "-1"。有关更多详细信息,请参见下面的“计时器”。- "Tc" 是等待与最终服务器建立连接的总时间(毫秒),包括重试。如果请求在建立连接之前被中止,则可以为 "-1"。有关更多详细信息,请参见下面的“计时器”。- "Tr" 是等待服务器发送完整 HTTP 响应的总时间(毫秒),不计数据。如果请求在接收到完整响应之前被中止,则可以为 "-1"。它通常与服务器处理请求的时间相匹配,尽管可能会受到客户端发送到服务器的数据量的影响。"GET" 请求此处时间过长通常表示服务器过载。有关更多详细信息,请参见下面的“计时器”。- "Tt" 是从接受到最后关闭所经过的总时间(毫秒)。它涵盖了所有可能的处理。有一个例外,如果指定了 "option logasap",则时间计数在发出日志时停止。在这种情况下,值前面会加上一个 '+' 符号,表示最终值会更大。有关更多详细信息,请参见下面的“计时器”。- "status_code" 是返回给客户端的 HTTP 状态码。此状态通常由服务器设置,但当无法访问服务器或其响应被 haproxy 阻止时,也可能由 haproxy 设置。- "bytes_read" 是在发出日志时传输到客户端的总字节数。这包括 HTTP 标头。如果指定了 "option logasap",则此值将以 '+' 符号为前缀,表示最终值可能会更大。请注意,此值为 64 位计数器,因此日志分析工具必须能够处理它而不会溢出。- "captured_request_cookie" 是一个可选的 "name=value" 条目,表示客户端在请求中包含此 cookie。cookie 名称及其最大长度由前端配置中的 "capture cookie" 语句定义。当未设置该选项时,该字段为单个破折号 ('-')。只能捕获一个 cookie,它通常用于跟踪客户端和服务器之间的会话 ID 交换,以检测由于应用程序错误导致的客户端之间的会话交叉。有关更多详细信息,请参阅下面的“捕获 HTTP 标头和 cookie”部分。- "captured_response_cookie" 是一个可选的 "name=value" 条目,表示服务器在其响应中返回了一个 cookie。cookie 名称及其最大长度由前端配置中的 "capture cookie" 语句定义。当未设置该选项时,该字段为单个破折号 ('-')。只能捕获一个 cookie,它通常用于跟踪客户端和服务器之间的会话 ID 交换,以检测由于应用程序错误导致的客户端之间的会话交叉。有关更多详细信息,请参阅下面的“捕获 HTTP 标头和 cookie”部分。- "termination_state" 是会话结束时会话所处的状态。这表示会话状态,哪一方导致会话结束,原因(超时、错误等),就像在 TCP 日志中一样,以及最后两个字符中关于 cookie 持久性操作的信息。正常标志应以 "--" 开始,表示会话由任一端关闭,缓冲区中没有剩余数据。有关更多详细信息,请参见下面的“断开连接时的会话状态”。- "actconn" 是记录会话时进程上的并发连接总数。它有助于检测何时达到某些每个进程的系统限制。例如,如果 actconn 在发生多个连接错误时接近 512 或 1024,则很可能系统限制进程最多使用 1024 个文件描述符,并且它们都已被使用。请参阅 第 3 节“全局参数”以了解如何调整系统。- "feconn" 是记录会话时前端上的并发连接总数。它有助于估算维持高负载所需的资源量,并检测何时达到前端的 "maxconn"。通常当此值大幅增加时,是因为后端服务器出现拥塞,但有时也可能是由拒绝服务攻击引起的。- "beconn" 是记录会话时后端处理的并发连接总数。它包括服务器上活跃的并发连接总数以及在队列中等待的连接数。它有助于估算为支持给定应用程序的高负载所需的额外服务器数量。通常当此值大幅增加时,是因为后端服务器出现拥塞,但有时也可能是由拒绝服务攻击引起的。- "srv_conn" 是记录会话时服务器上仍然活跃的并发连接总数。它永远不会超过服务器配置的 "maxconn" 参数。如果此值经常接近或等于服务器的 "maxconn",则意味着流量调节经常被涉及,这表示服务器的 maxconn 值太低,或者没有足够的服务器以最佳响应时间处理负载。当只有一个服务器的 "srv_conn" 很高时,通常意味着该服务器存在一些问题,导致请求处理时间比其他服务器更长。- "retries" 是此会话在尝试连接服务器时遇到的连接重试次数。它通常应为零,除非在尝试连接时服务器正在被停止。频繁的重试通常表示 haproxy 和服务器之间存在网络问题,或者服务器上的系统积压配置不当,阻止新连接排队。此字段可以选择性地以 '+' 符号为前缀,表示会话在初始服务器上达到最大重试次数后经历了重新分派。在这种情况下,日志中出现的服务器名称是连接被重新分派到的服务器,而不是第一个服务器,尽管在哈希的情况下两者有时可能相同。因此,作为一般经验法则,当重试次数前存在 '+' 时,此计数不应归因于记录的服务器。- "srv_queue" 是在此请求之前在服务器队列中处理的请求总数。当请求未经过服务器队列时,它为零。它可以通过将队列中花费的时间除以队列中的请求数来估算近似的服务器响应时间。值得注意的是,如果一个会话经历重新分派并经过两个服务器队列,它们的位置将被累加。除非发生重新分派,否则请求不应同时通过服务器队列和后端队列。- "backend_queue" 是在此请求之前在后端的全局队列中处理的请求总数。当请求未经过全局队列时,它为零。它可以通过除以服务器的 "maxconn" 参数来估算平均队列长度,从而轻松转换为缺失的服务器数量。值得注意的是,如果一个会话经历重新分派,它可能会两次通过后端的队列,然后两个位置都将被累加。除非发生重新分派,否则请求不应同时通过服务器队列和后端队列。- "captured_request_headers" 是由于前端存在 "capture request header" 语句而在请求中捕获的标头列表。可以捕获多个标头,它们将由竖线('|')分隔。当未启用捕获时,大括号不会出现,导致剩余字段的移位。重要的是要注意,此字段可能包含空格,使用它需要比不使用时更智能的日志解析器。有关更多详细信息,请参阅下面的“捕获 HTTP 标头和 cookie”部分。- "captured_response_headers" 是由于前端存在 "capture response header" 语句而在响应中捕获的标头列表。可以捕获多个标头,它们将由竖线('|')分隔。当未启用捕获时,大括号不会出现,导致剩余字段的移位。重要的是要注意,此字段可能包含空格,使用它需要比不使用时更智能的日志解析器。有关更多详细信息,请参阅下面的“捕获 HTTP 标头和 cookie”部分。- "http_request" 是完整的 HTTP 请求行,包括方法、请求和 HTTP 版本字符串。不可打印字符被编码(请参见下面的“不可打印字符”部分)。这始终是最后一个字段,并且始终由引号分隔,是唯一可以包含引号的字段。如果向日志格式添加新字段,它们将在此字段之前添加。如果请求很大并且不适合标准 syslog 缓冲区(1024 个字符),则此字段可能会被截断。这就是为什么此字段必须始终保持在最后的原因。指令 log-format 允许您在 http 模式和 tcp 模式下自定义日志。它接受一个字符串作为参数。HAproxy 理解一些日志格式变量。% 前缀表示日志格式变量。变量可以使用大括号('{}')接受参数,多个参数在大括号内用逗号分隔。可以通过前缀 '+' 或 '-' 符号来添加或删除标志。特殊变量 "%o" 可用于将其标志传播到同一格式字符串上的所有其他变量。这对于带引号的字符串格式("Q")特别方便。如果一个变量名在方括号('[' .. ']')之间,那么它被用作一个样本表达式规则(见 第 7.3 节)。这对于添加一些不太常见的信息很有用,例如客户端的 SSL 证书的 DN,或者记录将用于在粘性表中存储条目的密钥。注意:空格必须被转义。空格字符被视作分隔符。为了发出一个字面意义的 '%',它必须前面有另一个 '%',结果是 '%%'。HAProxy 会自动合并连续的分隔符。标志有:* Q: 引用一个字符串 * X: 十六进制表示 (IP、端口、%Ts、%rt、%pid)log-format %T\ %t\ Some\ Text log-format %{+Q}o\ %t\ %s\ %{-Q}r
目前,默认的 HTTP 格式定义如下:log-format %ci:%cp\ [%t]\ %ft\ %b/%s\ %Tq/%Tw/%Tc/%Tr/%Tt\ %ST\ %B\ %CC\ \ %CS\ %tsc\ %ac/%fc/%bc/%sc/%rc\ %sq/%bq\ %hr\ %hs\ %{+Q}r 默认的 CLF 格式定义如下:log-format %{+Q}o\ %{-Q}ci\ -\ -\ [%T]\ %r\ %ST\ %B\ \"\"\ \"\"\ %cp\ \ %ms\ %ft\ %b\ %s\ \%Tq\ %Tw\ %Tc\ %Tr\ %Tt\ %tsc\ %ac\ %fc\ \ %bc\ %sc\ %rc\ %sq\ %bq\ %CC\ %CS\ \%hrl\ %hsl 默认的 TCP 格式定义如下:log-format %ci:%cp\ [%t]\ %ft\ %b/%s\ %Tw/%Tc/%Tt\ %B\ %ts\ \ %ac/%fc/%bc/%sc/%rc\ %sq/%bq 请参阅下表以了解当前定义的变量: +---+------+-----------------------------------------------+-------------+ | R | var | 字段名 (8.2.2 和 8.2.3 描述) | 类型 | +---+------+-----------------------------------------------+-------------+ | | %o | 特殊变量,将标志应用于所有后续变量 | | +---+------+-----------------------------------------------+-------------+ | | %B | bytes_read (从服务器到客户端) | 数字 | | H | %CC | captured_request_cookie (捕获的请求 cookie) | 字符串 | | H | %CS | captured_response_cookie (捕获的响应 cookie) | 字符串 | | | %H | hostname (主机名) | 字符串 | | H | %HM | HTTP 方法 (例如: POST) | 字符串 | | H | %HP | 不带查询字符串的 HTTP 请求 URI (路径) | 字符串 | | H | %HQ | HTTP 请求 URI 查询字符串 (例如: ?bar=baz) | 字符串 | | H | %HU | HTTP 请求 URI (例如: /foo?bar=baz) | 字符串 | | H | %HV | HTTP 版本 (例如: HTTP/1.0) | 字符串 | | | %ID | unique-id (唯一ID) | 字符串 | | | %ST | status_code (状态码) | 数字 | | | %T | gmt_date_time (GMT 日期时间) | 日期 | | | %Tc | Tc | 数字 | | | %Tl | local_date_time (本地日期时间) | 日期 | | H | %Tq | Tq | 数字 | | H | %Tr | Tr | 数字 | | | %Ts | timestamp (时间戳) | 数字 | | | %Tt | Tt | 数字 | | | %Tw | Tw | 数字 | | | %U | bytes_uploaded (从客户端到服务器) | 数字 | | | %ac | actconn (活动连接数) | 数字 | | | %b | backend_name (后端名称) | 字符串 | | | %bc | beconn (后端并发连接数) | 数字 | | | %bi | backend_source_ip (连接地址) | IP | | | %bp | backend_source_port (连接地址) | 数字 | | | %bq | backend_queue (后端队列) | 数字 | | | %ci | client_ip (接受地址) | IP | | | %cp | client_port (接受地址) | 数字 | | | %f | frontend_name (前端名称) | 字符串 | | | %fc | feconn (前端并发连接数) | 数字 | | | %fi | frontend_ip (接受地址) | IP | | | %fp | frontend_port (接受地址) | 数字 | | | %ft | frontend_name_transport ('~' 后缀表示 SSL) | 字符串 | | | %lc | frontend_log_counter (前端日志计数器) | 数字 | | | %hr | 捕获的请求头 (默认样式) | 字符串 | | | %hrl | 捕获的请求头 (CLF 样式) | 字符串列表 | | | %hs | 捕获的响应头 (默认样式) | 字符串 | | | %hsl | 捕获的响应头 (CLF 样式) | 字符串列表 | | | %ms | 接受日期的毫秒数 (左侧用0填充) | 数字 | | | %pid | PID (进程ID) | 数字 | | H | %r | http_request (HTTP 请求) | 字符串 | | | %rc | retries (重试次数) | 数字 | | | %rt | request_counter (HTTP请求或TCP会话计数器) | 数字 | | | %s | server_name (服务器名称) | 字符串 | | | %sc | srv_conn (服务器并发连接数) | 数字 | | | %si | server_IP (目标地址) | IP | | | %sp | server_port (目标地址) | 数字 | | | %sq | srv_queue (服务器队列) | 数字 | | S | %sslc| ssl_ciphers (SSL 密码套件, 例如: AES-SHA) | 字符串 | | S | %sslv| ssl_version (SSL 版本, 例如: TLSv1) | 字符串 | | | %t | date_time (带毫秒分辨率的日期时间) | 日期 | | | %ts | termination_state (终止状态) | 字符串 | | H | %tsc | termination_state with cookie status (带 cookie 状态的终止状态) | 字符串 | +---+------+-----------------------------------------------+-------------+ R = 限制:H = 仅 http 模式;S = 仅 SSL当传入连接因 SSL 握手或无效的 PROXY 协议头而失败时,haproxy 将使用较短的固定行格式记录该事件。默认情况下,日志以 LOG_INFO 级别发出,除非在后端设置了 "log-separate-errors" 选项,在这种情况下将使用 LOG_ERR 级别。如果设置了 "dontlognull" 选项,则不记录没有数据交换的连接(例如:探测)。格式如下:>>> Dec 3 18:27:14 localhost \ haproxy[6103]: 127.0.0.1:56059 [03/Dec/2012:17:35:10.380] frt/f1: \ SSL 握手期间连接错误 字段 格式 从以上示例中提取 1 process_name '[' pid ']:' haproxy[6103]: 2 client_ip ':' client_port 127.0.0.1:56059 3 '[' accept_date ']' [03/Dec/2012:17:35:10.380] 4 frontend_name "/" bind_name ":" frt/f1: 5 message SSL 握手期间连接错误 这些字段仅提供最少的信息来帮助调试连接失败。
一些高级日志记录选项经常被寻找,但仅通过查看各种选项不容易找到。这里是几个可以实现更好日志记录的选项的入口点。有关其用法的更多信息,请参考关键字参考。
一些监控工具对 haproxy 执行健康检查是很常见的。有时它会是像 LVS 或任何商业负载均衡器一样的第 3 层负载均衡器,有时它会是一个更完整的监控系统,如 Nagios。当测试非常频繁时,用户经常询问如何禁用这些检查的日志记录。有三种可能性:- 如果连接来自任何地方并且只是 TCP 探测,通常希望通过在前端设置 "option dontlognull" 来简单地禁用没有数据交换的连接的日志记录。它还禁用了端口扫描的日志记录,这可能是期望的,也可能不是。- 如果连接来自已知的源网络,使用 "monitor-net" 将此网络声明为仅用于监控。此网络中的任何主机 тогда只能执行健康检查,并且它们的请求将不会被记录。这通常适用于指定一系列设备,例如其他负载均衡器。- 如果测试是在已知的 URI 上执行的,使用 "monitor-uri" 将此 URI 声明为专用于监控。任何发送此请求的主机只会得到健康检查的结果,并且该请求将不会被记录。
在连接结束时记录日志的问题在于,您无法了解在非常长的会话期间发生了什么,例如远程终端会话或大文件下载。这个问题可以通过在前端指定 "option logasap" 来解决。Haproxy 将尽快记录日志,就在数据传输开始之前。这意味着在 TCP 的情况下,它仍然会记录到服务器的连接状态,在 HTTP 的情况下,它将在处理完服务器标头后立即记录。在这种情况下,报告的字节数是发送给客户端的标头字节数。为了避免与正常日志混淆,总时间字段和字节数都以 '+' 符号为前缀,这意味着实际数字肯定更大。
有时,将正常流量与错误日志分开会更方便,例如,为了简化从日志文件中监控错误。当使用 "log-separate-errors" 选项时,遇到错误、超时、重试、重新分派或 HTTP 状态码为 5xx 的连接,其 syslog 级别将从 "info" 提高到 "err"。这将帮助 syslog 守护进程将日志存储在一个单独的文件中。将错误也保留在正常流量文件中非常重要,这样日志顺序就不会改变。如果您已经配置了 syslog 守护进程将所有高于 "notice" 的日志存储在 "admin" 文件中,您也应该小心,因为 "err" 级别高于 "notice"。
虽然这乍听起来可能很奇怪,但一些大型站点必须处理每秒数千条日志,并且在长时间保持其完整性或在其中检测错误方面遇到困难。如果在前端设置了 "dontlog-normal" 选项,所有正常的连接都不会被记录。在这方面,正常连接定义为没有任何错误、超时、重试或重新分派的连接。在 HTTP 中,状态码也会被检查,状态为 5xx 的响应不被认为是正常的,也会被记录。当然,这样做是强烈不鼓励的,因为它会从日志中删除大部分有用的信息。只有在没有其他选择的情况下才这样做。
计时器在排查网络问题时提供了极大的帮助。所有值都以毫秒(ms)为单位报告。这些计时器应与会话终止标志结合使用。在 TCP 模式下,并在前端设置了“option tcplog”,会以“Tw/Tc/Tt”的形式报告 3 个控制点;在 HTTP 模式下,会以“Tq/Tw/Tc/Tr/Tt”的形式报告 5 个控制点: HTTP 模式下的计时事件: 第一个请求 第2个请求 |<---------------------->|<-------------- ... t t ... ---|----|----|----|----|----|----|-- : Tq Tw Tc Tr Td : Tq ... :<--------- Tt --------->: TCP 模式下的计时事件: TCP 会话 |<------------>| t t ---|----|----|----|--- | Tw Tc Td | |<---- Tt ---->| - Tq:获取客户端请求的总时间(仅限 HTTP 模式)。这是从接受客户端连接的时刻到代理收到最后一个 HTTP 头的时刻所经过的时间。值为“-1”表示从未见过头的末尾(空行)。这在客户端过早关闭或超时时发生。 - Tw:在队列中等待连接槽的总时间。它计算了后端队列和服务器队列的时间,并取决于队列大小以及服务器完成先前请求所需的时间。值为“-1”表示请求在到达队列之前被终止,这通常发生在无效或被拒绝的请求中。 - Tc:建立到服务器的 TCP 连接的总时间。这是从代理发送连接请求的时刻到服务器确认该请求的时刻,或者在 TCP SYN 数据包和相应的 SYN/ACK 返回数据包之间所经过的时间。值为“-1”表示连接从未建立。 - Tr:服务器响应时间(仅限 HTTP 模式)。这是从建立到服务器的 TCP 连接的时刻到服务器发送其完整响应头的时刻所经过的时间。它纯粹显示了其请求处理时间,不包括数据传输造成的网络开销。值得注意的是,当客户端有数据要发送到服务器时,例如在 POST 请求期间,时间已经开始计算,这可能会扭曲表观响应时间。因此,对于来自不受信任网络的客户端发起的 POST 请求,通常不应过分相信该字段。此处的值为“-1”表示从未见过响应头的末尾(空行),很可能是因为服务器在设法处理请求之前超时了。 - Tt:总会话持续时间,从代理接受它到两端都关闭的时刻。例外情况是指定了“logasap”选项。在这种情况下,它仅等于(Tq+Tw+Tc+Tr),并以“+”号为前缀。 从该字段中,我们可以推导出“Td”,即数据传输时间,方法是减去其他有效计时器: Td = Tt - (Tq + Tw + Tc + Tr) 值为“-1”的计时器必须从该方程式中排除。在 TCP 模式下,“Tq”和“Tr”也必须排除。请注意,“Tt”永远不能为负。 这些计时器为问题原因提供了宝贵的指示。由于 TCP 协议定义了 3、6、12... 秒的重传延迟,我们可以肯定,接近 3 秒倍数的计时器几乎总是与由于网络问题(线路、协商、拥塞)导致的数据包丢失有关。此外,如果“Tt”接近配置中指定的超时值,这通常意味着会话已因超时而中止。 最常见的情况: - 如果“Tq”接近 3000,则客户端和代理之间可能丢失了一个数据包。这在本地网络上非常罕见,但当客户端位于遥远的网络并发送大请求时可能会发生。有时,可能会出现比平常大的值,而没有任何网络原因。有时,在攻击期间或资源匮乏结束后,haproxy 可能会在几毫秒内接受数千个连接。接受这些连接所花费的时间将不可避免地略微延迟其他连接的处理,并且可能会发生这样的情况:在一次性接受数千个新连接后,测得的请求时间约为几十毫秒。 使用其中一种 keep-alive 模式可能会显示更长的请求时间,因为“Tq”也测量了等待附加请求所花费的时间。 - 如果“Tc”接近 3000,则在服务器连接阶段,服务器和代理之间可能丢失了一个数据包。这个值应该总是非常低,例如在本地网络上为 1 毫秒,在远程网络上小于几十毫秒。 - 如果“Tr”几乎总是低于 3000,除了一些罕见的似乎是平均值加上 3000 的值外,那么代理和服务器之间可能丢失了一些数据包。 - 如果“Tt”即使对于小字节数也很大,通常是因为客户端和服务器都没有决定关闭连接,例如因为双方都同意了 keep-alive 连接模式。为了解决这个问题,需要在前端或后端指定“option httpclose”。如果问题仍然存在,这意味着服务器忽略了“close”连接模式并期望客户端关闭。那么将需要使用“option forceclose”。 当在服务器上使用“maxconn”选项进行连接调节时,拥有尽可能小的“Tt”是很重要的,因为在释放另一个连接之前,不会有新的连接发送到服务器。 其他值得注意的 HTTP 日志情况('xx' 表示任何要忽略的值): Tq/Tw/Tc/Tr/+Tt 前端存在“option logasap”,并且日志在数据阶段之前发出。除了“Tt”比实际短之外,所有计时器都有效。 -1/xx/xx/xx/Tt 客户端未能及时发送完整的请求或过早中止。检查会话终止标志,然后检查“timeout http-request”和“timeout client”设置。 Tq/-1/xx/xx/Tt 无法处理请求,可能是因为服务器出现故障,或者因为请求无效或被 ACL 规则禁止。检查会话终止标志。 Tq/Tw/-1/xx/Tt 无法在服务器上建立连接。它要么主动拒绝了连接,要么在 Tt-(Tq+Tw) 毫秒后超时。检查会话终止标志,然后检查“timeout connect”设置。请注意,tarpit 操作可能会返回外观相似的模式,其中“Tw”等于客户端连接保持打开的时间。 Tq/Tw/Tc/-1/Tt 服务器已接受连接,但未及时返回完整的响应,或者在 Tt-(Tq+Tw+Tc) 毫秒后意外关闭了连接。检查会话终止标志,然后检查“timeout server”设置。
TCP 和 HTTP 日志在“termination_state”字段中提供了一个会话终止指示符,就在活动连接数之前。它在 TCP 模式下长 2 个字符,在 HTTP 模式下扩展到 4 个字符,每个字符都有特殊含义: - 第一个字符,一个代码,报告导致会话终止的第一个事件: C:TCP 会话被客户端意外中止。 S:TCP 会话被服务器意外中止,或者服务器明确拒绝了它。 P:会话被代理过早中止,因为强制执行连接限制,因为匹配了 DENY 过滤器,因为安全检查检测到并阻止了服务器响应中可能导致信息泄漏的危险错误(例如:可缓存的 cookie)。 L:会话由 haproxy 在本地处理,并且未传递给服务器。这发生在统计和重定向的情况下。 R:代理上的资源已耗尽(内存、套接字、源端口等)。通常,这出现在连接阶段,系统日志应包含精确错误的副本。如果发生这种情况,必须将其视为非常严重的异常,应尽快通过任何方式修复。 I:在自检期间,代理识别出内部错误。这应该永远不会发生,我们鼓励您报告任何包含此内容的日志,因为这几乎肯定是错误。在这种事件之后预防性地重新启动进程也是明智的,以防它是由内存损坏引起的。 D:会话被 haproxy 终止,因为服务器被检测为关闭,并且配置为在关闭时终止所有连接。 U:会话被 haproxy 在此备份服务器上终止,因为检测到活动服务器已启动,并且配置为在启动时终止所有备份连接。 K:会话被操作 haproxy 的管理员主动终止。 c:客户端超时已过期,同时等待客户端发送或接收数据。 s:服务器端超时已过期,同时等待服务器发送或接收数据。 -:正常会话完成,客户端和服务器都已关闭,缓冲区中没有任何内容。 - 第二个字符,关闭时的 TCP 或 HTTP 会话状态: R:代理正在等待来自客户端的完整、有效的请求(仅限 HTTP 模式)。没有任何内容发送到任何服务器。 Q:代理正在队列中等待连接槽。这只会在服务器设置了 'maxconn' 参数时发生。在由于连接到即将关闭的服务器的尝试失败而进行重分派后,它也可能发生在全球队列中。如果没有报告重分派,则没有对任何服务器进行连接尝试。 C:代理正在等待在服务器上建立连接。服务器最多可能已注意到连接尝试。 H:代理正在等待来自服务器的完整、有效的响应头(仅限 HTTP)。 D:会话处于数据阶段。 L:代理仍在向客户端传输最后的数据,而服务器已经完成。这种情况非常罕见,因为它只能在客户端在接收最后的数据包时死亡时发生。 T:请求被置于 tarpit 状态。它在整个“timeout tarpit”持续时间内或直到客户端关闭时都与客户端保持打开状态,这两者都将在“Tw”计时器中报告。 -:数据传输结束后正常会话完成。 - 第三个字符表示客户端是否提供了持久性 cookie(仅在 HTTP 模式下): N:客户端没有提供 cookie。这通常是新访问者的情况,因此计算日志中此标志出现的次数通常可以指示网站访问量的有效趋势。 I:客户端提供了一个与任何已知服务器都不匹配的无效 cookie。这可能是由最近的配置更改、HTTP/HTTPS 站点之间混合的 cookie、有条件地忽略持久性或攻击引起的。 D:客户端提供了一个指定已关闭服务器的 cookie,因此要么使用了“option persist”并且客户端被发送到该服务器,要么没有设置它,客户端被重分派到另一个服务器。 V:客户端提供了一个有效的 cookie,并被发送到关联的服务器。 E:客户端提供了一个有效的 cookie,但其最后日期比“maxidle” cookie 参数允许的要早,因此该 cookie 被视为已过期并被忽略。请求将被重新分派,就像没有 cookie 一样。 O:客户端提供了一个有效的 cookie,但其首次日期比“maxlife” cookie 参数允许的要早,因此该 cookie 被视为过旧并被忽略。请求将被重新分派,就像没有 cookie 一样。 U:存在一个 cookie,但它没有用于选择服务器,因为使用了其他服务器选择机制(通常是“use-server”规则)。 -:不适用(配置中未设置 cookie)。 - 最后一个字符报告了对服务器返回的持久性 cookie 执行了哪些操作(仅在 HTTP 模式下): N:服务器没有提供 cookie,也没有插入任何 cookie。 I:服务器没有提供 cookie,代理插入了一个。请注意,在“cookie insert”模式下,如果服务器提供了一个 cookie,它仍然会被覆盖并在此处报告为“I”。 U:代理更新了客户端呈现的 cookie 中的最后日期。这只能在带有“maxidle”的插入模式下发生。每当在与 cookie 中指示的日期不同的日期有活动时,它就会发生。如果发生任何其他更改,例如重分派,那么 cookie 将被标记为已插入。 P:服务器提供了一个 cookie,并按原样传输。 R:服务器提供的 cookie 被代理重写,这发生在“cookie rewrite”或“cookie prefix”模式下。 D:服务器提供的 cookie 被代理删除。 -:不适用(配置中未设置 cookie)。 前两个标志的组合提供了大量关于会话终止时发生了什么以及为什么终止的信息。它有助于检测服务器饱和、网络问题、本地系统资源不足、攻击等... 最常见的终止标志组合如下所示。它们按字母顺序排序,小写字母紧跟在大写字母之后,以便于查找和理解。 标志 原因 -- 正常终止。 CC 在与服务器建立连接之前,客户端中止了连接。当 haproxy 尝试连接到最近关闭(或未检查)的服务器,并且客户端在 haproxy 等待服务器响应或“timeout connect”到期时中止,可能会发生这种情况。 CD 客户端在数据传输期间意外中止。这可能是由浏览器崩溃、客户端和 haproxy 之间的中间设备决定主动中断连接、客户端和 haproxy 之间的网络路由问题,或者由客户端首先终止的服务器和客户端之间的 keep-alive 会话引起的。 cD 客户端在“timeout client”延迟内既没有发送也没有确认任何数据。这通常是由客户端的网络故障或客户端不干净地离开网络引起的。 CH 客户端在等待服务器开始响应时中止。可能是服务器响应时间过长,或者客户端过快地点击了“停止”按钮。 cH 在 POST 请求期间等待客户端数据时,“timeout client”超时。这有时是由 PPPoE 网络的 TCP MSS 值过大,无法传输完整大小的数据包引起的。当客户端超时小于服务器超时并且服务器响应时间过长时,也可能发生这种情况。 CQ 客户端在会话排队等待有足够空闲槽的服务器接受它时中止。这可能是因为所有服务器都已饱和,或者分配的服务器响应时间过长。 CR 客户端在发送完整的 HTTP 请求之前中止。很可能是使用 telnet 客户端手动键入的请求,并过早中止。此处的 HTTP 状态代码可能是 400。有时这也可能是由于 IDS 终止了 haproxy 和客户端之间的连接引起的。“option http-ignore-probes”可用于忽略没有任何数据传输的连接。 cR 在客户端发送完整的 HTTP 请求之前,“timeout http-request”超时。这有时是由客户端 PPPoE 网络的 TCP MSS 值过大,无法传输完整大小的数据包引起的,或者由客户端手动发送请求且键入速度不够快,或忘记在请求末尾输入空行引起的。此处的 HTTP 状态代码可能是 408。注意:最近,一些浏览器开始实施“预连接”功能,即推测性地连接到一些最近访问过的网站,以防用户想要访问它们。这导致与网站建立许多连接,如果超时先到期,则最终导致 408 请求超时,或者当浏览器决定先关闭它们时,则导致 400 错误请求。这些会污染日志并增加错误计数器。据报道,某些版本的某些浏览器甚至会显示错误代码。可以通过在前端添加“option http-ignore-probes”来解决这种行为的不良影响,从而完全忽略零数据传输的连接。但这肯定会隐藏遇到连接问题的人的错误。 CT 客户端在其会话被置于 tarpit 状态时中止。检查这是否发生在有效请求上很重要,以确保没有编写错误的 tarpit 规则。如果发生了很多这样的情况,那么将“timeout tarpit”值降低到接近报告的平均“Tw”计时器的值可能是有意义的,以免为少数攻击者消耗资源。 LR 请求被 haproxy 拦截并在本地处理。通常这意味着这是一个重定向或统计请求。 SC 服务器或其与 haproxy 之间的设备明确拒绝了 TCP 连接(代理收到了 TCP RST 或 ICMP 消息作为回报)。在某些情况下,也可能是网络堆栈告诉代理服务器不可达(例如:没有路由,或本地网络上没有 ARP 响应)。当这种情况在 HTTP 模式下发生时,状态代码可能是 502 或 503。 sC 在与服务器的连接完成之前,“timeout connect”超时。当这种情况在 HTTP 模式下发生时,状态代码可能是 503 或 504。 SD 与服务器的连接在数据传输期间因错误而中断。这通常意味着 haproxy 在与服务器交换数据时从服务器收到了 RST 或从中间设备收到了 ICMP 消息。这可能是由服务器崩溃或中间设备的网络问题引起的。 sD 在数据阶段,服务器在“timeout server”设置的时间内既没有发送也没有确认任何数据。这通常是由服务器之前的 L4 设备(防火墙、负载均衡器等)上的超时时间过短,以及客户端和服务器之间维护的 keep-alive 会话在 haproxy 上首先过期引起的。 SH 服务器在发送其完整的 HTTP 响应头之前中止,或者在处理请求时崩溃。由于服务器在此时中止非常罕见,因此最好检查其日志以控制它是否崩溃以及原因。记录的请求可能指示一小组有问题的请求,表明应用程序中存在错误。有时这也可能是由于 IDS 终止了 haproxy 和服务器之间的连接引起的。 sH 在服务器返回其响应头之前,“timeout server”超时。这是最常见的异常,表明事务时间过长,可能是由服务器或数据库饱和引起的。直接的解决方法是增加“timeout server”设置,但重要的是要记住,用户体验会受到这些长响应时间的影响。唯一的长期解决方案是修复应用程序。 sQ 会话在队列中花费了太多时间并已过期。请参阅“timeout queue”和“timeout connect”设置,以了解如果这种情况发生得太频繁该如何解决。如果它经常在短时间内大量发生,则可能表明受影响的服务器由于 I/O 或数据库拥塞或由外部攻击引起的饱和而存在普遍性问题。 PC 代理拒绝与服务器建立连接,因为在尝试连接时已达到进程的套接字限制。可以增加配置中的全局“maxconn”参数,使其不再发生。这种情况非常罕见,并且可能在手动强制全局“ulimit-n”参数时发生。 PD 在服务器发出其头之后,代理阻止了请求或响应中格式不正确的块编码消息。在大多数情况下,这将表示从服务器到客户端的无效消息。Haproxy 支持最大为 2GB - 1(2147483647 字节)的块大小。任何更大的大小都将被视为错误。 PH 代理阻止了服务器的响应,因为它无效、不完整、危险(缓存控制)或匹配安全过滤器。在任何情况下,都会向客户端发送 HTTP 502 错误。此错误的一个可能原因是 HTTP 头名称中的语法无效,包含未经授权的字符。也可能(但相当罕见)的是,由于语法无效,代理在服务器响应之前阻止了来自客户端的块编码请求。在这种情况下,会向客户端发送 HTTP 400 错误并在日志中报告。 PR 代理阻止了客户端的 HTTP 请求,要么是因为 HTTP 语法无效,在这种情况下它向客户端返回了 HTTP 400 错误,要么是因为匹配了 deny 过滤器,在这种情况下它返回了 HTTP 403 错误。 PT 代理阻止了客户端的请求,并在向其返回 500 服务器错误之前将其连接置于 tarpit 状态。没有向服务器发送任何内容。连接保持打开的时间由“Tw”计时器字段报告。 RC 本地资源已耗尽(内存、套接字、源端口),导致无法与服务器建立连接。错误日志将精确地说明缺少什么。这种情况非常罕见,只能通过适当的系统调优来解决。 最后两个标志的组合提供了大量关于客户端、服务器和 haproxy 如何处理持久性的信息。这对于在用户抱怨必须重新进行身份验证时排查断开连接问题非常重要。常见的标志有: -- 未启用持久性 cookie。 NN 客户端没有提供 cookie,响应中也没有插入 cookie。例如,这可能是在带有“postonly”设置的 GET 请求的插入模式下。 II 客户端提供了一个指定无效服务器的 cookie,响应中插入了一个有效的 cookie。这通常发生在从配置中删除“server”条目时,因为它的 cookie 值可以由客户端在没有其他服务器知道它的情况下呈现。 NI 客户端没有提供 cookie,响应中插入了一个。这通常发生在“insert”模式下每个用户的第一个请求,这使其成为计算真实用户的简便方法。 VN 客户端提供了一个 cookie,响应中没有插入 cookie。这发生在客户端已经拥有 cookie 的大多数响应中。 VU 客户端提供了一个 cookie,其上次访问日期不是最新的,因此在响应中提供了一个更新的 cookie。如果根本没有日期,或者有日期但未设置“maxidle”参数,从而使 cookie 可以切换到无限时间,也可能发生这种情况。 EI 客户端提供了一个 cookie,其上次访问日期对于“maxidle”参数来说太旧了,因此该 cookie 被忽略,并在响应中插入了一个新的 cookie。 OI 客户端提供了一个 cookie,其首次访问日期对于“maxlife”参数来说太旧了,因此该 cookie 被忽略,并在响应中插入了一个新的 cookie。 DI cookie 指定的服务器已关闭,选择了新的服务器,并在响应中发出了新的 cookie。 VI cookie 指定的服务器未标记为死亡,但无法访问。发生了重分派并选择了另一个服务器,然后在响应中进行了通告。
为了在查阅日志时避免给日志分析工具或终端带来麻烦,不可打印的字符不会按原样发送到日志文件中,而是会转换为其 ASCII 码的两位十六进制表示,并以字符“#”为前缀。唯一可以不经转义直接记录的字符范围是 32 到 126(含)。显然,转义字符“#”本身也会被编码以避免任何歧义(“#23”)。字符“"”也是如此,它会变成“#22”,以及在记录头时,“{”、“|”和“}”也是如此。请注意,空格字符(' ')在头中不被编码,这可能会给依赖空格计数来定位字段的工具带来问题。一个包含空格的典型头是“User-Agent”。最后,据观察,一些 syslog 守护进程(如 syslog-ng)会用反斜杠('\')来转义引号('\"')。可以安全地执行反向操作,因为日志中其他任何地方都不会出现引号。Cookie 捕获简化了对完整用户会话的跟踪。这可以通过在前端使用“capture cookie”语句来实现。更多详情请参考第 4.2 节。只能捕获一个 cookie,并且同一个 cookie 将同时在请求(“Cookie:”头)和响应(“Set-Cookie:”头)中进行检查。相应的值将报告在 HTTP 日志的“captured_request_cookie”和“captured_response_cookie”位置(请参阅关于 HTTP 日志格式的第 8.2.3 节)。当任一 cookie 未被看到时,一个破折号('-')将取代该值。这样,就很容易检测到用户何时切换到新会话,例如,因为服务器将为其重新分配一个新的 cookie。也可以检测服务器是否意外地向客户端设置了错误的 cookie,从而导致会话交叉。
# 捕获第一个名称以“ASPSESSION”开头的 cookie capture cookie ASPSESSION len 32 # 捕获第一个名称正好是“vgnvisitor”的 cookie capture cookie vgnvisitor= len 32
头捕获对于跟踪由上层代理设置的唯一请求标识符、虚拟主机名、用户代理、POST 内容长度、引荐来源等非常有用。在响应中,可以搜索有关响应长度、服务器如何要求缓存行为的信息,或重定向期间的对象位置。头捕获是使用前端的“capture request header”和“capture response header”语句执行的。请参阅它们在第 4.2 节中的定义以获取更多详情。可以同时包含请求头和响应头。不存在的头将记录为空字符串,如果一个头出现多次,则只会记录其最后一次出现。请求头按其声明的顺序分组在大括号“{”和“}”内,并用竖线“|”分隔,不带任何空格。响应头遵循相同的表示方式,但在请求头块之后的一个空格后显示。这些块显示在日志中的 HTTP 请求之前。作为一种特殊情况,可以在 TCP 前端中指定 HTTP 头捕获。其目的是启用对将在 HTTP 后端解析的头的日志记录,如果请求随后切换到此 HTTP 后端。
# 此实例链接到出站代理 listen proxy-out mode http option httplog option logasap log global server cache1 192.168.1.1:3128 # 记录虚拟服务器的名称 capture request header Host len 20 # 记录 POST 期间上传的数据量 capture request header Content-Length len 10 # 记录引荐来源的开头 capture request header Referer len 20 # 服务器名称(仅对出站代理有用) capture response header Server len 20 # 记录 content-length 对“option logasap”很有用 capture response header Content-Length len 10 # 记录响应上预期的缓存行为 capture response header Cache-Control len 8 # Via 头将报告下一个代理的名称 capture response header Via len 20 # 记录重定向期间的 URL 位置 capture response header Location len 20 >>> Aug 9 20:26:09 localhost \ haproxy[2022]: 127.0.0.1:34014 [09/Aug/2004:20:26:09] proxy-out \ proxy-out/cache1 0/0/0/162/+162 200 +350 - - ---- 0/0/0/0/0 0/0 \ {fr.adserver.yahoo.co||http://fr.f416.mail.} {|864|private||} \ "GET http://fr.adserver.yahoo.com/" >>> Aug 9 20:30:46 localhost \ haproxy[2022]: 127.0.0.1:34020 [09/Aug/2004:20:30:46] proxy-out \ proxy-out/cache1 0/0/0/182/+182 200 +279 - - ---- 0/0/0/0/0 0/0 \ {w.ods.org||} {Formilux/0.1.8|3495|||} \ "GET http://trafic.1wt.eu/ HTTP/1.1" >>> Aug 9 20:30:46 localhost \ haproxy[2022]: 127.0.0.1:34028 [09/Aug/2004:20:30:46] proxy-out \ proxy-out/cache1 0/0/2/126/+128 301 +223 - - ---- 0/0/0/0/0 0/0 \ {www.sytadin.equipement.gouv.fr||http://trafic.1wt.eu/} \ {Apache|230|||http://www.sytadin.} \ "GET http://www.sytadin.equipement.gouv.fr/ HTTP/1.1"
这些是附有解释的真实日志示例。其中一些是手动编造的。为了便于阅读,syslog 部分已被删除。它们的唯一目的是解释如何解读它们。 >>> haproxy[674]: 127.0.0.1:33318 [15/Oct/2003:08:31:57.130] px-http \ px-http/srv1 6559/0/7/147/6723 200 243 - - ---- 5/3/3/1/0 0/0 \ "HEAD / HTTP/1.0" => 通过“telnet”手动输入的长时间请求(6.5秒)。服务器在 147 毫秒内回复,会话正常结束('----') >>> haproxy[674]: 127.0.0.1:33319 [15/Oct/2003:08:31:57.149] px-http \ px-http/srv1 6559/1230/7/147/6870 200 243 - - ---- 324/239/239/99/0 \ 0/9 "HEAD / HTTP/1.0" => 同上,但请求在全局队列中排在其他 9 个请求之后,并在那里等待了 1230 毫秒。 >>> haproxy[674]: 127.0.0.1:33320 [15/Oct/2003:08:32:17.654] px-http \ px-http/srv1 9/0/7/14/+30 200 +243 - - ---- 3/3/3/1/0 0/0 \ "GET /image.iso HTTP/1.0" => 请求进行长时间数据传输。指定了“logasap”选项,因此日志在传输数据之前生成。服务器在 14 毫秒内回复,向客户端发送了 243 字节的头,从接受到第一个数据字节的总时间是 30 毫秒。 >>> haproxy[674]: 127.0.0.1:33320 [15/Oct/2003:08:32:17.925] px-http \ px-http/srv1 9/0/7/14/30 502 243 - - PH-- 3/2/2/0/0 0/0 \ "GET /cgi-bin/bug.cgi? HTTP/1.0" => 代理阻止了一个服务器响应,原因可能是“rspdeny”或“rspideny”过滤器,或者是因为响应格式不正确且不符合 HTTP 规范,或者因为它阻止了可能被缓存的敏感信息。在这种情况下,响应被替换为“502 bad gateway”。标志(“PH--”)告诉我们是 haproxy 决定返回 502,而不是服务器。 >>> haproxy[18113]: 127.0.0.1:34548 [15/Oct/2003:15:18:55.798] px-http \ px-http/<NOSRV> -1/-1/-1/-1/8490 -1 0 - - CR-- 2/2/2/0/0 0/0 "" => 客户端从未完成其请求并在 8.5 秒后自行中止(“C---”),而代理正在等待请求头(“-R--”)。没有任何内容发送到任何服务器。 >>> haproxy[18113]: 127.0.0.1:34549 [15/Oct/2003:15:19:06.103] px-http \ px-http/<NOSRV> -1/-1/-1/-1/50001 408 0 - - cR-- 2/2/2/0/0 0/0 "" => 客户端从未完成其请求,该请求在 50 秒后因超时而中止(“c---”),而代理正在等待请求头(“-R--”)。没有向任何服务器发送任何内容,但代理可以向客户端发送 408 返回码。 >>> haproxy[18989]: 127.0.0.1:34550 [15/Oct/2003:15:24:28.312] px-tcp \ px-tcp/srv1 0/0/5007 0 cD 0/0/0/0/0 0/0 => 此日志是使用“option tcplog”生成的。客户端在 5 秒后超时(“c----”)。 >>> haproxy[18989]: 10.0.0.1:34552 [15/Oct/2003:15:26:31.462] px-http \ px-http/srv1 3183/-1/-1/-1/11215 503 0 - - SC-- 205/202/202/115/3 \ 0/0 "HEAD / HTTP/1.0" => 请求耗时 3 秒完成(可能是网络问题),并且在 4 次 2 秒的尝试后(配置为 'retries 3'),与服务器的连接失败('SC--'),并且没有重分派(否则我们会看到“/+3”)。向客户端返回了状态码 503。此服务器上有 115 个连接,此代理上有 202 个连接,全局进程上有 205 个连接。服务器可能因为已建立的连接过多而拒绝了连接。