Description
I have nginx as Reverse Proxy for sing-box (VPN server) with following configuration
stream {
map $ssl_preread_server_name $singbox {
some.example.com trojan;
}
upstream trojan {
server 127.0.0.1:8080;
}
server {
listen 443 reuseport;
proxy_pass $singbox;
ssl_preread on;
proxy_protocol on;
}
}
thus, i'm just wondering 'can i use gin instead of nginx' ? Tried to configure gin with following code: [How to reproduce]
But gin response with: http: proxy error: context canceled
And so on the sing-box side: http: Accept error: proxyproto: proxy protocol signature not present; retrying in 1s
How to reproduce
package main
import (
"fmt"
"net/http"
"net/http/httputil"
"github.com/gin-gonic/gin"
)
func main() {
// Create a new gin-gonic router
r := gin.Default()
// Add a new route to the router that will handle requests to the endpoint you want to proxy
r.GET("/wss", func(c *gin.Context) {
// Use the ReverseProxy function from the net/http/httputil package to forward the request to the backend server
director := func(req *http.Request) {
req.URL.Scheme = "http"
req.URL.Host = "localhost:8080"
fmt.Println(req.Header)
}
proxy := &httputil.ReverseProxy{Director: director}
proxy.ServeHTTP(c.Writer, c.Request)
})
r.GET("/", func(c *gin.Context) {
c.String(200, "OK")
})
// Start the gin-gonic server
r.RunTLS(":443", "/etc/certs/cert.pem", "/etc/certs/key.pem")
}
Expectations
Gin to work as nginx as reverse proxy
Actual result
Gin: http: proxy error: context canceled
Sing-box: http: Accept error: proxyproto: proxy protocol signature not present; retrying in 1s
Environment
- go version: go1.18.1
- gin version (or commit ref): v1.9.0
- operating system: Ubuntu 22.04.2
Comment From: yousifnimah
The issue you're encountering with using Gin as a reverse proxy is related to the handling of the Proxy Protocol. In your NGINX configuration, you have enabled the proxy_protocol directive, which allows NGINX to communicate the client's original IP address to the backend server. However, in your Gin code, you haven't implemented the Proxy Protocol support.
To resolve the issue and make Gin work as a reverse proxy with Proxy Protocol support, you can use the github.com/pires/go-proxyproto package. This package provides a middleware for Gin that handles the Proxy Protocol headers. Here's an updated version of your code that includes the necessary modifications:
package main
import (
"fmt"
"net/http"
"net/http/httputil"
"github.com/gin-gonic/gin"
"github.com/pires/go-proxyproto"
)
func main() {
r := gin.Default()
r.Use(proxyproto.NewProxyProtocolMiddleware())
r.GET("/wss", func(c *gin.Context) {
director := func(req *http.Request) {
req.URL.Scheme = "http"
req.URL.Host = "localhost:8080"
fmt.Println(req.Header)
}
proxy := &httputil.ReverseProxy{Director: director}
proxy.ServeHTTP(c.Writer, c.Request)
})
r.GET("/", func(c *gin.Context) {
c.String(200, "OK")
})
r.RunTLS(":443", "/etc/certs/cert.pem", "/etc/certs/key.pem")
}