haproxy的主配置文件为/etc/haproxy/haproxy.cfg ,其主要分为global配置段(用于设定全局配置参数)和proxy相关配置段(如defaults,listen,frontend和backend)。global配置中的参数为进程级别的参数,且通常与运行的OS相关,proxy代理配置主要和haproxy及后端server相关。一个简单的配置示例如下:

 1global
 2    daemon
 3    maxconn 25600
 4defaults
 5    mode http
 6    timeout connect 5000ms
 7    timeout client 50000ms
 8    timeout server 50000ms
 9frontend http-in
10    bind *:80
11    default_backend servers
12backend servers
13    server server1 127.0.0.1:8080 maxconn 32

以上配置了一个监听在所有接口的80端口上HTTP proxy服务,它转发所有的请求至后端监听在127.0.0.1:8080上。

一、全局配置

1、进程管理及安全相关的参数

chroot用于修改haproxy的工作目录至指定的目录并在放弃权限之前执行chroot()操作,可以提升haproxy的安全级别,不过需要注意的是要确保指定的目录为空目录且任何用户均不能有写权限:

chroot <jail dir>
– daemon # 让Haproxy以守护进程的方式工作于后台
– gid # 以指定的GID运行haproxy
– group # 同GID,不过指定的是组名
– log

<

address [max level [min level]] # 定义全局的syslog服务器,最多可定义两个
– log-send-hostname [string] # 在syslog信息的首部添加当前主机名,默认是使用当前主机名
– nbporc # 指定启动的haproxy进程个数,默认只启动一个,一般只在单进程仅能打开少数文件描述符的场景才使用多进程模式
– pidfile # pid文件
– uid # 以指定的UID身份运行进程
– unlimit -n # 设定每进程能够打开的最大文件描述符数据,默认情况下其会自动进行计算,不推荐修改此项
– user # 同UID,但使用用户名
– stats socket /var/lib/haproxy/status # 访问stats时,使用socket调用的文件
– node # 定义当前节点的名称,用于HA场景中多haproxy进程共享同一个IP地址时使用
– description # 当前实例的描述信息

2、性能调整相关的参数

 1maxconn <number>  # 设定每个haproxy进程所接受的最大并发连接数,等同于ulimit -n
 2# maxpipes指定haproxy使用Pipe完成基于内核的TCP报文重组,用于设定每进行所允许使用的最大Pipe个数,每个pipe使用两个文件描述符
 3maxpipes <number>
 4noepoll           # 在linux系统上禁用epoll机制
 5nokqueue          # 在BSD系统上禁用kqueue机制
 6nopoll            # 禁用poll机制
 7nosepoll          # 在linux禁用启发式epoll机制
 8# nosplice指禁止在Linux套按字上使用内核tcp重组,这会导致更多的recv/send系统调用,不过在2.6.25-28系统的内核上,tcp重组功能有bug
 9nosplice
10#spread-checks用在haproxy后端有着众多服务器的场景中,在精确的时间间隔后统一对众服务器进行健康状况检查可能会带来意外问题;
11此选项用于将其检查的时间间隔长度上增加或减小一定的随机时长
12spread-checks <0..50,in percent>
13#设定buffer的大小,同样的内存条件下,较小的值可以让haproxy有能力接受更多的并发连接,
14较大的值可以让某些应用程序使用较大的cookie信息;默认为16384,其可以在编译时修改,
15不过强烈建议使用默认值
16tune.bufsize <number>
17tune.chksize <number>   检查缓冲的大小,专用检测用户的请求首部信息,建议默认值
18tune.maxaccept <number> 一次性一次交由多少个请求给进程
19# maxpollevents设定一次系统调用可以处理的事件最大数,默认值取决于OS;其值小于200时可节约带宽,但会略微增大网络延迟,
20而大于200时会降低延迟,但会稍稍增加网络带宽的占用量;
21tune.maxpollevents <number>
22# maxrewrite设定首部重写或追加而预留的缓冲空间,建议使用1024左右的大小,在需要使用更大的空间时,haproxy全自动增加其值
23tune.maxrewrite <number>
24debug : 调度模式
25quiet : 静默模式

二、代理配置

