如何在Go Fiber中无需重启应用更新HTTPS服务器TLS配置
无需重启Go Fiber应用动态更新TLS配置(Autocert HostPolicy)
核心思路
autocert.Manager的HostPolicy本质是一个函数类型,我们可以自定义支持动态更新的HostPolicy实现,通过并发安全的方式修改允许的域名列表。由于tls.Config的GetCertificate指向autocert.Manager的方法,只要Manager的HostPolicy是动态的,新的TLS请求就会自动使用最新规则,无需重启应用。
实现步骤与代码示例
1. 定义可动态更新的HostPolicy结构体
import ( "context" "sync" "golang.org/x/crypto/acme/autocert" ) // DynamicHostPolicy 支持动态更新域名白名单的HostPolicy实现 type DynamicHostPolicy struct { mu sync.RWMutex hosts map[string]bool } // NewDynamicHostPolicy 创建带初始域名列表的DynamicHostPolicy func NewDynamicHostPolicy(hosts ...string) *DynamicHostPolicy { hp := &DynamicHostPolicy{ hosts: make(map[string]bool), } for _, h := range hosts { hp.hosts[h] = true } return hp } // HostPolicy 实现autocert.HostPolicy接口 func (hp *DynamicHostPolicy) HostPolicy(ctx context.Context, host string) error { hp.mu.RLock() defer hp.mu.RUnlock() if hp.hosts[host] { return nil } return autocert.ErrHostPolicyDenied } // UpdateHosts 更新域名白名单,替换现有列表 func (hp *DynamicHostPolicy) UpdateHosts(hosts ...string) { hp.mu.Lock() defer hp.mu.Unlock() // 清空原有域名 for k := range hp.hosts { delete(hp.hosts, k) } // 添加新域名 for _, h := range hosts { hp.hosts[h] = true } }
2. 修改原Fiber TLS服务器代码
将固定的autocert.HostWhitelist替换为自定义的动态实现,并添加更新接口:
package main import ( "crypto/tls" "log" "github.com/gofiber/fiber/v2" "golang.org/x/crypto/acme/autocert" ) // 上面的DynamicHostPolicy代码放在此处或单独文件中 func main() { app := fiber.New() // 初始化动态HostPolicy,初始域名:example.com、example.net dynamicHP := NewDynamicHostPolicy("example.com", "example.net") m := &autocert.Manager{ Prompt: autocert.AcceptTOS, HostPolicy: dynamicHP.HostPolicy, // 绑定动态HostPolicy Cache: autocert.DirCache("./certs"), } cfg := &tls.Config{ GetCertificate: m.GetCertificate, NextProtos: []string{ "http/1.1", "acme-tls/1", }, } ln, err := tls.Listen("tcp", ":443", cfg) if err != nil { panic(err) } // 添加域名更新接口(生产环境需加身份验证,比如API密钥) app.Post("/update-hosts", func(c *fiber.Ctx) error { var req struct { Hosts []string `json:"hosts"` } if err := c.BodyParser(&req); err != nil { return c.Status(fiber.StatusBadRequest).SendString("请求格式错误") } if len(req.Hosts) == 0 { return c.Status(fiber.StatusBadRequest).SendString("域名列表不能为空") } dynamicHP.UpdateHosts(req.Hosts...) return c.SendString("域名列表更新成功") }) log.Fatal(app.Listener(ln)) }
3. 触发动态更新
发送POST请求到https://你的域名/update-hosts,请求体为JSON格式:
{ "hosts": ["example1.org", "example1.info"] }
更新完成后,新的TLS请求会自动使用最新的域名白名单规则。
关键说明
- 并发安全:使用读写锁
sync.RWMutex保证域名列表更新时不阻塞正常请求。 - 即时生效:每次TLS握手都会调用HostPolicy函数,读取最新的域名列表,更新后立即生效。
- 生产环境防护:更新接口必须添加安全验证(如API密钥、IP白名单),避免未授权修改。
内容的提问来源于stack exchange,提问作者Vyacheslav
相关产品推荐
相关产品推荐

