frp icon indicating copy to clipboard operation
frp copied to clipboard

https多域名开启后,对于通配符域名SSL证书无法支持,会自动重定向到其中一个网站;同一时间只能一个子域名能正常访问

Open BInodes-official opened this issue 1 year ago • 4 comments

Bug Description

通配符域名无法支持 当给每个子域名切换成各自的单域名证书时 网站访问正常

frpc Version

0.58.1

frps Version

0.58.1

System Architecture

ubuntu

Configurations

FRPS配置: bindPort = 7000 vhostHTTPPort = 80 vhostHTTPSPort=443

FRPC配置: 域名1: [[proxies]] name = "plugin_https2http_dify" type = "https" customDomains = ["dify.bistudio.com.cn"] transport.proxyProtocolVersion = "v2" # 获取真实IP [proxies.plugin] type = "https2http" localAddr = "127.0.0.1:2111" crtPath = "/home/adminpc/deploy/nginx/conf.d/ssl/all.bistudio.com.cn/all.bistudio.com.cn.crt" keyPath = "/home/adminpc/deploy/nginx/conf.d/ssl/all.bistudio.com.cn/all.bistudio.com.cn.key" #hostHeaderRewrite = "127.0.0.1" requestHeaders.set.x-from-where = "frp"

域名2: [[proxies]] name = "plugin_https2http_lobe-chat" type = "https" customDomains = ["lobe-chat.bistudio.com.cn"] transport.proxyProtocolVersion = "v2" # 获取真实IP [proxies.plugin] type = "https2http" localAddr = "127.0.0.1:2104" crtPath = "/home/adminpc/deploy/nginx/conf.d/ssl/all.bistudio.com.cn/all.bistudio.com.cn.crt" keyPath = "/home/adminpc/deploy/nginx/conf.d/ssl/all.bistudio.com.cn/all.bistudio.com.cn.key" requestHeaders.set.x-from-where = "frp"

Logs

log观察一直都是正常的,没有报错 ----刚观察到frpc访问会报: 2024-06-28 14:46:10.467 [W] [httputil/reverseproxy.go:661] http: proxy error: context canceled 2024-06-28 14:46:10.467 [W] [httputil/reverseproxy.go:661] http: proxy error: context canceled

Steps to reproduce

...

Affected area

  • [ ] Docs
  • [ ] Installation
  • [ ] Performance and Scalability
  • [ ] Security
  • [ ] User Experience
  • [ ] Test and Release
  • [ ] Developer Infrastructure
  • [ ] Client Plugin
  • [ ] Server Plugin
  • [ ] Extensions
  • [ ] Others

BInodes-official avatar Jun 28 '24 06:06 BInodes-official

https://github.com/fatedier/frp/issues/4278#issuecomment-2166020723

xqzr avatar Jun 28 '24 08:06 xqzr

#4278 (comment)

感谢提示,我中间没有nginx,全部用的frp进行的https网站访问多子域名复用443端口 看了文章,目前暂未找到在frp中禁用TLS Session Ticket的方法

BInodes-official avatar Jun 28 '24 10:06 BInodes-official

之所以我的需求是直接用frps透传,是因为AI大模型文字输出上,各种实测后Frp是文字输出性能最高的!没有之一!

1、如果我最外层用nginx和泛域名证书转发内部frp一层后,文字输出速度呈断崖式下降! 2、但如果直接用frp的https2http插件透传出来,最外层不经过nginx, 对话AI模型可以马上输出结果,性能很高! 可惜只支持单域名,不支持泛域名!

作为一个使用了frp达6年的用户,从frp的0.2X版本一直用到现在,一直在生产环境使用,非常稳定从未失望过! 麻烦作者帮看看有没有办法,谢谢了!

PS:目前最外层用nginx加了一层代理后,千问2模型的token响应很慢,网址:https://www.bistudio.com.cn ,我真不知道为什么外面套一层nginx为什么会比原生frp的https2http慢这么多!也许学艺不精

BInodes-official avatar Jun 28 '24 16:06 BInodes-official

----------------2024年6月29日凌晨更新 根据对nginx的研究,在server中加入如下配置后,可以保障AI模型文字的流式输出性能:

proxy_cache off; # 关闭缓存 proxy_buffering off; # 关闭代理缓冲 chunked_transfer_encoding on; # 开启分块传输编码 tcp_nopush on; # 开启TCP NOPUSH选项,禁止Nagle算法 tcp_nodelay on; # 开启TCP NODELAY选项,禁止延迟ACK算法 keepalive_timeout 300; # 设定keep-alive超时时间为65秒

