带有Apache2 SNI/主机名错误的Golang ReverseProxy [英] Golang ReverseProxy with Apache2 SNI/Hostname error
问题描述
我正在用Go编写自己的ReverseProxy.ReverseProxy应该连接我的go-web服务器和我的apache2 web服务器.但是,当我在另一个IP地址上运行反向代理时,然后在我的Apache2网络服务器上,当反向代理将请求发送到apache时,我的apache-log文件中出现以下错误.
i am writing my own ReverseProxy in Go.The ReverseProxy should connect my go-webserver and my apache2 webserver. But when I run my reverseproxy on another IP-Adress then my Apache2 webserver I got following error in my apache-logfile, when the reverseproxy sends the request to apache.
"Hosname xxxx provided via sni and hostname xxxx2 provided via http are different"
我的反向代理和运行在https上的apache-webserver.
My Reverse Proxy and apache-webserver running on 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)
}
}
也许有人对这个问题有个想法.
Perhaps someone has a idea about that issue.
推荐答案
简短示例
假设您正在向https://your-proxy.local
发起HTTP请求.您的请求处理程序采用http.Request
结构,并将其URL
字段重写为https://your-apache-backend.local
.
Short example
Say you're starting an HTTP request to https://your-proxy.local
. Your request handler takes the http.Request
struct and rewrites its URL
field to https://your-apache-backend.local
.
您没有考虑的是,原始HTTP请求还包含一个Host
标头(Host: your-proxy.local
).将同一请求传递给http://your-apache-backend.local
时,该请求中的Host
标头仍显示为Host: your-proxy.local
.这就是Apache所抱怨的.
What you have not considered, is that the original HTTP request also contained a Host
header (Host: your-proxy.local
). When passing that same request to http://your-apache-backend.local
, the Host
header in that request still says Host: your-proxy.local
. And that's what Apache is complaining about.
当您使用带服务器名称指示(SNI)的TLS时,请求主机名不仅将用于DNS解析,还将选择用于建立TLS连接的SSL证书.另一方面,HTTP 1.1 Host
标头用于通过Apache区分多个虚拟主机.这两个名称必须匹配. Apache HTTPD Wiki :
As you're using TLS with Server Name Indication (SNI), the request hostname will not only be used for DNS resolution, but also to select the SSL certificate that should be used to establish the TLS connection. The HTTP 1.1 Host
header on the other hand is used to distinguish several virtual hosts by Apache. Both names must match. This issue is also mentioned in the Apache HTTPD wiki:
SNI/请求主机名不匹配,或者SNI提供的主机名与请求不匹配.
这是浏览器错误. Apache将拒绝该请求,并显示400类型的错误.
This is a browser bug. Apache will reject the request with a 400-type error.
解决方案
也重写Host
标头.如果要保留原始的Host
标头,则可以将其存储在X-Forwarded-Host
标头中(这是非标准标头,但是在反向代理中广泛使用):
Solution
Also rewrite the Host
header. If you want to preserve the original Host
header, you can store it in an X-Forwarded-Host
header (that's a non-standard header, but it's widely used in reverse proxies):
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
}
这篇关于带有Apache2 SNI/主机名错误的Golang ReverseProxy的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!