package main import ( "crypto/tls" "flag" "fmt" "log" "net" "net/http" "os" "os/signal" "syscall" "github.com/darkit/goproxy" "github.com/darkit/goproxy/config" ) func main() { // 解析命令行参数 var ( listenAddr = flag.String("listen", ":443", "HTTPS监听地址") httpAddr = flag.String("http", ":80", "HTTP监听地址,用于重定向到HTTPS") targetAddr = flag.String("target", "http://localhost:8080", "目标服务地址") certFile = flag.String("cert", "server.crt", "TLS证书文件") keyFile = flag.String("key", "server.key", "TLS私钥文件") autoRedirect = flag.Bool("redirect", true, "自动将HTTP请求重定向到HTTPS") insecureSkipVerify = flag.Bool("insecure", false, "跳过目标HTTPS验证") ) flag.Parse() // 检查证书和私钥文件 if !fileExists(*certFile) || !fileExists(*keyFile) { log.Printf("证书或私钥文件不存在: %s, %s", *certFile, *keyFile) if *autoRedirect { log.Printf("将只启动HTTP服务") } else { log.Fatalf("无法启动HTTPS服务,请提供有效的证书和私钥文件") } } // 创建配置 cfg := config.DefaultConfig() // 配置反向代理 cfg.ReverseProxy = true // 启用反向代理模式 cfg.ListenAddr = *listenAddr // HTTPS监听地址 cfg.TargetAddr = *targetAddr // 目标地址 cfg.DecryptHTTPS = true // 启用HTTPS cfg.TLSCert = *certFile // 证书文件 cfg.TLSKey = *keyFile // 私钥文件 cfg.PreserveClientIP = true // 保留客户端IP cfg.AddXForwardedFor = true // 添加X-Forwarded-For头 cfg.InsecureSkipVerify = *insecureSkipVerify // 是否跳过目标HTTPS验证 // 创建代理实例 proxy := goproxy.New(&goproxy.Options{ Config: cfg, }) // 创建HTTPS服务器 httpsServer := &http.Server{ Addr: *listenAddr, Handler: proxy, TLSConfig: &tls.Config{ MinVersion: tls.VersionTLS12, }, } // 创建HTTP重定向服务器 var httpServer *http.Server if *autoRedirect { httpServer = &http.Server{ Addr: *httpAddr, Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // 构建重定向URL host := r.Host // 如果Host包含端口,去除端口 if h, _, err := net.SplitHostPort(host); err == nil { host = h } // 构建HTTPS URL target := "https://" + host // 如果HTTPS端口不是443,添加端口 if *listenAddr != ":443" { _, port, _ := net.SplitHostPort(*listenAddr) if port != "" && port != "443" { target = "https://" + host + ":" + port } } // 添加路径和查询参数 target += r.URL.Path if r.URL.RawQuery != "" { target += "?" + r.URL.RawQuery } // 重定向 http.Redirect(w, r, target, http.StatusMovedPermanently) }), } } // 优雅退出 quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) // 启动HTTPS服务器 if fileExists(*certFile) && fileExists(*keyFile) { go func() { fmt.Printf("HTTPS反向代理启动在 %s,转发到 %s\n", *listenAddr, *targetAddr) if err := httpsServer.ListenAndServeTLS(*certFile, *keyFile); err != nil && err != http.ErrServerClosed { log.Printf("HTTPS服务器启动失败: %v\n", err) } }() } // 启动HTTP重定向服务器 if *autoRedirect && httpServer != nil { go func() { fmt.Printf("HTTP重定向服务启动在 %s\n", *httpAddr) if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Printf("HTTP服务器启动失败: %v\n", err) } }() } // 等待退出信号 <-quit fmt.Println("服务器正在关闭...") // 关闭服务器 if httpServer != nil { if err := httpServer.Close(); err != nil { log.Printf("HTTP服务器关闭失败: %v\n", err) } } if fileExists(*certFile) && fileExists(*keyFile) { if err := httpsServer.Close(); err != nil { log.Printf("HTTPS服务器关闭失败: %v\n", err) } } fmt.Println("服务器已关闭") } // 检查文件是否存在 func fileExists(filename string) bool { info, err := os.Stat(filename) if os.IsNotExist(err) { return false } return !info.IsDir() }