<pre data-language="XML">```markup
# defaults用于为所有其它配置段提供默认参数,这配置默认配置参数可由下一个defaults所重新设定
defaults <name>
# frontend用于定义一系列监听的套拼字,这些套按字可接受客户端请求并与之建立连接
frontend <name>
# backend用于定义一系列“后端”服务器,代理将会将对应客户端的请求转发至这些服务器
backend <name>
# listen通过关联“前端”和“后端”定义了一个完整的代理 ,通常只对TCP流量有效
listen <name>

注:所有代理的名称只能使用大写字母、小写字母、数字、-(中线)、\_(下划线)、.(点号)和:(冒号)。此外,ACL名称会区分字母大小写。

### 三、关键字部分

#### 1、balance

定义负载算法,可用于defaults,listen,backend段。其分为动态调整和静态调整。动态:权重可动态调整,服务器自己调整;静态:调整权重不会实时生效,只有重启才会生效。目前其有九种算法(---page by www.361way.com,防扒取):

**roundrobin**:基于权重进行轮叫,在服务器的处理时间保持均匀分布时,这是最平衡、最公平的算法。此算法是动态的,这表示其权重可以在运行时进行调整,不过,在设计上,每个后端服务器仅能最多接受4128个连接;

**static-rr**:基于权重进行轮叫,与roundrobin类似,但是为静态方法,在运行时调整其服务器权重不会生效;不过,其在后端服务器连接数上没有限制;

**leastconn**:新的连接请求被派发至具有最少连接数目的后端服务器;在有着较长时间会话的场景中推荐使用此算法,如LDAP、SQL等,其并不太适用于较短会话的应用层协议,如HTTP;此算法是动态的,可以在运行时调整其权重;

**first**:其会匹配server的id,id值设置低的先进行连接,直到达到该服务器的maxconn,再使用第二台。比较适用于RDP、IMAP、HTTP等长连接及云环境下;

**source**:将请求的源地址进行hash运算,并由后端服务器的权重总数相除后派发至某匹配的服务器;这可以使得同一个客户端IP的请求始终被派发至某特定的服务器;不过,当服务器权重总数发生变化时,如某服务器宕机或添加了新的服务器,许多客户端的请求可能会被派发至与此前请求不同的服务器;常用于负载均衡无cookie功能的基于TCP的协议;其默认为静态,不过也可以使用hash-type修改此特性;

**uri**:对URI的左半部分(“问题”标记之前的部分)或整个URI进行hash运算,并由服务器的总权重相除后派发至某匹配的服务器;这可以使得对同一个URI的请求总是被派发至某特定的服务器,除非服务器的权重总数发生了变化;此算法常用于代理缓存或反病毒代理以提高缓存的命中率;需要注意的是,此算法仅应用于HTTP后端服务器场景;其默认为静态算法,不过也可以使用hash-type修改此特性;

**uri-param**:通过为URL指定的参数在每个HTTP GET请求中将会被检索;如果找到了指定的参数且其通过等于号“=”被赋予了一个值,那么此值将被执行hash运算并被服务器的总权重相除后派发至某匹配的服务器;此算法可以通过追踪请求中的用户标识进而确保同一个用户ID的请求将被送往同一个特定的服务器,除非服务器的总权重发生了变化;如果某请求中没有出现指定的参数或其没有有效值,则使用轮叫算法对相应请求进行调度;此算法默认为静态的,不过其也可以使用hash-type修改此特性;

**hdr(name)**:对于每个HTTP请求,通过指定的HTTP首部将会被检索;如果相应的首部没有出现或其没有有效值,则使用轮叫算法对相应请求进行调度;其有一个可选选项“use\_domain\_only”,可在指定检索类似Host类的首部时仅计算域名部分(比如通过www.361way.com来说,仅计算361way字符串的hash值)以降低hash算法的运算量;此算法默认为静态的,不过其也可以使用hash-type修改此特性;

**rdp-cookie**:其将looked up and hashed每个近入的TCP连接,并将该请求和之前的策略作匹配,这样对于同一个用户发来的请求,可以发往后端同一台realserver上,如果cookie not found,其将使用roundrobin 代替。

balance使用示例如下:

```bash
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

2、bind

