ktor 在进行 https 重定向时重定向到 0.0.0.0
ktor redirecting to 0.0.0.0 when doing an https redirect
我已将 http 重定向添加到我的 Ktor 应用程序,它重定向到 https://0.0.0.0
而不是实际域的 https
@ExperimentalTime
fun Application.module() {
if (ENV.env != LOCAL) {
install(ForwardedHeaderSupport)
install(XForwardedHeaderSupport)
install(HttpsRedirect)
}
拦截路由并打印出主机
routing {
intercept(ApplicationCallPipeline.Features) {
val host = this.context.request.host()
我似乎正在为主机0:0:0:0:0:0:0:0
我是否需要向 Google Cloud 的负载平衡器添加任何特殊的 headers 才能使此 https 重定向正常工作?似乎没有选择正确的主机
由于您的 Ktor 服务器隐藏在反向代理之后,因此它没有绑定到您网站的“外部”主机。 Ktor 有特定的 feature to handle working behind reverse proxy,因此在配置和引用 request.origin.remoteHost
以获取实际主机时应该像 install(XForwardedHeaderSupport)
一样简单。
让我们看看发生了什么。
您在 http://example.org 下创建了一个服务。在 example.org 主机的 80 端口上有一个负载均衡器。它处理所有传入流量,将其路由到其背后的服务器。
您的实际应用程序是 运行 在另一台虚拟机上。它有自己的 IP 地址,位于您的云内部,可由负载均衡器访问。
让我们看看这个系统的 HTTP 请求和响应流程。
- 外部用户在 example.org 的端口 80 上使用
Host: example.org
向 GET /
发送 HTTP 请求。
- 负载均衡器获取请求,检查其规则并找到将请求定向到的内部服务器。
- 负载均衡器制作新的 HTTP 请求,主要是复制传入数据,但会更新
Host
header 并添加几个 X-Forwarded-*
header 以保留有关代理的信息请求(有关特定于 GCP 的信息,请参阅 here)。
- 请求到达您的服务器。此时您可以分析
X-Forwarded-*
headers 以查看您是否在反向代理后面,并获取实际用户发送的实际查询所需的详细信息,如原始主机。
- 您制作 HTTP 响应,然后您的服务器将其发送回负载平衡器。
- 负载均衡器将此响应传递给外部用户。
请注意,虽然有RFC 7239用于指定请求转发的信息,但GCP负载均衡器似乎使用de-facto标准X-Forwarded-*
header,因此您需要XForwardedHeaderSupport
,而不是 ForwardedHeaderSupport
(注意额外的 X)。
所以似乎 Google Cloud Load Balancer 发送了错误的 headers 或 Ktor 读取了错误的 headers 或两者都有。
我试过了
install(ForwardedHeaderSupport)
install(XForwardedHeaderSupport)
install(HttpsRedirect)
或
//install(ForwardedHeaderSupport)
install(XForwardedHeaderSupport)
install(HttpsRedirect)
或
install(ForwardedHeaderSupport)
//install(XForwardedHeaderSupport)
install(HttpsRedirect)
或
//install(ForwardedHeaderSupport)
//install(XForwardedHeaderSupport)
install(HttpsRedirect)
所有这些组合都在另一个项目上工作,但该项目使用的是旧版本的 Ktor(这是与 1.4 rc 一起发布的版本)并且该项目还使用了旧的 Google Cloud负载平衡器设置。
所以我决定自己动手。
此行将记录所有随您的请求而来的 headers,
log.info(context.request.headers.toMap().toString())
然后选择相关的并构建一个 https 重定向:
routing {
intercept(ApplicationCallPipeline.Features) {
if (ENV.env != LOCAL) {
log.info(context.request.headers.toMap().toString())
// workaround for call.request.host that contains the wrong host
// and not redirecting properly to the correct https url
val proto = call.request.header("X-Forwarded-Proto")
val host = call.request.header("Host")
val path = call.request.path()
if (host == null || proto == null) {
log.error("Unknown host / port")
} else if (proto == "http") {
val newUrl = "https://$host$path"
log.info("https redirecting to $newUrl")
// redirect browser
this.context.respondRedirect(url = newUrl, permanent = true)
this.finish()
}
}
}
我已将 http 重定向添加到我的 Ktor 应用程序,它重定向到 https://0.0.0.0
而不是实际域的 https
@ExperimentalTime
fun Application.module() {
if (ENV.env != LOCAL) {
install(ForwardedHeaderSupport)
install(XForwardedHeaderSupport)
install(HttpsRedirect)
}
拦截路由并打印出主机
routing {
intercept(ApplicationCallPipeline.Features) {
val host = this.context.request.host()
我似乎正在为主机0:0:0:0:0:0:0:0
我是否需要向 Google Cloud 的负载平衡器添加任何特殊的 headers 才能使此 https 重定向正常工作?似乎没有选择正确的主机
由于您的 Ktor 服务器隐藏在反向代理之后,因此它没有绑定到您网站的“外部”主机。 Ktor 有特定的 feature to handle working behind reverse proxy,因此在配置和引用 request.origin.remoteHost
以获取实际主机时应该像 install(XForwardedHeaderSupport)
一样简单。
让我们看看发生了什么。
您在 http://example.org 下创建了一个服务。在 example.org 主机的 80 端口上有一个负载均衡器。它处理所有传入流量,将其路由到其背后的服务器。 您的实际应用程序是 运行 在另一台虚拟机上。它有自己的 IP 地址,位于您的云内部,可由负载均衡器访问。
让我们看看这个系统的 HTTP 请求和响应流程。
- 外部用户在 example.org 的端口 80 上使用
Host: example.org
向GET /
发送 HTTP 请求。 - 负载均衡器获取请求,检查其规则并找到将请求定向到的内部服务器。
- 负载均衡器制作新的 HTTP 请求,主要是复制传入数据,但会更新
Host
header 并添加几个X-Forwarded-*
header 以保留有关代理的信息请求(有关特定于 GCP 的信息,请参阅 here)。 - 请求到达您的服务器。此时您可以分析
X-Forwarded-*
headers 以查看您是否在反向代理后面,并获取实际用户发送的实际查询所需的详细信息,如原始主机。 - 您制作 HTTP 响应,然后您的服务器将其发送回负载平衡器。
- 负载均衡器将此响应传递给外部用户。
请注意,虽然有RFC 7239用于指定请求转发的信息,但GCP负载均衡器似乎使用de-facto标准X-Forwarded-*
header,因此您需要XForwardedHeaderSupport
,而不是 ForwardedHeaderSupport
(注意额外的 X)。
所以似乎 Google Cloud Load Balancer 发送了错误的 headers 或 Ktor 读取了错误的 headers 或两者都有。
我试过了
install(ForwardedHeaderSupport)
install(XForwardedHeaderSupport)
install(HttpsRedirect)
或
//install(ForwardedHeaderSupport)
install(XForwardedHeaderSupport)
install(HttpsRedirect)
或
install(ForwardedHeaderSupport)
//install(XForwardedHeaderSupport)
install(HttpsRedirect)
或
//install(ForwardedHeaderSupport)
//install(XForwardedHeaderSupport)
install(HttpsRedirect)
所有这些组合都在另一个项目上工作,但该项目使用的是旧版本的 Ktor(这是与 1.4 rc 一起发布的版本)并且该项目还使用了旧的 Google Cloud负载平衡器设置。
所以我决定自己动手。 此行将记录所有随您的请求而来的 headers,
log.info(context.request.headers.toMap().toString())
然后选择相关的并构建一个 https 重定向:
routing {
intercept(ApplicationCallPipeline.Features) {
if (ENV.env != LOCAL) {
log.info(context.request.headers.toMap().toString())
// workaround for call.request.host that contains the wrong host
// and not redirecting properly to the correct https url
val proto = call.request.header("X-Forwarded-Proto")
val host = call.request.header("Host")
val path = call.request.path()
if (host == null || proto == null) {
log.error("Unknown host / port")
} else if (proto == "http") {
val newUrl = "https://$host$path"
log.info("https redirecting to $newUrl")
// redirect browser
this.context.respondRedirect(url = newUrl, permanent = true)
this.finish()
}
}
}