reverse_proxy
将请求代理到一个或多个后端(upstream),并提供可配置的传输、负载均衡、健康检查、请求操作和缓冲选项。
Syntax
reverse_proxy [<matcher>] [<upstreams...>] {
# backends
to <upstreams...>
dynamic <module> ...
# load balancing
lb_policy <name> [<options...>]
lb_retries <retries>
lb_try_duration <duration>
lb_try_interval <interval>
lb_retry_match <request-matcher>
# active health checking
health_uri <uri>
health_upstream <ip:port>
health_port <port>
health_interval <interval>
health_passes <num>
health_fails <num>
health_timeout <duration>
health_method <method>
health_status <status>
health_request_body <body>
health_body <regexp>
health_follow_redirects
health_headers {
<field> [<values...>]
}
# passive health checking
fail_duration <duration>
max_fails <num>
unhealthy_status <status>
unhealthy_latency <duration>
unhealthy_request_count <num>
# streaming
flush_interval <duration>
request_buffers <size>
response_buffers <size>
stream_timeout <duration>
stream_close_delay <duration>
# request/header manipulation
trusted_proxies [private_ranges] <ranges...>
header_up [+|-]<field> [<value|regexp> [<replacement>]]
header_down [+|-]<field> [<value|regexp> [<replacement>]]
method <method>
rewrite <to>
# round trip
transport <name> {
...
}
# optionally intercept responses from upstream
@name {
status <code...>
header <field> [<value>]
}
replace_status [<matcher>] <status_code>
handle_response [<matcher>] {
<directives...>
# special directives only available in handle_response
copy_response [<matcher>] [<status>] {
status <status>
}
copy_response_headers [<matcher>] {
include <fields...>
exclude <fields...>
}
}
}
Upstreams
- <upstreams...> 是要代理到的上游(后端)列表。
- to 是指定上游列表的另一种写法,每行一个或多个。
- dynamic 配置一个 动态上游 模块。它允许为每次请求动态获取上游列表。有关标准动态上游模块的描述,请参见下文的动态上游。动态上游在每次代理循环迭代时都会获取(即如果启用负载均衡重试,可能在同一请求中多次获取),并且会优先于静态上游。如果发生错误,代理将回退到使用任何静态配置的上游。
上游地址
静态上游地址可以采用仅包含 scheme 和 host/port 的 URL 形式,或常规的 Caddy 网络地址。有效示例:
localhost:4000127.0.0.1:4000[::1]:4000http://localhost:4000https://example.comh2c://127.0.0.1example.comunix//var/php.sockunix+h2c//var/grpc.socklocalhost:8001-8006[fe80::ea9f:80ff:fe46:cbfd%eth0]:443
默认情况下,与上游的连接通过明文 HTTP 建立。使用 URL 形式时,可以通过 scheme 以简写方式设置一些transport 默认值。
-
使用
https://作为 scheme 将使用带有启用tls的http传输。此外,您可能需要覆盖
Host头以使其与 TLS SNI 值匹配,服务器会使用该值进行路由和证书选择。有关详细信息,请参见下面的 HTTPS 部分。 -
使用
h2c://作为 scheme 将使用设置为允许明文 HTTP/2 连接的http传输。 -
使用
http://作为 scheme 与省略 scheme 等效,因为 HTTP 已经是默认值。此语法包含以对称于其他 scheme 的方便性。
不能混合使用不同的 scheme,因为它们会修改公共传输配置(启用 TLS 的传输不能同时承载 HTTPS 和明文 HTTP)。任何显式的传输配置将不会被覆盖,省略 scheme 或使用其他端口也不会假定某种特定传输。
当在 IPv6 地址中使用 zone(例如带有特定网络接口的链路本地地址)时,不能使用 scheme 作为简写,因为 % 会导致 URL 解析错误;应显式配置传输。
使用网络地址形式时,网络类型作为前缀指定在上游地址中。这不能与 URL scheme 结合使用。作为特殊情况,unix+h2c/ 被支持为 unix/ 网络的简写,并具有与 h2c:// scheme 相同的效果。端口范围作为简写受支持,会扩展为具有相同主机的多个上游。
上游地址不能包含路径或查询字符串,因为那会意味着在代理时同时重写请求,其行为未定义且不受支持。如有此需求,请使用rewrite 指令。
如果地址不是 URL(即没有 scheme),则可以使用占位符,但这会使上游变为“动态静态”,意味着许多不同的后端在健康检查和负载均衡方面被视为单个静态上游。建议在可能的情况下改用动态上游 模块。当使用占位符时,必须包含端口(要么由占位符替换提供,要么作为地址的静态后缀)。
动态上游
Caddy 的反向代理默认包含一些动态上游模块。注意,使用动态上游会对负载均衡和健康检查产生影响,具体取决于策略配置:主动健康检查不会针对动态上游运行;并且如果上游列表相对稳定且一致(尤其在轮询 round-robin 情况下),则对负载均衡和被动健康检查更有利。理想情况下,动态上游模块只返回健康且可用的后端。
SRV
从 SRV DNS 记录检索上游。
dynamic srv [<full_name>] {
service <service>
proto <proto>
name <name>
refresh <interval>
resolvers <ip...>
dial_timeout <duration>
dial_fallback_delay <duration>
}
- <full_name> 是要查询的完整域名(即
_service._proto.name)。 - service 是完整名称中的服务组件。
- proto 是完整名称中的协议组件。可以是
tcp或udp。 - name 是名称组件。或者,如果
service和proto为空,则为要查询的完整域名。 - refresh 是刷新缓存结果的频率。默认:
1m - resolvers 是覆盖系统解析器的 DNS 解析器列表。
- dial_timeout 是拨号查询的超时时间。
- dial_fallback_delay 是在生成 RFC 6555 快速回退连接之前等待的时间。默认:
300ms
A/AAAA
从 A/AAAA DNS 记录检索上游。
dynamic a [<name> <port>] {
name <name>
port <port>
refresh <interval>
resolvers <ip...>
dial_timeout <duration>
dial_fallback_delay <duration>
versions ipv4|ipv6
}
- name 是要查询的域名。
- port 是用于后端的端口。
- refresh 是刷新缓存结果的频率。默认:
1m - resolvers 是覆盖系统解析器的 DNS 解析器列表。
- dial_timeout 是拨号查询的超时时间。
- dial_fallback_delay 是在生成 RFC 6555 快速回退连接之前等待的时间。默认:
300ms - versions 是要解析的 IP 版本列表。默认:
ipv4 ipv6,分别对应 A 和 AAAA 记录。
Multi
将多个动态上游模块的结果追加在一起。若希望从冗余来源获取上游(例如:主 SRV 集群备份次要 SRV 集群)时很有用。
dynamic multi {
<source> [...]
}
- <source> 是动态上游模块的名称,后跟其配置。可以指定多个。
负载均衡
负载均衡通常用于在多个上游之间分配流量。通过启用重试,它也可以与一个或多个上游一起使用,在能够选择到健康上游之前阻止请求(例如在上游重启或重新部署时等待并缓解错误)。
默认启用,使用 random 策略。重试默认被禁用。
-
lb_policy 是负载均衡策略的名称及其任何选项。默认:
random。对于涉及哈希的策略,使用最高随机权重 (HRW) 算法,确保具有相同哈希键的客户端或请求映射到相同上游,即使上游列表发生变化。
某些策略支持作为选项的回退(fallback),在注明的情况下,它们接受一个包含
fallback <policy>的块,该回退项接受另一个负载均衡策略。对于这些策略,默认回退是random。配置回退允许在主策略未选出上游时使用次级策略,从而实现强大的组合。回退可以嵌套多次。例如,可以使用
header作为主策略,允许开发者选择特定上游,并以first作为回退来实现主/备故障转移。lb_policy header X-Upstream { fallback first }-
random随机选择一个上游 -
random_choose <n>随机选择两个或更多上游,然后从中选择负载最小的一个(n通常为 2) -
first选择配置中定义顺序中的第一个可用上游,允许主/备故障转移;记得配合健康检查一起使用,否则不会发生故障转移 -
round_robin依次轮询每个上游 -
weighted_round_robin <weights...>依次轮询每个上游,遵循提供的权重。权重参数的数量应与配置的上游数量相匹配。权重应为非负整数。例如,对于两个上游和权重5 1,第一个上游将连续被选择 5 次,然后第二个上游被选择 1 次,然后循环重复。如果使用 0 作为权重,则表示禁止为新请求选择该上游。 -
least_conn选择当前请求数最少的上游;如果不止一个主机具有最少请求数,则从这些主机中随机选择一个 -
ip_hash将远端 IP(直接对等方)映射到一个粘性上游 -
client_ip_hash将客户端 IP 映射到一个粘性上游;最好与启用真实客户端 IP 解析的servers > trusted_proxies全局选项 配合使用,否则它的行为与ip_hash相同 -
uri_hash将请求 URI(路径和查询)映射到一个粘性上游 -
query [key]将请求查询的某个键的值哈希后映射到粘性上游;如果指定键不存在,则使用回退策略选择上游(默认random) -
header [field]将请求头字段值哈希后映射到粘性上游;如果指定的头字段不存在,则使用回退策略选择上游(默认random) -
cookie [<name> [<secret>]]对于来自客户端的第一次请求(当没有该 cookie 时),将使用回退策略选择上游(默认random),并在响应中添加Set-Cookie头(如果未指定 cookie 名称,默认名为lb)。cookie 的值是所选上游的拨号地址,经 HMAC-SHA256(使用<secret>作为共享密钥,若未指定则为空字符串)哈希后的结果。在随后带有该 cookie 的请求中,如果对应的上游可用,则该 cookie 值会映射到相同的上游;如果不可用或未找到,则使用回退策略选择新的上游,并将新 cookie 添加到响应中。
如果您希望用于调试,可用已知上游地址与 secret 计算 cookie 值,然后在 HTTP 客户端中设置该 cookie(浏览器或其他)。例如,在 PHP 中,您可以运行下面的命令计算 cookie 值,其中
10.1.0.10:8080是某个上游地址,secret是配置的 secret。echo hash_hmac('sha256', '10.1.0.10:8080', 'secret'); // cdd96966817dd14a99f47ee17451464f29998da170814a16b483e4c1ff4c48cf您可以通过 Javascript 控制台在浏览器中设置 cookie,例如设置名为
lb的 cookie:document.cookie = "lb=cdd96966817dd14a99f47ee17451464f29998da170814a16b483e4c1ff4c48cf";
-
-
lb_retries 定义在每次请求中如果下一个可用主机宕机,要重试选择可用后端的次数。默认情况下重试被禁用(为零)。
如果同时配置了
lb_try_duration,则当达到该持续时间时重试可能会提前停止。换言之,重试持续时间优先于重试次数。 -
lb_try_duration 是一个持续时间值,定义在下一个可用主机宕机时为每次请求尝试选择可用后端的最长时间。默认:重试被禁用(持续时间为零)。
客户端将在负载均衡器尝试查找可用上游时等待最长此时长。一个合理的起点可能是
5s,因为 HTTP 传输的默认拨号超时为3s,因此在第一个选定的上游无法访问时应该至少允许一次重试;但请根据您的用例调整以找到合适的平衡。 -
lb_try_interval 是一个持续时间值,定义在从池中选择下一个主机之间要等待的时间。默认值:
250ms。仅在向上游主机的请求失败时相关。注意,如果将其设置为0且lb_try_duration非零,则当所有后端都宕机且延迟非常低时,可能会导致 CPU 空转。 -
lb_retry_match 限制哪些请求允许重试。仅当请求满足此条件时,若到上游的连接成功但随后的往返失败,才会进行重试。如果连接到上游失败,则始终允许重试。默认情况下,仅重试
GET请求。此选项的语法与命名请求匹配器相同,但不带
@name。如果只需要单个匹配器,可在同一行进行配置。对于多个匹配器,需要使用块语法。
主动健康检查
主动健康检查在后台定时执行。要启用此功能,需要配置 health_uri 或 health_port。
-
health_uri 是主动健康检查的 URI 路径(可含查询)。
-
health_upstream 是用于主动健康检查的 ip:port(如果与上游不同)。应与
health_header和{http.reverse_proxy.active.target_upstream}一起使用。 -
health_port 是用于主动健康检查的端口(如果与上游的端口不同)。如果使用
health_upstream则忽略此项。 -
health_interval 是一个持续时间值,定义执行主动健康检查的频率。默认:
30s。 -
health_passes 是在将后端重新标记为健康之前所需的连续成功健康检查次数。默认:
1。 -
health_fails 是在将后端标记为不健康之前所需的连续失败健康检查次数。默认:
1。 -
health_timeout 是一个持续时间值,定义在将后端标记为宕机之前等待回复的时间。默认:
5s。 -
health_method 是主动健康检查要使用的 HTTP 方法。默认:
GET。 -
health_status 是期望来自健康后端的 HTTP 状态码。可以是 3 位状态码,或以
xx结尾的状态码类别。例如:200(默认),或2xx。 -
health_request_body 是要随主动健康检查发送的请求体字符串。
-
health_body 是要在主动健康检查响应体上匹配的子字符串或正则表达式。如果后端返回的 body 不匹配,则会将其标记为宕机。
-
health_follow_redirects 会使健康检查跟随上游提供的重定向。默认情况下,重定向响应会被视为失败。
-
health_headers 允许指定在主动健康检查请求上设置的头部。如果需要更改
Host头,或在健康检查中向后端提供某些认证信息,这很有用。
被动健康检查
被动健康检查与实际代理请求一起在线发生。要启用此功能,需要配置 fail_duration。
-
fail_duration 是一个持续时间值,定义记住一次失败请求的时长。大于
0的持续时间会启用被动健康检查;默认是0(关闭)。一个合理的起点可能是30s,以在错误率与当不健康上游恢复时的响应性之间取得平衡;请根据实际情况调整。 -
max_fails 是在
fail_duration内将后端视为宕机所需的最大失败请求数;必须 >=1;默认:1。 -
unhealthy_status 如果响应返回这些状态码中的任意一个,则计为失败。可以是 3 位状态码或以
xx结尾的状态码类别,例如:404或5xx。 -
unhealthy_latency 是一个持续时间值,如果请求耗时达到该阈值,则计为失败。
-
unhealthy_request_count 是在将后端标记为宕机之前允许同时发送到该后端的最大并发请求数。换言之,如果某个后端当前正在处理这么多请求,则认为它“过载”,并会优先选择其他后端。
该值应为相对较大的数字;配置此项意味着代理将有一个
unhealthy_request_count × upstreams_count的总并发请求限制,超过该数量的请求将因没有可用上游而导致错误。
事件
当上游从健康变为不健康或相反时,会发出事件。这些事件可用于触发其他动作,例如发送通知或记录日志。事件包括:
healthy在上游从不健康变为健康时发出unhealthy在上游从健康变为不健康时发出
在两种情况下,事件元数据中都会包含 host 来标识状态已更改的上游。可以在 exec 事件处理器中使用 {event.data.host} 作为占位符,例如用于脚本中引用。
流式处理 (Streaming)
默认情况下,代理会为线缆效率部分缓冲响应。
代理还支持 WebSocket 连接,执行 HTTP 升级请求后,将连接转换为双向隧道。
-
flush_interval 是一个持续时间值,用于调整 Caddy 将响应缓冲区刷新到客户端的频率。默认:不进行周期性刷新。负值(通常为 -1)表示“低延迟模式”,它会完全禁用响应缓冲,并在每次写入客户端后立即刷新,即使客户端提前断开也不会取消对后端的请求。如果响应满足以下任一条件,则该选项被忽略,响应会立即刷新到客户端:
Content-Type: text/event-streamContent-Length未知- 双端都是 HTTP/2,
Content-Length未知,并且Accept-Encoding未设置或为 "identity"
-
request_buffers 会导致代理在将请求发送到上游之前,从请求体中读取最多
<size>字节到缓冲区。这非常低效,只有在上游要求在没有延迟的情况下读取请求体时才应使用(这是上游应用应修复的问题)。该项接受 go-humanize 支持的所有大小格式。 -
response_buffers 会导致代理在将响应返回给客户端之前,从响应体中读取最多
<size>字节到缓冲区。出于性能原因,应尽量避免,但如果后端内存受限,可能有用。该项接受 go-humanize 支持的所有大小格式。 -
stream_timeout 是一个持续时间值,在此超时之后,流式请求(例如 WebSocket)将在超时结束时被强制关闭。本质上,如果连接保持打开时间过长,会取消该连接。一个合理的起点可能是
24h,用于清理超过一天的连接。默认:无超时。 -
stream_close_delay 是一个持续时间值,在配置卸载时延迟强制关闭流式请求(例如 WebSocket);在延迟期间,流将保持打开。换句话说,启用此项可以防止在 Caddy 配置重载时流立即关闭。启用此项可以避免之前配置关闭连接后导致的大量客户端重新连接(雪崩效应)。一个合理的起点可能是
5m,允许用户在配置重载后有 5 分钟的时间自然离开页面。默认:无延迟。
头部 (Headers)
代理可以在自身与后端之间操作头部:
-
header_up 在发送到上游后端的请求头上设置、添加(使用
+前缀)、删除(使用-前缀),或通过使用两个参数(搜索与替换)执行替换。 -
header_down 在从后端下游传来的响应头上设置、添加(使用
+前缀)、删除(使用-前缀),或通过使用两个参数(搜索与替换)执行替换。
例如,要设置请求头并覆盖任何现有值:
header_up Some-Header "the value"
要添加响应头;注意头字段可以有多个值:
header_down +Some-Header "first value"
header_down +Some-Header "second value"
要删除请求头,防止其到达后端:
header_up -Some-Header
使用后缀匹配删除所有匹配的请求头:
header_up -Some-*
删除所有请求头,以便您可以单独添加所需的头(不推荐):
header_up -*
对请求头执行正则替换:
header_up Some-Header "^prefix-([A-Za-z0-9]*)$" "replaced-$1-suffix"
正则表达式语言使用的是 Go 中包含的 RE2。参见 RE2 语法参考 和 Go regexp 语法概览。替换字符串会被展开,允许使用捕获的值,例如 $1 表示第一个捕获组。
默认值
默认情况下,Caddy 会将传入的头部(包括 Host)原样传递给后端,但有三个例外:
- 它设置或补充
X-Forwarded-For头字段。 - 它设置
X-Forwarded-Proto头字段。 - 它设置
X-Forwarded-Host头字段。
对于这些 X-Forwarded-* 头,默认情况下代理会忽略传入请求中的这些值,以防止伪造。
如果 Caddy 不是客户端首先连接的服务器(例如在 Caddy 前面有 CDN),您可以使用 trusted_proxies 配置一组 IP 范围(CIDR),来自这些范围的传入请求被信任其发送的这些头值是可信的。
强烈建议通过servers > trusted_proxies 全局选项进行配置,而不是在代理中配置,以便此设置适用于服务器中的所有代理处理程序,而且这还有启用客户端 IP 解析的好处。
此外,在使用http 传输时,如果客户端请求中缺少 Accept-Encoding: gzip 头,Caddy 会自动设置该头。这允许上游在支持时提供压缩内容。可以在传输上使用 compression off 禁用此行为。
HTTPS
由于(大多数)头在代理时保留其原始值,因此在代理到 HTTPS 时,通常需要用配置的上游地址覆盖 Host 头,以便 Host 头与 TLS ServerName 值匹配:
reverse_proxy https://example.com {
header_up Host {upstream_hostport}
}
X-Forwarded-Host 头仍然会默认传递,因此上游如果需要知道原始 Host 值仍可使用它。
当在 Caddy 中终止 TLS 并通过 HTTP 代理(无论是到端口还是 unix 套接字)时也同样适用。确实,当 reverse_proxy 的目标是 Caddy 本身时,Caddy 必须接收到正确的 Host。在 unix 套接字的情况下,upstream_hostport 将是套接字路径,必须显式设置 Host。
重写 (Rewrites)
默认情况下,Caddy 在代理到上游时会使用与传入请求相同的 HTTP 方法和 URI,除非在到达 reverse_proxy 之前的中间件链中已执行重写。
在代理之前,请求会被克隆;这确保了处理期间对请求所做的任何修改不会泄漏到其他处理程序中。这在处理需要在代理之后继续进行的情况时非常有用。
除了头部操作之外,请求的方法和 URI 可以在发送到上游之前被更改:
- method 更改克隆请求的 HTTP 方法。如果方法更改为
GET或HEAD,则该处理程序不会将传入请求的主体发送到上游。如果希望让其他处理程序消费请求体,这是有用的。 - rewrite 更改克隆请求的 URI(路径和查询)。这类似于
rewrite指令,但不会在此处理程序的范围之外保留重写。
这些重写通常适用于“预检查请求”(pre-check requests)之类的模式,其中请求发送到另一个服务器以帮助决定如何继续处理当前请求。
例如,请求可以发送到一个身份验证网关,以决定请求是否来自已认证用户(例如请话中有 session cookie)并应继续处理,还是应重定向到登录页面。对于此模式,Caddy 提供了快捷指令 forward_auth,以跳过大部分配置样板。
传输 (Transports)
Caddy 的代理传输是可插拔的:
- transport 定义如何与后端通信。默认是
http。
http 传输
transport http {
read_buffer <size>
write_buffer <size>
max_response_header <size>
proxy_protocol v1|v2
dial_timeout <duration>
dial_fallback_delay <duration>
response_header_timeout <duration>
expect_continue_timeout <duration>
resolvers <ip...>
tls
tls_client_auth <automate_name> | <cert_file> <key_file>
tls_insecure_skip_verify
tls_curves <curves...>
tls_timeout <duration>
tls_trust_pool <module>
tls_server_name <server_name>
tls_renegotiation <level>
tls_except_ports <ports...>
keepalive [off|<duration>]
keepalive_interval <interval>
keepalive_idle_conns <max_count>
keepalive_idle_conns_per_host <count>
versions <versions...>
compression off
max_conns_per_host <count>
forward_proxy_url <url>
}
-
read_buffer 是读取缓冲区的大小(字节)。接受 go-humanize 支持的所有格式。默认:
4KiB。 -
write_buffer 是写入缓冲区的大小(字节)。接受 go-humanize 支持的所有格式。默认:
4KiB。 -
max_response_header 是从响应头读取的最大字节数。接受 go-humanize 支持的所有格式。默认:
10MiB。 -
proxy_protocol 在到上游的连接上启用 PROXY protocol(由 HAProxy 流行),在连接前添加真实客户端 IP 数据。如果 Caddy 在另一个代理后面,则最好与
servers > trusted_proxies全局选项 配合使用。支持版本v1和v2。仅当您确定上游服务器能够解析 PROXY protocol 时才应使用。默认:禁用。 -
dial_timeout 是连接上游套接字时等待的最大持续时间。默认:
3s。 -
dial_fallback_delay 在生成 RFC 6555 快速回退连接之前等待的最大持续时间。负值禁用该功能。默认:
300ms。 -
response_header_timeout 是从上游读取响应头时等待的最大持续时间。默认:无超时。
-
expect_continue_timeout 是在请求包含
Expect: 100-continue头并在完全写入请求头后等待上游首次响应头的最大持续时间。默认:无超时。 -
read_timeout 是从后端下一次读取时等待的最大持续时间。默认:无超时。
-
write_timeout 是向后端下一次写入时等待的最大持续时间。默认:无超时。
-
resolvers 是覆盖系统解析器的 DNS 解析器列表。
-
tls 使用 HTTPS 与后端通信。如果您使用
https://scheme 或端口:443指定后端,或配置了下面的任一tls_*选项,则会自动启用此项。 -
tls_client_auth 通过两种方式启用 TLS 客户端认证: (1) 指定一个域名,Caddy 会为其获取证书并保持续期,或 (2) 指定要用于与后端进行 TLS 客户端认证的证书和密钥文件。
-
tls_insecure_skip_verify 关闭 TLS 握手验证,使连接变得不安全并易受中间人攻击。不要在生产环境中使用。
-
tls_curves 是用于上游连接的一组椭圆曲线。Caddy 的默认设置是现代且安全的,只有在有特定要求时才需要配置此项。
-
tls_timeout 是完成 TLS 握手的最大持续时间。默认:无超时。
-
tls_trust_pool 配置受信任证书颁发机构的来源,类似于
tls指令文档中描述的trust_pool子指令。标准 Caddy 安装中可用的信任池来源列表可在此处查看 here。 -
tls_server_name 设置在验证 TLS 握手中收到的证书时使用的服务器名称(ServerName)。默认:使用上游地址的 host 部分。
仅当上游地址与上游可能使用的证书不匹配时才需要覆盖此项。例如,如果上游地址是 IP 地址,则需要将此项配置为上游服务器提供的主机名。
可以使用请求占位符,在这种情况下会在每个请求上克隆 HTTP 传输配置,这可能会带来性能开销。
-
tls_renegotiation 设置 TLS 重新协商级别。TLS 重新协商是指在首次握手后执行后续握手。级别可以是:
never(默认) 禁用重新协商。once允许远端服务器每个连接请求重新协商一次。freely允许远端服务器反复请求重新协商。
-
tls_except_ports 当启用 TLS 时,如果上游目标使用了给定端口之一,则对这些连接禁用 TLS。这在配置动态上游时可能有用,某些上游期望 HTTP 而其他上游期望 HTTPS。
-
keepalive 为
off或一个指定连接保持打开的持续时间值(超时)。默认:2m。 -
keepalive_interval 为存活探测之间的持续时间。默认:
30s。 -
keepalive_idle_conns 定义要保持的最大空闲连接数。默认:无限制。
-
keepalive_idle_conns_per_host 如果非零,控制每个主机要保持的最大空闲(keep-alive)连接数。默认:
32。 -
versions 允许自定义要支持的 HTTP 版本。
有效选项:
1.1、2、h2c、3。默认:
1.1 2,或者如果上游的 scheme 是h2c://,则默认是h2c 2。h2c启用与上游的明文 HTTP/2 连接。这是一个非标准特性,不使用 Go 的默认 HTTP 传输,因此它与其他功能互斥。3启用与上游的 HTTP/3 连接。⚠️ 此功能为实验性,可能会发生变化。 -
compression 可通过设置为
off来禁用到后端的压缩。 -
max_conns_per_host 可选地限制每个主机的总连接数,包括拨号、激活和空闲状态的连接。默认:无限制。
-
forward_proxy_url 指定 HTTP 传输用于通过其代理请求到上游服务器的服务器 URL。默认情况下,Caddy 尊重 Go 标准库中基于环境变量配置的代理(参见 Go stdlib),如
HTTP_PROXY。当为此参数提供值时,请求将按以下顺序通过反向代理流动:- 客户端(用户) 🡒
reverse_proxy🡒forward_proxy_url🡒 上游
- 客户端(用户) 🡒
fastcgi 传输
transport fastcgi {
root <path>
split <at>
env <key> <value>
resolve_root_symlink
dial_timeout <duration>
read_timeout <duration>
write_timeout <duration>
capture_stderr
}
-
root 是站点根目录。默认:
{http.vars.root}或当前工作目录。 -
split 指定在 URI 末尾从哪里拆分路径以获取 PATH_INFO。
-
env 将额外的环境变量设置为给定值。可多次指定以设置多个环境变量。
-
resolve_root_symlink 启用通过解析符号链接来解析
root目录的真实路径(如果存在符号链接)。 -
dial_timeout 是连接上游套接字时的等待时长。接受持续时间值。默认:
3s。 -
read_timeout 是从 FastCGI 服务器读取时的等待时长。接受持续时间值。默认:无超时。
-
write_timeout 是向 FastCGI 服务器发送时的等待时长。接受持续时间值。默认:无超时。
-
capture_stderr 启用捕获并记录上游 fastcgi 服务器写入
stderr的任何消息。默认以WARN级别记录。如果响应状态为4xx或5xx,则使用ERROR级别。默认情况下忽略stderr。
拦截响应
反向代理可以配置为拦截来自后端的响应。为此,可以定义响应匹配器(语法与请求匹配器类似),第一个匹配的 handle_response 路由将被调用。
当响应处理器被调用时,来自后端的响应不会写入客户端,而会执行配置的 handle_response 路由,由该路由负责写入响应。如果该路由未写入响应,则请求处理将继续执行在该 reverse_proxy 之后有序排列的任何处理程序。
-
@name 是响应匹配器 的名称。只要每个响应匹配器具有唯一名称,即可定义多个匹配器。响应可基于状态码和响应头的存在或值进行匹配。
-
replace_status 在被给定匹配器匹配时,仅更改响应的状态码。
-
handle_response 定义在被给定匹配器匹配时要执行的路由(如果省略匹配器,则适用于所有响应)。将应用第一个匹配的块。在
handle_response块内,可以使用任何其他指令。
此外,在 handle_response 内,可使用两个特殊的处理指令:
-
copy_response 将从后端接收到的响应体复制回客户端。可选地在复制时更改响应的状态码。该指令在指令顺序中位于
respond之前。 -
copy_response_headers 将来自后端的响应头复制到客户端,且可选择包含或排除一组头字段(不能同时指定
include和exclude)。该指令在指令顺序中位于header之后。
在 handle_response 路由内,将提供三个占位符:
-
{rp.status_code}来自后端响应的状态码。 -
{rp.status_text}来自后端响应的状态文本。 -
{rp.header.*}来自后端响应的头部。
虽然反向代理的响应处理器可以将从代理接收到的新响应复制回客户端,但它不能将该新响应传递给后续的反向代理。每次使用 reverse_proxy 时,都会接收原始请求的主体(或由其他模块修改后的主体)。
示例
将所有请求反向代理到本地后端:
example.com {
reverse_proxy localhost:9005
}
example.com {
reverse_proxy node1:80 node2:80 node3:80
}
相同配置,但仅对 /api 内的请求,并使用cookie 策略实现粘性:
example.com {
reverse_proxy /api/* node1:80 node2:80 node3:80 {
lb_policy cookie api_sticky
}
}
使用主动健康检查确定哪些后端是健康的,并在连接失败时启用重试,在找到健康后端之前保持请求:
example.com {
reverse_proxy node1:80 node2:80 node3:80 {
health_uri /healthz
lb_try_duration 5s
}
}
配置一些传输选项:
example.com {
reverse_proxy localhost:8080 {
transport http {
dial_timeout 2s
response_header_timeout 30s
}
}
}
反向代理到HTTPS 上游:
example.com {
reverse_proxy https://example.com {
header_up Host {upstream_hostport}
}
}
反向代理到 HTTPS 上游,但⚠️ 禁用 TLS 验证。强烈不推荐这样做,因为这会禁用 HTTPS 提供的所有安全检查;如果可能,优先在私有网络中通过 HTTP 代理,因为那样不会产生错误的安全感:
example.com {
reverse_proxy 10.0.0.1:443 {
transport http {
tls_insecure_skip_verify
}
}
}
作为替代,您可以通过显式信任上游的证书来建立信任,并(可选地)将 TLS-SNI 设置为与上游证书中的主机名匹配:
example.com {
reverse_proxy 10.0.0.1:443 {
transport http {
tls_trust_pool file /path/to/cert.pem
tls_server_name app.example.com
}
}
}
在代理前剥离路径前缀;但请注意子文件夹问题 :
example.com {
handle_path /prefix/* {
reverse_proxy localhost:9000
}
}
在代理前替换路径前缀,使用rewrite:
example.com {
handle_path /old-prefix/* {
rewrite * /new-prefix{path}
reverse_proxy localhost:9000
}
}
支持 X-Accel-Redirect,即按请求提供静态文件,通过拦截响应实现:
example.com {
reverse_proxy localhost:8080 {
@accel header X-Accel-Redirect *
handle_response @accel {
root * /path/to/private/files
rewrite * {rp.header.X-Accel-Redirect}
method * GET
file_server
}
}
}
为来自上游的错误设置自定义错误页面,通过按状态码拦截错误响应:
example.com {
reverse_proxy localhost:8080 {
@error status 500 503
handle_response @error {
root * /path/to/error/pages
rewrite * /{rp.status_code}.html
file_server
}
}
}
example.com {
reverse_proxy {
dynamic a example.com 9000
}
}
example.com {
reverse_proxy {
dynamic srv _api._tcp.example.com
}
}
使用主动健康检查 并结合 health_upstream 在创建中间服务以进行更彻底的健康检查时非常有用。然后可以使用 {http.reverse_proxy.active.target_upstream} 作为头部将原始上游提供给健康检查服务。
example.com {
reverse_proxy node1:80 node2:80 node3:80 {
health_uri /health
health_upstream 127.0.0.1:53336
health_headers {
Full-Upstream {http.reverse_proxy.active.target_upstream}
}
}
}