此指令仅能用于frontend和listen区段,用于定义一个或几个监听的套接字,其使用如下:

1# 语法
2bind [<address>]:<port-range> [,...]
3bind [<address>]:<port_range> [, ...] interface <interface>
4# 示例
5frontend  main
6    bind *:80
7    bind *:8080
8    acl url_static       path_beg       -i /static /images /javascript /stylesheets
9    acl url_static       path_end       -i .jpg .gif .png .css .js

3、mode

设定实例的运行模式或协议。当实现内容交换时,前端和后端必须工作于同一种模式(一般说来都是HTTP模式),否则将无法启动实例。其用法为:mode {tcp|http|health}

tcp:实例运行于纯TCP模式,在客户端和服务器端之间将建立一个全双工的连接,且不会对7层报文做任何类型的检查;此为默认模式,通常用于SSL、SSH、SMTP等应用;
http:实例运行于HTTP模式,客户端请求在转发至后端服务器之前将被深度分析,所有不与RFC格式兼容的请求都会被拒绝;
health:实例工作于health模式,其对入站请求仅响应“OK”信息并关闭连接,且不会记录任何日志信息;此模式将用于响应外部组件的健康状态检查请求;目前业讲,此模式已经废弃,因为tcp或http模式中的monitor关键字可完成类似功能

4、hash-type

定义用于将hash码映射至后端服务器的方法;其不能用于frontend区段;可用方法有map-based和consistent,在大多数场景下推荐使用默认的map-based方法。用法

1用法:hash-type <method>
2示例:
3backend app
4    balance     uri
5    hash-type consistent
6    server  srv1 172.16.36.70:80 check
7    server  srv2 172.16.36.71:80 check

map-based:hash表是一个包含了所有在线服务器的静态数组。其hash值将会非常平滑,会将权重考虑在列,但其为静态方法,对在线服务器的权重进行调整将不会生效,这意味着其不支持慢速启动。此外,挑选服务器是根据其在数组中的位置进行的,因此,当一台服务器宕机或添加了一台新的服务器时,大多数连接将会被重新派发至一个与此前不同的服务器上,对于缓存服务器的工作场景来说,此方法不甚适用。

consistent:hash表是一个由各服务器填充而成的树状结构;基于hash键在hash树中查找相应的服务器时,最近的服务器将被选中。此方法是动态的,支持在运行时修改服务器权重,因此兼容慢速启动的特性。添加一个新的服务器时,仅会对一小部分请求产生影响,因此,尤其适用于后端服务器为cache的场景。不过,此算法不甚平滑,派发至各服务器的请求未必能达到理想的均衡效果,因此,可能需要不时的调整服务器的权重以获得更好的均衡性。

5、log

为每个实例启用事件和流量日志,因此可用于所有区段。每个实例最多可以指定两个log参数,不过,如果使用了“log global”且”global”段已经定了两个log参数时,多余的log参数将被忽略。用法如下:

1log global
2log <address> <facility> [<level>][<minlevel>]

6、maxconn

设定一个前端的最大并发连接数,因此,其不能用于backend区段。对于大型站点来说,可以尽可能提高此值以便让haproxy管理连接队列,从而避免无法应答用户请求。当然,此最大值不能超出“global”段中的定义。此外,需要留心的是,haproxy会为每个连接维持两个缓冲,每个缓冲的大小为8KB,再加上其它的数据,每个连接将大约占用17KB的RAM空间。这意味着经过适当优化后,有着1GB的可用RAM空间时将能维护40000-50000并发连接。如果为指定了一个过大值,极端场景下,其最终占据的空间可能会超出当前主机的可用内存,这可能会带来意想不到的结果;因此,将其设定了一个可接受值方为明智决定。其默认为2000。用法如下: maxconn <conns>

7、default_backend

在没有匹配的”use_backend”规则时为实例指定使用的默认后端,因此,其不可应用于backend区段。在”frontend”和”backend”之间进行内容交换时,通常使用”use-backend”定义其匹配规则;而没有被规则匹配到的请求将由此参数指定的后端接收。配置示例如下:

1frontend main *:80
2    acl url_static path_beg -i /static /images /javascript /stylesheets
3    acl url_static path_end -j .jpg .gif .png .css .js
4    use_backend static if url_static
5    default_backend app