frp还是正常可以作为后端http穿透

问题已解决,软件还是有各自的边界更好,谢谢

BInodes-official avatar Jun 28 '24 16:06 BInodes-official

我也和你一样遇到同样的问题

客户端:

serverAddr = "1.2.3.4"
serverPort = 443
transport.protocol = "tcp"
transport.tls.disableCustomTLSFirstByte = false
auth.token = "123456"

[[proxies]]
name = "docker-nginx"
type = "https"
customDomains = ["w-1.test.com", "w-2.test.com", "w-3.test.com"]
[proxies.plugin]
type = "https2http"
localAddr = "nginx:80"
crtPath = "/etc/frp/ssl/xxx.com.cer"
keyPath = "/etc/frp/ssl/xxx.com.key"

[[proxies]]
name = "host-web"
type = "https"
customDomains = ["w-4.test.com", "w-5.test.com"]
[proxies.plugin]
type = "https2http"
localAddr = "docker.localhost:88"
crtPath = "/etc/frp/ssl/xxx.com.cer"
keyPath = "/etc/frp/ssl/xxx.com.key"

前面 w-1、w-2、w-3 正常,那么后面 w-4、w-5 也无法正常访问,会加载前的 1-3 的默认证书和网站内容, 重启之后,后面的可以了,那么前的就不行,每次重启都随机的,就无法全部正确加载域名所对应的web

也不是上面你说的 nginx,我贴出来的只有两组 https2http,其实我是有4组,只有一组是 nginx 的,其他的都不是 nginx 的web 服务。同样会出现混乱的加载的情况。配置 localAddr 是不同内的 IP 上的 web。估计是逻辑上的问题 出现域名无法准确的对应上内网的 localAddr 的 web服务

@fatedier

haodiao avatar Jul 04 '24 18:07 haodiao

我也和你一样遇到同样的问题

客户端:

serverAddr = "1.2.3.4"
serverPort = 443
transport.protocol = "tcp"
transport.tls.disableCustomTLSFirstByte = false
auth.token = "123456"

[[proxies]]
name = "docker-nginx"
type = "https"
customDomains = ["w-1.test.com", "w-2.test.com", "w-3.test.com"]
[proxies.plugin]
type = "https2http"
localAddr = "nginx:80"
crtPath = "/etc/frp/ssl/xxx.com.cer"
keyPath = "/etc/frp/ssl/xxx.com.key"

[[proxies]]
name = "host-web"
type = "https"
customDomains = ["w-4.test.com", "w-5.test.com"]
[proxies.plugin]
type = "https2http"
localAddr = "docker.localhost:88"
crtPath = "/etc/frp/ssl/xxx.com.cer"
keyPath = "/etc/frp/ssl/xxx.com.key"

前面 w-1、w-2、w-3 正常,那么后面 w-4、w-5 也无法正常访问,会加载前的 1-3 的默认证书和网站内容, 重启之后,后面的可以了,那么前的就不行,每次重启都随机的,就无法全部正确加载域名所对应的web

也不是上面你说的 nginx,我贴出来的只有两组 https2http,其实我是有4组,只有一组是 nginx 的,其他的都不是 nginx 的web 服务。同样会出现混乱的加载的情况。配置 localAddr 是不同内的 IP 上的 web。估计是逻辑上的问题 出现域名无法准确的对应上内网的 localAddr 的 web服务

@fatedier

最外层挂nginx。 FRP只做内网穿透,不做https服务,这样挂多少个域名都不会混乱;至少我是这样解决的

BInodes-official avatar Jul 06 '24 09:07 BInodes-official

@osbi-code 你 nginx 的配置可以贴一下?nginx 上是否启用了 http2?

我目前观察下来,在 go https server 里关闭 TLS Session Ticket 也不会起到作用。只有禁用 http2 才可以,不太确定你的 nginx 配置是因为禁用了 http2 才解决问题,还是因为 TLS Session Ticket 的配置解决了问题。

fatedier avatar Jul 08 '24 09:07 fatedier

@fatedier 我不会 go 没看得懂 https2http 插件逻辑, 建立 ssl/tls 握手的在 frpc 端进行还是在 frps 端。

