Files
demo/cmd/https_reverse_proxy.go
2025-03-14 18:50:49 +00:00

153 lines
4.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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()
}