8、server

为后端声明一个server,其用法和示例如下:

1用法:
2server <name> <address>[:port][param*]
3示例:
4server srv1 172.16.100.6:80 redir http://imageserver.361way.com check

server对应的参数如下:

 1backup : 设定为备用服务器,即sorry server
 2check : 健康状态检测
 3    inter <delay> : 设定健康状态检测时的时间,默认为2000,单位为ms
 4    fall <number> : 从up-->down(soft state-->hard state),默认为3次
 5    rise <number> : 从down-->up的次数
 6cookie <value> : 为server设定个cookie值,会话级别的cookie,基于cookie的原绑定方式,会在响应报文中的cookie头后添加相应的cookie值
 7maxconn :此服务器接受的并发连接最大数值
 8maxqueue : 请求队列的最大长度
 9observer <mode> : 通过流量判断后端服务器的状态,默认为禁用,其支持4层和7层
10weight <number> : 默认为1,最大为256,0表示不被调用
11redir <prefix> : 启用重定向功能,所有发往此服务器的GET和HEAD请求,均以302响应,在prefix最后不能加/,且不能使用相对地址

9、opttion check

健康状态检测方法定义,其用法示例如下:

 1用法:
 2option httpchk
 3option httpchk <uri>
 4option httpchk <method> <uri>
 5option httpchk <mothod> <uri> <version> :不能用于frontend段
 6用例:
 7backend https_relay
 8    mode tcp
 9    option check OPTIONS * HTTP/1.1\r\nHost:\ www.361way.com
10    server apache1 172.16.36.70 check prot 80

10、capture request header

捕获并记录指定的请求首部最近 一次出现时的第一个值,仅能用于“frontend”和“listen”区段。捕获的首部值使用花括号{}括起来后添加进日志中。如果需要捕获多个首部值,它们将以指定的次序出现在日志文件中,并以竖线“|”作为分隔符。不存在的首部记录为空字符串,最常需要捕获的首部包括在虚拟主机环境中使用的“Host”、上传请求首部中的“Content-length”、快速区别真实用户和网络机器人的“User-agent”,以及代理环境中记录真实请求来源的“X-Forward-For”。可以捕获的请求首部的个数没有限制,但每个捕获最多只能记录64个字符。为了保证同一个frontend中日志格式的统一性,首部捕获仅能在frontend中定义。使用方法如下:

1capture request header <name> len <length>

11、capture response header

捕获并记录响应首部,其格式和要点同请求首部。用法如下:

1capture response header <name> len <length>

12、stats enable

启用基于程序编译时默认设置的统计报告,不能用于frontend段。使用示例如下:

1listen statistics  #定义listen区段名称
2bind *:9090        #定义监听端口
3stats enable    #启用stats
4stats hide-version #隐藏版本
5stats refresh 10s #刷新时间
6stats uri /haproxyadmin?stats    #stats的URI地址
7stats realm "HAProxy\ statistics" #stats的登陆提示信息
8stats auth zhenping:123321 # 定义用户名和密码
9stats admin if TRUE        #如果用户验证成功,就给予admin权限

13、option httplog

启用记录HTTP请求,会话状态和计时器的功能,默认情况下,日志输入格式非常简陋,因为其仅包括源地址、目标地址和实例名称,而“option httplog”参数将会使得日志格式变得丰富许多,其通常包括但不限于HTTP请求、连接计时器、会话状态、连接数、捕获的首部及cookie、“frontend”、“backend”及服务器名称,当然也包括源地址和端口号等。示例如下:

option httplog [clf]

14、option logasap/no option logasap

启用或禁用提前将http请求记入日志,不能用于frontend段:

1listen http_proxy 0.0.0.0:80
2mode http
3option httplog
4option logasap
5log 172.16.100.9 local2

15、option forwardfor

允许在发往服务器的请求首部中插入“X-Forwarded-For”首部,些参数定义后,需要在后端服务器的记录日志格式修改为记录X-Forwarded-For的信息,方可记录下客户端IP地址。if-none: 仅在此首部不存在时才将其添加至请求报文中。示例及用法如下:

