参考 stackoverflowhttps://stackoverflow.com/questions/37473201/is-there-a-way-to-update-the-tls-certificates-in-a-net-http-server-without-any-d代码如下 ,http是用github.com/gogf/gf 框架。
package main
import (
"crypto/tls"
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/net/ghttp"
"sync"
)
// 调用
func main() {
s := g.Server("proxy")
err := UpdateSsl("./ssl/cert.txt", "./ssl/key.txt", s)
if err != nil {
g.Log().Error(err)
return
}
s.Group("/api", func(group *ghttp.RouterGroup) {
group.POST("/ssl_renew", func(r *ghttp.Request) {
err := ReloadSSL()
if err != nil {
return
}
r.Response.Writeln("更新完成")
})
})
s.Run()
}
//==============================================
type keypairReloader struct {
certMu sync.RWMutex
cert *tls.Certificate
certPath string
keyPath string
}
func NewKeypairReloader(certPath, keyPath string) (*keypairReloader, error) {
result := &keypairReloader{
certPath: certPath,
keyPath: keyPath,
}
cert, err := tls.LoadX509KeyPair(certPath, keyPath)
if err != nil {
return nil, err
}
result.cert = &cert
return result, nil
}
func (kpr *keypairReloader) maybeReload() error {
newCert, err := tls.LoadX509KeyPair(kpr.certPath, kpr.keyPath)
if err != nil {
return err
}
kpr.certMu.Lock()
defer kpr.certMu.Unlock()
kpr.cert = &newCert
g.Log().Info("ssl 加载成功!")
return nil
}
func (kpr *keypairReloader) GetCertificateFunc() func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
return func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
kpr.certMu.RLock()
defer kpr.certMu.RUnlock()
return kpr.cert, nil
}
}
var kpr *keypairReloader
// 启用https服务
// 框架 github.com/gogf/gf,这个方法可以优化优化,改成其他框架
func UpdateSsl(certPath, keyPath string, s *ghttp.Server) error {
var err error
kpr, err = NewKeypairReloader(certPath, keyPath)
if err != nil {
return err
}
var ssl_tls = &tls.Config{
MinVersion: tls.VersionTLS12,
MaxVersion: tls.VersionTLS13,
}
ssl_tls.GetCertificate = kpr.GetCertificateFunc()
s.SetTLSConfig(ssl_tls)
s.EnableHTTPS(certPath, keyPath, ssl_tls)
return nil
}
// 外部调用这个方法
func ReloadSSL() error {
if kpr == nil {
return nil
}
return kpr.maybeReload()
}