尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

fabio HTTPS TCP-SNI 混合代理:在同一监听端口上按 SNI 分流 TCP 透传与 HTTPS 终止

发布时间:2026/9/29 7:27:42

资讯中心
01
ARTICLE

fabio HTTPS TCP-SNI 混合代理:在同一监听端口上按 SNI 分流 TCP 透传与 HTTPS 终止

fabio HTTPS TCP-SNI 混合代理:在同一监听端口上按 SNI 分流 TCP 透传与 HTTPS 终止
后端API网关微服务【免费下载链接】fabioConsul Load-Balancing made simple项目地址https://gitcode.com/gh_mirrors/fa/fabio点击查看免费下载fabio 从 1.5.14 版本起提供httpstcpsni监听器协议它把 TCP-SNI 代理与 HTTPS 终止能力融合在同一个端口上凡是能通过 TLS SNI 主机名匹配到prototcp或tcp://scheme路由的连接fabio 直接按 SNI 把原始 TLS 流量透传不解密给上游其余连接则回落到 HTTPS 处理由 fabio 使用证书源cs终止 TLS 并走常规的 HTTP(S) 路由。读完本文你将掌握该监听器的配置方法、Consul 服务注册标签写法、SNI 分流与 HTTPS 回落的路由判定逻辑以及底层源码实现原理。什么是 HTTPS TCP-SNI 混合代理httpstcpsni是 fabio 支持的一种监听器协议官方文档将其描述为 TCP-SNI 代理与 HTTPS 功能的“合体”amalgam。它解决的问题是很多部署场景下同一个域名/IP/端口上既存在需要由 fabio 终止 TLS 再按路径转发给 HTTP 上游的服务又存在需要把整条 TLS 连接原样透传给上游由上游自己终止 TLS的服务例如数据库、消息队列、私有协议服务等。通过一个监听器fabio 可以在不拆开 TLS 的前提下读取 TLS ClientHello 中的 SNIServer Name Indication主机名用它来决定连接的去向从而省去为不同协议分别开放端口、配置多套负载均衡器的成本。启用方式监听器配置在 fabio 启动参数中配置一个httpstcpsni监听器即可proto关键字是监听器协议的核心fabio -proxy.addr:443;protohttpstcpsni;cssomecertstore该配置在:443端口上同时提供两条能力TCPSNI 路由对 SNI 主机名命中 TCP 路由的连接透明代理原始 TLS 流量HTTPS 回落对未命中 TCP 路由的连接使用cssomecertstore指定的证书源终止 TLS然后按 HTTP(S) 路由处理。从源码结构看config/load.go中的parseListenconfig/load.go负责解析该监听器配置proto的合法取值包括tcp、tcpsni、tcp-dynamic、http、https、grpc、grpcs、httpstcpsni、prometheus其他取值会直接报unknown protocol错误。更重要的是校验规则csName ! 指定了证书源时proto必须是https、tcp、tcp-dynamic、grpcs、prometheus或httpstcpsni之一否则报错protohttps和protogrpcs都必须配置证书源否则报proto https requires cert source。也就是说httpstcpsni监听器必须配置cs这一点与纯tcpsni不同——因为该模式包含 HTTPS 终止回落功能需要证书来服务这部分连接。对应的校验测试覆盖在 config/load_test.go其中给出了多监听器同时启用的示例:443;csconsul-cs,:80,:2375;prototcpsni。除proto与cs外监听器还支持strictmatch、tlsmin、tlsmax、tlsciphers、pxyproto、pxytimeout、rt/wt/it超时等参数。若证书源类型为vault-pki而未显式设置strictmatchfabio 会自动为该监听器启用strictmatch以保证签发的证书 Common Name 与请求主机名严格匹配。路由匹配host 匹配走 TCPpath 匹配走 HTTPShttpstcpsni监听器的分流依据是路由的匹配类型host 匹配SNI凡是prototcp或目标 scheme 为tcp://的路由fabio 会使用 SNI 中的主机名查找上游并做 TCP 透传TLS 由上游终止fabio 不解密path 匹配形如urlprefix-/path/的常规路径路由fabio 使用cs指定的证书源终止 TLS再按 HTTP 请求路径、方法等条件转发。两者互不冲突TCP 路由按主机名匹配、HTTP 路由按路径匹配共存在同一张路由表中。集成测试 proxy/inetaf_tcpproxy_integration_test.go 展示了这种共存关系——同一张路由表里同时有route add srv / ... opts protohttpsHTTPS 回落路径和route add tcproute example2.com/ tcp://... opts prototcpSNI TCP 透传路径。在 Consul 中注册服务对于需要 TCP 透传的上游服务在 Consul 中通过urlprefix-标签注册路由主机名取自 TLS ClientHello 的 SNI 扩展如果上游服务响应https://foo.com/...则注册urlprefix-foo.com/ prototcp注意这里显式给出了prototcp因为 fabio 默认会把没有proto的路由当作 HTTP(S) 路由处理必须用prototcp明确告知 fabio 这条路由属于 TCP 透传而非 HTTPS 终止。如果服务需要 fabio 终止 TLS 并按路径转发则按常规方式注册路径路由urlprefix-/path/从lookupHostMatchermain.go的实现可以看到这一约定的源头它先用 SNI 主机名查询路由表命中后检查目标路由的opts[proto]若没有显式设置proto则回退读取t.URL.Scheme只有最终取值为tcp时才判定该连接属于 TCP 代理返回 true否则返回 false 让连接回落到 HTTPS。这解释了为什么 TCP 路由必须写prototcp或使用tcp://scheme。源码级工作原理入口一个端口、两条通路main.go中proto httpstcpsni的分支main.go同时构造了两个处理器HTTP 代理newHTTPProxy服务于 HTTPS 回落路径tcp.SNIProxy服务于 SNI 透传路径。随后调用 proxy/serve.go 中的ListenAndServeHTTPSTCPSNI。该函数基于inetaf/tcpproxy建立单一监听器并挂接两条通路AddSNIMatchRoute把命中 SNI 匹配器即上述lookupHostMatcher的连接交给tcpSNIListener由tcp.Server驱动SNIProxy做透明透传AddRoute作为兜底通路所有未命中 SNI 路由的连接交给httpsListener再用tls.NewListener(httpsListener, cfg)包裹由http.Server完成 TLS 终止与 HTTP 代理。函数注释明确说明 PROXY protocol 必须在tcpproxy检查 ClientHello 之前被消费因此监听器包装由ListenTCP统一完成proxy/listen.go。SNI 解析不解密读取主机名SNIProxy.ServeTCPproxy/tcp/sni_proxy.go的流程是用bufio.Reader.Peek(9)读取 TLS 记录头部调用clientHelloBufferSize计算 ClientHello 消息总长度并校验记录类型0x16 Handshake、TLS 版本范围、记录长度不超过 16384与握手消息长度不支持跨多条记录的 ClientHello 分片返回fragmentation not implemented完整读出 ClientHello 后跳过前 5 字节的 TLS 记录头调用readServerName从握手消息中解析 SNI 扩展若解析失败或server_name缺失记录[DEBUG]日志并关闭连接用Lookup(host)在路由表中按 SNI 主机名查找目标未命中则累计Noroute计数并返回拨号上游受DialTimeout约束若目标配置了 PROXY protocolt.ProxyProto则先写 PROXY 头把已读入的 ClientHello 原样回写上游再启动两条 goroutine 双向拷贝数据流实现“透明”透传——整个过程中 TLS 流量从未被解密。SNI 解析器的核心在 proxy/tcp/tls_clienthello.goclientHelloBufferSize校验 TLS 记录与握手头readServerName通过clientHelloMsg.unmarshal解析扩展区只提取extensionServerName扩展号 0中的主机名其余扩展ALPN、SessionTicket、SNI 等全部忽略。该解析代码取自 Go 标准库crypto/tls的handshake_messages.go并做了裁剪仅保留读取 SNI 所需的字段是典型的“少即是多”实现。指标与可观测性SNIProxy暴露三类计数器proxy/tcp/sni_proxy.go并在 main.go 中绑定到tcpSniConn、tcpSniConnFail、tcpSniNoRoute等指标上Conn建立的连接总数ConnFail上游连接失败、TLS 握手失败、ClientHello 解析失败等异常次数NorouteLookup未命中路由的次数。配合 fabio 的 metrics 模块可以监控 SNI 分流路径的健康度与无路由命中情况便于定位证书或路由注册问题。适用前提与注意事项必须配置证书源httpstcpsni需要cs参数用于 HTTPS 回落路径的 TLS 终止纯 TCP 透传路径不使用该证书TCP 路由必须显式声明prototcp否则 fabio 会把它当作 HTTP 路由处理SNI 匹配器不会命中SNI 依赖客户端扩展TLS 1.0 以上普遍支持 SNI但若客户端不发server_name扩展fabio 无法按主机分流连接将被拒绝并记录server_name missing不支持 ClientHello 分片从源码注释可见跨多条 TLS 记录的 ClientHello 会解析失败仅适用于常规未分片的握手该功能需要 fabio 1.5.14 及以上版本且Lookup为 nil 时SNIProxy会 panic源码中的显式约定正常运行由main.go注入实现无需用户干预。相关参考官方功能文档docs/content/feature/https-tcp-sni-proxy.md监听器协议解析与校验config/load.go、config/load_test.go混合监听器装配与 SNI 匹配器main.go、main.go双通路监听实现proxy/serve.goSNI 透传与 ClientHello 解析proxy/tcp/sni_proxy.go、proxy/tcp/tls_clienthello.go集成测试示例proxy/inetaf_tcpproxy_integration_test.go赞分享后端API网关微服务【免费下载链接】fabioConsul Load-Balancing made simple项目地址https://gitcode.com/gh_mirrors/fa/fabio点击查看免费下载相关推荐fabio 单实例多协议监听器配置指南HTTP/HTTPS/TCPSNI 同机共存fabio 单实例多协议监听器配置指南HTTP/HTTPS/TCPSNI 同机共存 fabio 是面向 Consul 生态的轻量级负载均衡与反向代理其核心后端API网关微服务FastAPI HTTPS 部署详解TLS 终止代理、SNI、Lets Encrypt 与 --forwarded-allow-ips 配置FastAPI HTTPS 部署详解TLS 终止代理、SNI、Lets Encrypt 与 forwarded allow ips 配置 本文基于 Fast后端Web框架API设计FastAPI HTTPS 部署全解TLS 终止代理、SNI 与证书自动化实践FastAPI HTTPS 部署全解TLS 终止代理、SNI 与证书自动化实践 导读 HTTP 之上的 HTTPS 远不止开启一个开关那么简单它涉及证书后端Web框架API设计创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。