1用法:
2option forwardfor [except <network>][header <name>][if-none]
3示例:
4frontend www
5  mode http
6  option forwardfor except 127.0.0.1/8

16、errorfile

在用户请求不存的页面时,返回一个页面文件给客户端而非由haproxy生成的错误代码;可用于所有段中。指定对HTTP的哪些状态码返回指定的页面;这里可用的状态码有200、400、403、408、500、502、503和504 。:指定用于响应的页面文件。用法及示例如下:

1用法:
2errorfile  <file>
3示例:
4errorfile 400 /etc/haproxy/errorpages/400badreq.http
5errorfile 403 /etc/haproxy/errorpages/403forbid.http
6errorfile 503 /etc/haproxy/errorpages/503sorry.http

17、errorloc和errorloc302

请求错误时,返回一个HTTP重定向至某URL的信息;可用于所有配置段中。指定对HTTP的哪些状态码返回指定的页面;这里可用的状态码有200、400、403、408、500、502、503和504;:Location首部中指定的页面位置的具体路径,可以是在当前服务器上的页面的相对路径,也可以使用绝对路径;需要注意的是,如果URI自身错误时产生某特定状态码信息的话,有可能会导致循环定向。需要留意的是,这两个关键字都会返回302状态码,这将使得客户端使用同样的HTTP方法获取指定的URL,对于非GET方法的场景(如POST)来说会产生问题,因为返回客户的URL是不允许使用GET以外的其它方法的。如果的确有这种问题,可以使用errorloc303来返回303状态码给客户端 。

1errorloc  <url>
2errorloc302  <url>

18、errorloc303

请参考上面errorloc302 。

19、no option http-server-close 与option http-server-close

功能:由客户端到服务端的连接设定,当HAProxy的保持连接开启的时候,需要把这项开起来,服务器主动断开连接,其是向报文中添加connection:close的头信息,客户端收到后,将发出断开连接请求

20、option http-pretend-keepalive

功能:当启用http-server-close或option forceclose代理服务器添加一个connect:close(就是短连接模式)的头部信息,转发至后端server,当后端的server收到报文后,无法识别或拒绝响应。所以需要代理 服务器就需要假装是保持连接模式,而不发送connection:close的信息头部,在使用了option forceclose,http-server-close的选项时,就应该启用http-pretend-keepalive选项 。

21、option httpclose / no option httpcolse

功能:启用或禁用被动http连接功能,是否允许服务端断开连接,跟http-server-close一样。

21、option redispatch / no option redispatch

是否允许做重新调度,如果做了保持功能的情况下,被访问的主机坏了,是不是允许把请求调到其它主机。

22、redirect

如果/除非 条件满足,返回重定向给客户端;如果未指定条件,表示直接返回重定向。语法如下:

1redirect location <loc> [code ] <option> [{if | unless} <condition>]
2redirect prefix   <pfx> [code ] <option> [{if | unless} <condition>]
3redirect scheme   <sch> [code ] <option> [{if | unless} <condition>]

参数说明:redirect location ;

使 Location 首部的值等于 loc;

redirect prefix ;

构建 Location 首部为: + 完整的 URI path + query string;

  • 如果使用了 “drop-query” 选项,表示不添加 query string;
  • 如果 \= /,那么不需要重新构建 URI;适用的场景:重定向至同一个 URL,但是插入一个 cookie;

redirect scheme ;

构建 Location 首部为: + “://” + 第一个 Host 首部字段的值 + URI path + query sting

  • 如果使用了 “drop-query” 选项,表示不添加 query string;
  • 如果没有给出 URI path,或者 path = *,则使用 “/” 替代 URI path;
  • 如果找不到 Host 首部字段,则返回空的 Host 首部,大部分浏览器将其解释为:重定向到同一个 host;

常用于将 HTTP 重定向至 HTTPS

\

\ 是可选的;用于指定重定向的状态码,不同的重定向码表示不同的重定向类型,支持使用 301, 302, 303, 307 and 308;

302 是默认状态码;

301 表示:”Moved permanently” 永久重定向;浏览器可以将这个 Location 进行缓存

302 表示:”Moved temporarily” 临时重定向;浏览器不应该缓存这个 Location

