如果加入fallback_ws,可以非常容易地构建 (v2ray+tcp+tls+web) + (v2ray+ws+tls+web)。期望中配置如下
{
"inbounds": [
{
"port": 443,
"protocol": "vless",
"settings": {
"clients": [
{
"id": "baa79d9d-4700-468f-8b80-f86dff44ace1",
"level": 0
}
],
"fallback": {
"addr": "127.0.0.1",
"port": 8001,
"xver": 0
},
"fallback_h2": {
"addr": "127.0.0.1",
"port": 8002,
"xver": 0
},
"fallback_ws": {
"addr": "127.0.0.1",
"port": 8003
},
"decryption": "none"
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"serverName": "example.domain",
"alpn": [
"h2",
"http/1.1"
],
"certificates": [
{
"certificateFile": "/path/to/certificate.crt",
"keyFile": "/path/to/key.key"
}
]
}
}
},
{
"listen": "127.0.0.1",
"port": 8003,
"protocol": "vless",
"settings": {
"clients": [
{
"id": "baa79d9d-4700-468f-8b80-f86dff44ace1",
"level": 0
}
],
},
"streamSettings": {
"network": "ws",
"wsSettings": {
"path": "/xxxxxx" //path与客户端中填写相同
}
}
}
],
"outbounds": [
{
"protocol": "freedom",
"settings": {}
}
]
}
nginx.conf的配置与https://github.com/v2fly/v2ray-examples/blob/master/VLESS-TCP-TLS/nginx.conf 相同
或者如果服务端network能填写tcp+ws,并根据客户端配置自动匹配,这样最好,但只是我的臆想。
{
"inbounds": [
{
"port": 443,
"protocol": "vless",
"settings": {
"clients": [
{
"id": "92fefe6c-0776-4c0e-8cd0-a55d46073ada",
"level": 0
}
],
"fallback": {
"addr": "127.0.0.1",
"port": 8001,
"xver": 0
},
"fallback_h2": {
"addr": "127.0.0.1",
"port": 8002,
"xver": 0
},
"decryption": "none"
},
"streamSettings": {
"network": "tcp,ws", //根据客户端自动匹配
"security": "tls",
"tlsSettings": {
"alpn": [
"h2",
"http/1.1"
],
"certificates": [
{
"certificateFile": "/path/to/certificate.crt",
"keyFile": "/path/to/key.key"
}
]
},
"wsSettings": {
"path": "/xxxxx" //path与客户端中填写相同
}
}
}
],
"outbounds": [
{
"protocol": "freedom",
"settings": {}
}
]
}
我觉得这是可以实现的,因为ws本身也是tcp协议。接到请求后,通过$http_upgrade判断是不是ws协议,如果是ws协议,再判断id是否匹配,不匹配则通过8001端口交给web服务器处理,匹配则提供v2ray+ws服务。
想法不错,不过成功升级到 WS 后却回落到一个不支持 WS 的服务器,会不会变成特征?或许可以解决。但是,升级到 WS 这个过程很有可能会产生可探测的特征,不太好处理。
另一种思路:通过匹配 HTTP/1.1 的 PATH 来实现不同的回落。
想法不错,不过成功升级到 WS 后却回落到一个不支持 WS 的服务器,会不会变成特征?或许可以解决。但是,升级到 WS 这个过程很有可能会产生可探测的特征,不太好处理。
捋一下思路,目标要实现的是:
1.v2客户端发起v2ray+tcp+tls请求,服务端提供相应服务
2.v2客户端发起v2ray+ws+tls请求,服务端提供相应服务
3.非v2客户端发起https请求,返回普通网页
4.非v2客户端发起ws+tls连接请求,返回的内容必须和直接向web服务器发起ws请求返回的内容相同。
要实现目标,就要实现:
1.服务端区分接收到的连接是普通的tcp还是ws
2.区分tcp请求是由v2客户端发起还是非v2客户端发起
3.区分ws请求是由v2客户端发起还是非v2客户端发起
4.对于非v2客户端发起的tcp请求和ws请求,交给后端web服务器处理
目前较难实现的是哪一个呢?
WS 有一个握手的过程,即由 HTTP/1.1 升级到 WS,UUID 并不会第一时间发过来,就无法第一时间进行身份认证。而对于未知客户端的升级请求,如果不交给专业的 web 服务器处理,很可能会产生可区分的特征。
目前我想到的一个比较合适的思路是:加入 fallback_h1。这将是一个数组,每个元素内都有匹配规则,比如 GET、PATH,以及其它 headers(当然也可以有 WS 升级请求),匹配成功则采用该元素的回落设置。
这样的话,对于不知道 PATH 的人,甚至不会知道你的网站有 WS。
WS 有一个握手的过程,即由 HTTP/1.1 升级到 WS,UUID 并不会第一时间发过来,就无法第一时间进行身份认证。而对于未知客户端的升级请求,如果不交给专业的 web 服务器处理,很可能会产生可区分的特征。
目前我想到的一个比较合适的思路是:加入 fallback_h1。这将是一个数组,每个元素内都有匹配规则,比如 GET、PATH,以及其它 headers(当然也可以有 WS 升级请求),匹配成功则采用该元素的回落设置。
这样的话,对于不知道 PATH 的人,甚至不会知道你的网站有 WS。
我明白了,您看我理解得对不对。客户端发起ws连接请求,一旦和v2服务端建立ws连接,就很难交给后端服务器,但是不建立ws连接,就无法判断id是否正确。但是不建立ws连接也可以看到get path user-agent等参数。正好v2可以设置path,所以可以根据path来分流。这样甚至可以做到 (v2ray+tcp+tls+web) + (v2ray+ws+tls+web) + (v2ray+h2+tls+web)。
理想配置
{
"inbounds": [
{
"port": 443,
"protocol": "vless",
"settings": {
"clients": [
{
"id": "0cc11cd7-9ca7-4f49-9afc-b38810b0b4ae",
"level": 1
}
],
"fallback_h1": {
"addr": "127.0.0.1",
"port": 8001,
"path": "!(/path_ws)", //正则表达式,表示path不为path1的交给web服务器
"xver": 0
},
"fallback_h2": {
"addr": "127.0.0.1",
"port": 8002,
"path": "!(/path_h2)", //正则表达式,表示path不为path2的交给web服务器
"xver": 0
},
"decryption": "none"
},
"streamSettings": {
"network": "tcp,ws,h2",
"security": "tls",
"tlsSettings": {
"alpn": [
"h2",
"http/1.1"
],
"certificates": [
{
"certificateFile": "your.cer",
"keyFile": "your.key"
}
]
},
"wsSettings": {
"path": "/path_ws"
},
"httpSettings": {
"path": "/path_h2"
}
}
}
],
"outbounds": [
{
"protocol": "freedom",
"settings": {}
}
]
}
是否回落必须是第一时间就能确定的,否则避免不了产生特征。比如处理 WS 本就麻烦,遇到了异常情况还无法和 Nginx 表现得完全一致。至于建立 WS 连接后如何再回落,这的确也是不好操作的地方。
目前我打算给 fallback 加一个新的参数 read(数组),它会尝试从首包内读取 METHOD、PATH 等信息(仅支持 HTTP/1.1),然后根据匹配结果来覆盖 fallback 原有的参数。fallback_h2 则没有 read。
read 支持 h2 是完全没有必要的,比较麻烦且没有实际应用场景(WS 的应用场景也只是套 CDN,此时真实 IP 仅靠 header)。v2fly 群里有人说实现了 Cloudflare 回源 2053 端口,你也可以先试试。
对于“理想配置”,v2ray 现有框架做不到那样,长期来看也非必要。。。
是否回落必须是第一时间就能确定的,否则避免不了产生特征。比如处理 WS 本就麻烦,遇到了异常情况还无法和 Nginx 表现得完全一致。至于建立 WS 连接后如何再回落,这的确也是不好操作的地方。
目前我打算给 fallback 加一个新的参数 read(数组),它会尝试从首包内读取 METHOD、PATH 等信息(仅支持 HTTP/1.1),然后根据匹配结果来覆盖 fallback 原有的参数。fallback_h2 则没有 read。
read 支持 h2 是完全没有必要的,比较麻烦且没有实际应用场景(WS 的应用场景也只是套 CDN,此时真实 IP 仅靠 header)。v2fly 群里有人说实现了 Cloudflare 回源 2053 端口,你也可以先试试。
对于“理想配置”,v2ray 现有框架做不到那样,长期来看也非必要。。。
我明白您所说的数组的意思了。我也觉得回落在第一时间进行比较好。我一直以为回落是在发现id不匹配后,也就是第二时间进行的。我觉得用数组匹配的这个方向非常好,因为配置nginx也是类似的原理,让我有一种熟悉的感觉 /笑。
“理想配置”只是像说明一种前进的方向,可以理解为想要实现的目标之类的,不必当真。
我觉得,既然都用数组进行匹配了,就不用分成fallback和fallback_h2两个部分了,因为http版本也可以作为匹配的一部分。
这是鄙人所想的一种匹配方案,,如果会显得很傻逼还望包涵 /笑:
{
"inbounds": [
{
"port": 443,
"protocol": "vless",
"settings": {
"clients": [
{
"id": "",
"level": 1
}
],
"fallback": [ //回落匹配规则列表,从上到下一个一个匹配,遇到第一个匹配的,进行回落(规则类似于nginx的匹配机制)
{
"http_version": "http/1.x",
"path": "/path_ws",
"fallback_server": "v2_ws"
},
{
"http_version": "http/1.x",
"fallback_server": "web_http1"
},
{
"http_version": "http2",
"path": "/path_h2",
"fallback_server": "v2_h2"
},
{
"http_version": "http2",
"fallback_server": "web_http2"
}
],
"fallback_servers": [ //回落的服务器列表
{
"name": "web_http1",
"addr": "127.0.0.1",
"port": 8001,
"xver": 0
},
{
"name": "web_http2",
"addr": "127.0.0.1",
"port": 8002,
"xver": 0
},
{
"name": "v2_ws",
"addr": "127.0.0.1",
"port": 8003,
"xver": 0
},
{
"name": "v2_h2",
"addr": "127.0.0.1",
"port": 8004,
"xver": 0
}
],
"decryption": "none"
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"alpn": [
"h2",
"http/1.1"
],
"certificates": [
{
"certificateFile": "your.cer",
"keyFile": "your.key"
}
]
}
}
},
{
"listen": "127.0.0.1",
"port": 8003,
"protocol": "vless",
"settings": {
"clients": [
{
"id": "",
"level": 1
}
]
},
"streamSettings": {
"network": "ws",
"wsSettings": {
"path": "/path_ws"
}
}
},
{
"listen": "127.0.0.1",
"port": 8004,
"protocol": "vless",
"settings": {
"clients": [
{
"id": "",
"level": 1
}
]
},
"streamSettings": {
"network": "h2",
"httpSettings": {
"path": "/path_h2"
}
}
}
],
"outbounds": [
{
"protocol": "freedom",
"settings": {}
}
]
}
我的方案是这样,fallback改为回落匹配规则的列表,新增fallback_servers,作为回落服务器列表。在接受到连接第一时刻,先对规则列表从上到下进行一个一个匹配,遇到第一个匹配的,则进行回落。全部规则都不满足,则进行v2ray连接。如果进行v2连接的id不匹配,则进行第二次回落,选择回落服务器列表中的第一个进行回落。
更新:
抱歉没有仔细看你的回复。就是说思路大致是一样的,只不过我把servers单独列出来了,还有就是对于h2没有必要实现path user-agent等信息的提取,可以理解。毕竟我不是内行人,我原来以为http2和http1提取path user-agent等信息的难度是相同的 /笑,因为nginx的log上把http版本 path user-agent等信息都一起列出来了,所以我才会以为都很好提取 /笑
关于 (v2ray+tcp+tls) + (v2ray+ws+tls),使用v2ray和nginx其实已经可以实现了,就是在v2ray+tcp+tls配置的基础上再加个v2ray+ws+tls的inbound配置,在nginx的配置上再加个对应path的websocket反代。我已经实践过可行。但是我就是觉得这样绕得太远了,要用v2ray+ws+tls的话,得从v2绕道nginx再绕到v2 /笑哭。心想如果能从v2直接绕到v2就好了。
关于cdn,除了隐藏ip,对于小机来说,或者经常出去旅游的人来说(旅游的话要用流量,而且网络环境不断变化,有一个国内的cdn就会稳定很多)cdn还是很重要的,所以我觉得能实现v2ray+ws+tls还是很重要的。至于v2ray+h2+tls我觉得就是锦上添花,能实现最好,不能实现也罢。
第一时间指的是仅通过首包来迅速判断,不等待更不与客户端进一步交互,这样客户端是全过程无感知的。所以只通过首包来判断的都算是,包括协议版本无效和身份认证失败(如果首包有的话)。
现在 VLESS 的回落并不以 HTTP 的方式读取内容,而是只判断首包长度和 VLESS 协议头,至于 fallback 还是 fallback_h2,则是通过读取 ALPN 协商结果来决定的,这样也更简洁、高效、安全。可以看到,如果没有特殊需求,VLESS 并不关心也不想分析内容,只要不是有效的 VLESS 协议头,直接 fallback 就对了。
从实际需求的角度出发,回落首先是要防各种探测,其次才是有限的路径分流(场景只是 CDN WS),这里不应该颠倒重要性顺序,所以不需要大改配置结构、不需要完全按 HTTP 来(也有很多局限性)。提取 h2c 中的信息只是麻烦些,但在直连的场景下,TCP 是更好的选择,所以实际意义并不大(但也可能支持)。
其实 read 的作用也有限,因为只是判断一个 TCP 连接的第一个请求。read 应该是可选的,即对于大多数人,保持现有回落逻辑(非侵入式),对于少数有特殊需求的人,才对首包内容进行 HTTP 分析、匹配。
另外对于同时支持 CDN WS,我觉得有两种更优雅的方式:回源到 2053 等其它 HTTPS 端口,或以 HTTP 方式回源到 80 端口(反正还有 VMess)。
第一时间指的是仅通过首包来迅速判断,不等待更不与客户端进一步交互,这样客户端是全过程无感知的。所以只通过首包来判断的都算是,包括协议版本无效和身份认证失败(如果首包有的话)。
现在 VLESS 的回落并不以 HTTP 的方式读取内容,而是只判断首包长度和 VLESS 协议头,至于 fallback 还是 fallback_h2,则是通过读取 ALPN 协商结果来决定的,这样也更简洁、高效、安全。可以看到,如果没有特殊需求,VLESS 并不关心也不想分析内容,只要不是有效的 VLESS 协议头,直接 fallback 就对了。
从实际需求的角度出发,回落首先是要防各种探测,其次才是有限的路径分流(场景只是 CDN WS),这里不应该颠倒重要性顺序,所以不需要大改配置结构、不需要完全按 HTTP 来(也有很多局限性)。提取 h2c 中的信息只是麻烦些,但在直连的场景下,TCP 是更好的选择,所以实际意义并不大(但也可能支持)。
其实 read 的作用也有限,因为只是判断一个 TCP 连接的第一个请求。read 应该是可选的,即对于大多数人,保持现有回落逻辑(非侵入式),对于少数有特殊需求的人,才对首包内容进行 HTTP 分析、匹配。
明白了,谢谢
决定给 fallback 和 fallback_h2 都加一个新的参数 read,它是一个数组,数组内每个元素有五个参数,其中 path 必填(仅支持正则表达式),其它四个参数及规则与 fallback 项原有的四个参数完全相同。
read 存在时,回落前会尝试以 http/1.1 或 h2c(取决于写在哪)分析首包内容并提取 PATH,然后按第一个匹配成功的 path 所在元素的规则来回落。若未能提取 PATH 或全部匹配失败,则按 fallback 或 fallback_h2 的默认规则来回落。
https://github.com/rprx/v2ray-vless/releases
文档正在路上,配置方法可先参考 v2fly tg 群聊天记录
https://github.com/rprx/v2ray-vless/releases
文档正在路上,配置方法可先参考 v2fly tg 群聊天记录
好
最后还是把回落的配置重构了,PATH 分流目前只支持 HTTP/1.1(及 WS),因为 h2c 的首包没有 PATH
Most helpful comment
https://github.com/v2fly/v2ray-core/releases/tag/v4.27.4