不知道目前是不是在 frps端,如果不是,我就建议是把 https 服务放到 frps 端,把所有 frpc 的 customDomains 里的域名的 SSL 证书都挨个上传到 frps 并放到一个列表里,列表里标记有哪些 frpc 的哪些 localAddr 服务,也就是一个对应关系的列表, (还要维护一下某个 frpc 退出之后要从列表里删除对应域名和 SSL), 当有访问时,frps 就获取当前访问的域名之后查询这个域名关系列表,取出对应 SSL 来建立握手,握手成功之后再把 http 的请求通过隧道转发给对应 frpc 里 localAddr 的 http 服务器上。

haodiao avatar Jul 08 '24 11:07 haodiao

@fatedier 我不会 go 没看得懂 https2http 插件逻辑, 建立 ssl/tls 握手的在 frpc 端进行还是在 frps 端。

不知道目前是不是在 frps端,如果不是,我就建议是把 https 服务放到 frps 端,把所有 frpc 的 customDomains 里的域名的 SSL 证书都挨个上传到 frps 并放到一个列表里,列表里标记有哪些 frpc 的哪些 localAddr 服务,也就是一个对应关系的列表, (还要维护一下某个 frpc 退出之后要从列表里删除对应域名和 SSL), 当有访问时,frps 就获取当前访问的域名之后查询这个域名关系列表,取出对应 SSL 来建立握手,握手成功之后再把 http 的请求通过隧道转发给对应 frpc 里 localAddr 的 http 服务器上。

这个问题具体可以看这里: https://github.com/fatedier/frp/issues/628#issuecomment-473147400

https 目前在 frp 里就是一个 SNI proxy,不涉及证书,也不会解析请求,只根据 SNI 信息做连接路由。

大部分情况下,frps 是公用的,证书都放在服务端不太合适。当然,未来 v2 版本也会考虑更多其他的使用场景。

fatedier avatar Jul 08 '24 12:07 fatedier

@osbi-code 你 nginx 的配置可以贴一下?nginx 上是否启用了 http2?

我目前观察下来,在 go https server 里关闭 TLS Session Ticket 也不会起到作用。只有禁用 http2 才可以,不太确定你的 nginx 配置是因为禁用了 http2 才解决问题,还是因为 TLS Session Ticket 的配置解决了问题。

我的最外层nginx配置:

server {

        listen 443 ssl;
        #对应的域名  
        server_name  *.bistudio.com.cn;
        ssl_certificate /etc/nginx/conf.d/ssl/all.bistudio.com.cn/all.bistudio.com.cn.crt;
        ssl_certificate_key /etc/nginx/conf.d/ssl/all.bistudio.com.cn/all.bistudio.com.cn.key;
        ssl_session_timeout 5m;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
        ssl_prefer_server_ciphers on;

        # 添加内容安全策略头部  
        add_header Content-Security-Policy "upgrade-insecure-requests";
        location / {
                proxy_set_header Host $host;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_pass http://localhost:8090;
                proxy_cache off;  # 关闭缓存
                proxy_buffering off;  # 关闭代理缓冲
                chunked_transfer_encoding on;  # 开启分块传输编码
                tcp_nopush on;  # 开启TCP NOPUSH选项,禁止Nagle算法
                tcp_nodelay on;  # 开启TCP NODELAY选项,禁止延迟ACK算法
                keepalive_timeout 300;  # 设定keep-alive超时时间为65秒
        }

其中:http://localhost:8090; 是转发到对应的frp内网穿透服务,服务端配置: frps:

bindPort = 7000
vhostHTTPPort = 8090
subdomainHost = "bistudio.com.cn"

客户端配置:

# frpc.toml
[[proxies]]
name = "web_mj"
type = "http"
localPort = 2105
subdomain = "midjourney"

注:我最终并没有使用https2http插件直接穿透外网使用443端口,SSL证书仍然在服务端上,最外层用nginx转发了一道。 因为经过测试,直接使用https2http插件在客户端上使用SSL证书,将导致无法支持泛域名解析,只能是随机子域名访问,该问题无法解决

BInodes-official avatar Jul 08 '24 12:07 BInodes-official

@osbi-code 你 nginx 的配置应该是没开启 http2 的,所以不存在这个问题。

你可以用 https://github.com/fatedier/frp/pull/4323 这个 PR 的代码编译一个版本进行测试,预计明天会基于这个代码发一个新版本。

目前的解决方案是对于 SNI 和 host 不匹配的请求,返回 421,一般的浏览器会通过新建连接进行重试从而使请求正常。目前测试下来只有 safari 的行为不正常,其他浏览器基本上都能正常工作。

对于少数浏览器不正常的情况,增加了 enableHTTP2 配置项,默认为 true,通过配置为 false 禁用 http2 来避免这个问题。

fatedier avatar Jul 08 '24 13:07 fatedier

这个问题具体可以看这里: #628 (comment)

https 目前在 frp 里就是一个 SNI proxy,不涉及证书,也不会解析请求,只根据 SNI 信息做连接路由。

大部分情况下,frps 是公用的,证书都放在服务端不太合适。当然,未来 v2 版本也会考虑更多其他的使用场景。

那可以考虑增加这种 把 SSL 证书上传到 frps 的场景,可以在配置和文档写一下说明上传证书的的风险提示语。
这样就可以正常的开启 http2 甚至是 http3。

当然如果能在现有的模式基础上解决这个问题那最好了,SNI proxy 在 http2 确实会有连接复用时无法正确路由对应的域名,虽然返回 421 也只是有所缓解而已,当然要完全实现正确的路由,可能需要记录对应的 TLS Session ID 来进行匹配才行。frps 进行抓包获取 TLS Session ID 并记录这是由哪个 frpc 发出的,然后以此来匹配对应的连路。 这样实现起来可能会比较复杂,但我更倾向于上传 SSL 到 frps 的方式

haodiao avatar Jul 08 '24 14:07 haodiao

frps 进行抓包获取 TLS Session ID 并记录这是由哪个 frpc 发出的

属于 DPI

xqzr avatar Jul 08 '24 15:07 xqzr

那可以考虑增加这种 把 SSL 证书上传到 frps 的场景,可以在配置和文档写一下说明上传证书的的风险提示语。 这样就可以正常的开启 http2 甚至是 http3。

这不是同一个问题,你这个可以理解为一个新的 feature,在 v2 的计划里,比较长期,目前暂时不过多讨论。

fatedier avatar Jul 09 '24 02:07 fatedier

up主可以参考下这个方案:https://mp.weixin.qq.com/s/V4-k8kUd1c70taGH4BIuHw

weiIPcool avatar Jul 29 '24 01:07 weiIPcool

我的最外层nginx配置:

server {

        listen 443 ssl;
        #对应的域名  
        server_name  *.bistudio.com.cn;
        ssl_certificate /etc/nginx/conf.d/ssl/all.bistudio.com.cn/all.bistudio.com.cn.crt;
        ssl_certificate_key /etc/nginx/conf.d/ssl/all.bistudio.com.cn/all.bistudio.com.cn.key;
        ssl_session_timeout 5m;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
        ssl_prefer_server_ciphers on;

        # 添加内容安全策略头部  
        add_header Content-Security-Policy "upgrade-insecure-requests";
        location / {
                proxy_set_header Host $host;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_pass http://localhost:8090;
                proxy_cache off;  # 关闭缓存
                proxy_buffering off;  # 关闭代理缓冲
                chunked_transfer_encoding on;  # 开启分块传输编码
                tcp_nopush on;  # 开启TCP NOPUSH选项,禁止Nagle算法
                tcp_nodelay on;  # 开启TCP NODELAY选项,禁止延迟ACK算法
                keepalive_timeout 300;  # 设定keep-alive超时时间为65秒
        }

其中:http://localhost:8090; 是转发到对应的frp内网穿透服务,服务端配置: frps:

bindPort = 7000
vhostHTTPPort = 8090
subdomainHost = "bistudio.com.cn"

客户端配置:

# frpc.toml
[[proxies]]
name = "web_mj"
type = "http"
localPort = 2105
subdomain = "midjourney"

注:我最终并没有使用https2http插件直接穿透外网使用443端口,SSL证书仍然在服务端上,最外层用nginx转发了一道。 因为经过测试,直接使用https2http插件在客户端上使用SSL证书,将导致无法支持泛域名解析,只能是随机子域名访问,该问题无法解决

我一直用0.36.2版本也是这样配置的(唯一不同我使用custom domains),这两天突然出现frps会死掉情况。 然后昨天升级到0.60,出现访问了https网站,网站加载出http链接,导致chrome报错 block-mixed content。 你有这样的问题吗?

DaPoHou avatar Sep 27 '24 22:09 DaPoHou