303 表示:与 302 相同,但浏览器会使用 GET 方法获取 location

307 表示:与 302 相同,但会明确让浏览器使用同一个 method

308 表示:与 301 相同,但会明确让浏览器使用同一个 method

选项是用于调整重定向的行为的:

“drop-query”

用于 prefix-based redirection 和 sch-based redirection,表示设置 Location 字段时,不添加 query string;

使用场景举例:将用户导向一个非安全的页面;

“append-slash”

这个选项和 drop-query 合用时,可将不是以 ‘/’ 重定向至同一个 Location ,但在尾部添加上 ‘/’;

这个修改可确保搜索引擎只看到一个 URL;

这时最好使用 301 作为状态码;

“set-cookie NAME[=value]”

在重定向响应中添加一个 “Set-Cookie” 首部字段;

这使得用户的下一次访问会携带 cookie,利用这一点可以防御某些类型的 DoS 攻击;

因为没有添加其他的 cookie 选项,所以这里设置的 cookie 是唯一的 cookie,这是其成为一个 session cookie;

注意,对于浏览器而言,一个不带 = 符号的 cookie name,和带了 = 符号的 cookie name 是不同的;

“clear-cookie NAME[=]”

在重定向响应中添加一个 “Set-Cookie” 首部字段,但 “Max-Age” 属性被设置为 0,浏览器会删除这个 cookie;

使用场景举例:访问了一个登出页面 logout page,表示要退出访问,这时为安全考虑最好删除 cookie,以免被人盗取,这对于提高安全性是有好处的;

特别要注意,”clear-cookie NAME” 和 “clear-cookie NAME=” 是不同的;前者不会删除这样的 cookie: “NAME=value”,必须使用 “clear-cookie NAME=” 删除这样的 cookie,这一点不同是因为浏览器而产生的,因为浏览器对其进行不同的处理。

示例1:强制用户使用 HTTPS 协议访问登陆页面

 1acl clear      dst_port  80
 2acl secure     dst_port  8080
 3acl login_page url_beg   /login
 4acl logout     url_beg   /logout
 5acl uid_given  url_reg   /login?userid={FNXX==XXFN}+
 6acl cookie_set hdr_sub(cookie) SEEN=1
 7redirect prefix   https://mysite.com set-cookie SEEN=1 if !cookie_set # 如果用户访问时不携带 cookie,让其重定向使用 HTTPS 访问,并且为其设置 cookie
 8redirect prefix   https://mysite.com           if login_page !secure # 访问登陆页面,但不是访问的安全端口,重定向使用 HTTPS 协议
 9redirect prefix   http://mysite.com drop-query if login_page !uid_given # 访问登陆页面,但没有给出 userid 信息,让用户重新填写登陆信息
10redirect location http://mysite.com/           if !login_page secure # 访问非登陆页面,但却要求使用安全端口,这没必要,让用户重定向到普通页面
11redirect location / clear-cookie USERID=       if logout # 登出之后,让浏览器删除 cookie USERID=value,且重定向到首页

示例2:Send redirects for request for articles without a ‘/’ .

1acl missing_slash path_reg ^/article/{FNXX==XXFN}*$
2redirect code 301 prefix / drop-query append-slash if missing_slash
3不改变 URI,改变默认状态码为 301,删除 query string,并在 URI 尾部添加 "/"

示例3:Redirect all HTTP traffic to HTTPS when SSL is handled by haproxy.

1acl is_ssl dst_port 8080
2redirect scheme https if !is_ssl

23、reqadd

功能:向请求报文添加首部,如果是通过81访问的请求,就向请求首部添加X-Proto: SSL的首部信息示例如下:

1acl is-ssl dst_port 81
2reqadd X-Proto:\ SSL if is-ssl

24、rspadd

向响应报文添加首部,示例如下:rspadd Via:\ node1.361way.com

25、timeout http-keep-alive

开启haproxy的保持连接功能,示例如下:timeout http-keep-alive 10s

26、option dontlognull

功能:不记录自己的健康状态检查的日志。

关于配置参数部分就先搞这么多,关于配置示例再单独搞一篇吧。ACL规则也准备单独搞一篇来做。

参考文档

haproxy configuration.txt

HAProxy doc页面