Ssl Golang ReverseProxy带有Apache2 SNI/主机名错误
我正在用Go编写自己的ReverseProxy。ReverseProxy应该连接我的Go Web服务器和我的apache2 Web服务器。但是,当我在另一个IP地址上运行reverseproxy时,我的Apache2 Web服务器在apache日志文件中出现以下错误:reverseproxy将请求发送到apacheSsl Golang ReverseProxy带有Apache2 SNI/主机名错误,ssl,go,apache2,reverse-proxy,sni,Ssl,Go,Apache2,Reverse Proxy,Sni,我正在用Go编写自己的ReverseProxy。ReverseProxy应该连接我的Go Web服务器和我的apache2 Web服务器。但是,当我在另一个IP地址上运行reverseproxy时,我的Apache2 Web服务器在apache日志文件中出现以下错误:reverseproxy将请求发送到apache "Hosname xxxx provided via sni and hostname xxxx2 provided via http are different" 我的反向代理和
"Hosname xxxx provided via sni and hostname xxxx2 provided via http are different"
我的反向代理和apache Web服务器在https上运行
下面是一些代码:
func (p *Proxy) directorApache(req *http.Request) {
mainServer := fmt.Sprintf("%s:%d", Config.HostMain, Config.PortMain)
req.URL.Scheme = "https"
req.URL.Host = mainServer
}
func (p *Proxy) directorGo(req *http.Request) {
goServer := fmt.Sprintf("%s:%d", Config.GoHost, Config.GoPort)
req.URL.Scheme = "http"
req.URL.Host = goServer
}
func (p *Proxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
fmt.Println(req.URL.Path)
if p.isGoRequest(req) {
fmt.Println("GO")
p.goProxy.ServeHTTP(rw, req)
return
}
p.httpProxy.ServeHTTP(rw, req)
}
func main() {
var configPath = flag.String("conf", "./configReverse.json", "Path to the Json config file.")
flag.Parse()
proxy := New(*configPath)
cert, err := tls.LoadX509KeyPair(Config.PathCert, Config.PathPrivateKey)
if err != nil {
log.Fatalf("server: loadkeys: %s", err)
}
config := tls.Config{InsecureSkipVerify: true, Certificates: []tls.Certificate{cert}}
listener, err := net.Listen("tcp",
net.JoinHostPort(proxy.Host, strconv.Itoa(proxy.Port)))
if err != nil {
log.Fatalf("server: listen: %s", err)
}
log.Printf("server: listening on %s")
proxy.listener = tls.NewListener(listener, &config)
serverHTTPS := &http.Server{
Handler: proxy.mux,
TLSConfig: &config,
}
if err := serverHTTPS.Serve(proxy.listener); err != nil {
log.Fatal("SERVER ERROR:", err)
}
}
也许有人对这个问题有想法。举个简单的例子
假设您正在启动对https://your-proxy.local
。您的请求处理程序接受http.request
struct并将其URL
字段重写为https://your-apache-backend.local
您没有考虑的是,原始HTTP请求还包含一个Host
头(Host:your proxy.local
)。将相同的请求传递给http://your-apache-backend.local
,该请求中的Host
标题仍然显示Host:your proxy.local
。这就是Apache所抱怨的
解释
当您使用带有服务器名称指示(SNI)的TLS时,请求主机名不仅将用于DNS解析,还将用于选择用于建立TLS连接的SSL证书。另一方面,HTTP 1.1Host
头用于Apache区分多个虚拟主机。两个名称必须匹配。以下文件中也提到了这一问题:
SNI/请求主机名不匹配,或者SNI提供主机名而请求不提供。
这是一个浏览器错误。Apache将以400类型错误拒绝该请求
解决方案
同时重写主机标题。如果要保留原始的Host
头,可以将其存储在X-Forwarded-Host
头中(这是一个非标准头,但在反向代理中广泛使用):
简短的例子
假设您正在启动对https://your-proxy.local
。您的请求处理程序接受http.request
struct并将其URL
字段重写为https://your-apache-backend.local
您没有考虑的是,原始HTTP请求还包含一个Host
头(Host:your proxy.local
)。将相同的请求传递给http://your-apache-backend.local
,该请求中的Host
标题仍然显示Host:your proxy.local
。这就是Apache所抱怨的
解释
当您使用带有服务器名称指示(SNI)的TLS时,请求主机名不仅将用于DNS解析,还将用于选择用于建立TLS连接的SSL证书。另一方面,HTTP 1.1Host
头用于Apache区分多个虚拟主机。两个名称必须匹配。以下文件中也提到了这一问题:
SNI/请求主机名不匹配,或者SNI提供主机名而请求不提供。
这是一个浏览器错误。Apache将以400类型错误拒绝该请求
解决方案
同时重写主机标题。如果要保留原始的Host
头,可以将其存储在X-Forwarded-Host
头中(这是一个非标准头,但在反向代理中广泛使用):
感谢您的好主意和解决方案。你说得对,我没想过。但我有一个问题。首先,我的req.Header根本没有主机字段。我手动添加了x转发主机。但是仅仅设置主机头并不能解决这个问题,我也遇到了同样的错误。所以我尝试直接设置req.Host。然后Apache错误被解决了,但是我的站点没有加载任何其他内容,我认为我在Apache上的php出现了一个错误。我认为请求有问题,因为我更换了主机?所以我认为它解决了问题。但是您必须使用req.Host=mainServer,因为请求头不会被使用,您认为它属于这个问题:think与此有关:我在之前的评论中提到的问题是我的AngularJS,因为不安全的Resource加载,因为我的reverseproxy运行在与我的AngularJS不同的ip上。在赫尔姆伯特向你开火。你让我高兴:)很乐意帮忙。我还更新了我的答案,以反映
req.Host=mainServer
的更改。我想我还有另一个问题,当我更改req.Host时,我在ReverseProxy上没有收到任何新的请求。也许是因为主机发送的响应或新请求是错误的?我现在不知道。我的意思是apache问题已经解决了,但现在我的reverseProxy无法正常工作。他从apache为我的网站提供服务,但当用户对其进行操作时,他没有收到新的请求。如果是另一个问题,可能值得一个新问题。也许也会帮助你。谢谢你的好主意和解决方案。你说得对,我没想过。但我有一个问题。首先,我的req.Header根本没有主机字段。我手动添加了x转发主机。但是仅仅设置主机头并不能解决这个问题,我也遇到了同样的错误。所以我尝试直接设置req.Host。然后Apache错误被解决了,但是我的站点没有加载任何其他内容,我认为我在Apache上的php出现了一个错误。我认为请求有问题,因为我更换了主机?所以我认为它解决了问题。但是您必须使用req.Host=mainServer,因为请求头不会被使用,您认为它属于这个问题:think与此有关:我在之前的评论中提到的问题是我的AngularJS,因为不安全的Resource加载,因为我的reverseproxy运行在与我的AngularJS不同的ip上。在赫尔姆伯特向你开火。你让我高兴:)很乐意帮忙。我还更新了我的答案,以反映req.Host=mainServer
的更改。我想我还有另一个问题,我没有收到任何新的req
func (p *Proxy) directorApache(req *http.Request) {
mainServer := fmt.Sprintf("%s:%d", Config.HostMain, Config.PortMain)
req.URL.Scheme = "https"
req.URL.Host = mainServer
req.Header.Set("X-Forwarded-Host", req.Header().Get("Host"))
req.Host = mainServer
}