frp配置https转发,并且强制http请求跳转到https

标签: frp ;


  1. 首先把 frps 安装在公网服务器上,配置frps.toml,让它在 80 和 443 端口上监听
bindPort = 7070

vhostHTTPPort = 80
vhostHTTPSPort = 443

auth.method = "token"
auth.token = "TOKEN HERE"
  1. 在内网服务器上配置好Nginx及ssl证书。在我的环境中,通过动态绑定 IPv6 地址,从外网访问 https 成功后,确认 ssl 工作正常。然后从Nginx配置中删除 https 配置的相关段,只保留 http 部分。

  2. 在内网服务器上安装 frpc, 并分别开启 http 和 https 两个代理。

全局设置:

serverAddr = "外网服务器地址"
serverPort = 7070

auth.method = "token"
auth.token = "TOKEN HERE"

接下来配置 https:

[[proxies]]
name = "https"
type = "https"
customDomains = ["www.example.com"]

[proxies.plugin]
type = "https2http"
localAddr = "127.0.0.1:80"
crtPath = "/path/to/fullchain.pem"
keyPath = "/path/to/privkey.pem"
hostHeaderRewrite ="www.example.com"

通过 crtPath 和 keyPath 配置正确的证书后,从客户端到 frps 再到 frpc 的通信都是加密的,最终,frpc 再将明文转发给相同机器上的 80 端口,即 Nginx.

这里最关键的除了证书配置外,就是hostHeaderRewrite,通过修改请求头中的 Host 字段,确保背后的 Nginx 知道客户想要访问的是那个域名。

如果配置没问题,此时 https 应该是通了。但是 http 还没有配置。这多少会有一些问题。如果配置 frp 直接转发 http 请求,https 相当于形同虚设。在没有 frp 挡在前面的情况下,让 Nginx 强制跳转到 https是很简单的,但是此时frp接管了 https 通信, Nginx 本身也是裸奔的,它只通过 80 端口和 frpc 进行通信,它怎么知道客户是通过 http 还是 https 发起的请求呢?解决的办法还是让 frp 修改请求头。

  1. 强制 http 跳转到 https
[[proxies]]
name = "http"
type = "http"
customDomains = ["www.example"]
localIP = "127.0.0.1"
localPort = 80
hostHeaderRewrite = "www.example"
requestHeaders.set.x-from-where = "frp"

最后一句,在http请求头中添加一条 x-from-where, 将值设为 frp.

最后,当 Nginx 检测到请求头中包含有 x-from-where: frp后,它就知道该请求是通过 http 发起的,接下来,Nginx返回一个 301, 让客户端自动跳转到 https:

if ($http_x_from_where = 'frp') {
    return 301 https://$host$request_uri;
}