153 lines
4.2 KiB
Go
153 lines
4.2 KiB
Go
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()
|
||
}
|