我在Go中编写自己的ReverseProxy.ReverseProxy应该连接我的go-webserver和我的apache2 webserver。但是当我在另一个IP-Adress上运行我的reverseeproxy然后我的Apache2 webserver我的apache-logfile中出现以下错误,当reverseeproxy将请求发送到apache时。
"Hosname xxxx provided via sni and hostname xxxx2 provided via http are different"
我的反向代理和运行在https上的apache-webserver。
这里有一些代码:
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)
}
}
也许有人对这个问题有所了解。
答案 0 :(得分:3)
假设您正在向https://your-proxy.local
发起HTTP请求。您的请求处理程序采用http.Request
结构并将其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.1 Host
标头用于通过Apache区分多个虚拟主机。两个名称必须匹配。 Apache HTTPD wiki:
SNI /请求主机名不匹配,或者SNI提供的主机名和请求没有。
这是一个浏览器错误。 Apache将拒绝400类错误的请求。
同样重写Host
标题。如果要保留原始Host
标头,可以将其存储在X-Forwarded-Host
标头中(这是非标准标头,但它在反向代理中广泛使用):
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
}