123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- package cert
- import (
- "runtime"
- "strings"
- "time"
- "github.com/0xJacky/Nginx-UI/internal/notification"
- "github.com/0xJacky/Nginx-UI/model"
- "github.com/0xJacky/Nginx-UI/settings"
- "github.com/pkg/errors"
- "github.com/uozi-tech/cosy/logger"
- )
- func AutoCert() {
- defer func() {
- if err := recover(); err != nil {
- buf := make([]byte, 1024)
- runtime.Stack(buf, false)
- logger.Errorf("%s\n%s", err, buf)
- }
- }()
- logger.Info("AutoCert Worker Started")
- autoCertList := model.GetAutoCertList()
- for _, certModel := range autoCertList {
- autoCert(certModel)
- }
- logger.Info("AutoCert Worker End")
- }
- func autoCert(certModel *model.Cert) {
- confName := certModel.Filename
- log := NewLogger()
- log.SetCertModel(certModel)
- defer log.Close()
- if len(certModel.Filename) == 0 {
- log.Error(ErrCertModelFilenameEmpty)
- return
- }
- if len(certModel.Domains) == 0 {
- log.Error(errors.New("domains list is empty, " +
- "try to reopen auto-cert for this config:" + confName))
- notification.Error("Renew Certificate Error", confName, nil)
- return
- }
- if certModel.SSLCertificatePath == "" {
- log.Error(errors.New("ssl certificate path is empty, " +
- "try to reopen auto-cert for this config:" + confName))
- notification.Error("Renew Certificate Error", confName, nil)
- return
- }
- certInfo, err := GetCertInfo(certModel.SSLCertificatePath)
- if err != nil {
- // Get certificate info error, ignore this certificate
- log.Error(errors.Wrap(err, "get certificate info error"))
- notification.Error("Renew Certificate Error", strings.Join(certModel.Domains, ", "), nil)
- return
- }
- // Calculate certificate age (days since NotBefore)
- certAge := int(time.Since(certInfo.NotBefore).Hours() / 24)
- // Calculate days until expiration
- daysUntilExpiration := int(time.Until(certInfo.NotAfter).Hours() / 24)
- // Calculate total certificate validity period
- totalValidityDays := int(certInfo.NotAfter.Sub(certInfo.NotBefore).Hours() / 24)
- renewalInterval := settings.CertSettings.GetCertRenewalInterval()
- // For certificates with short validity periods (less than renewal interval),
- // use early renewal logic to prevent expiration
- if totalValidityDays < renewalInterval {
- // Renew when 2/3 of the certificate's lifetime remains
- // This provides a safety buffer for short-lived certificates
- earlyRenewalThreshold := 2 * totalValidityDays / 3
- if daysUntilExpiration > earlyRenewalThreshold {
- return
- }
- // If we reach here, proceed with renewal for short-lived certificate
- } else {
- // For normal certificates with validity >= renewal interval:
- // Skip renewal if certificate age is less than the configured renewal interval
- // This ensures we don't renew certificates too frequently
- if certAge < renewalInterval {
- return
- }
- }
- // after 1 mo, reissue certificate
- // support SAN certification
- payload := &ConfigPayload{
- CertID: certModel.ID,
- ServerName: certModel.Domains,
- ChallengeMethod: certModel.ChallengeMethod,
- DNSCredentialID: certModel.DnsCredentialID,
- KeyType: certModel.GetKeyType(),
- NotBefore: certInfo.NotBefore,
- MustStaple: certModel.MustStaple,
- LegoDisableCNAMESupport: certModel.LegoDisableCNAMESupport,
- RevokeOld: certModel.RevokeOld,
- }
- if certModel.Resource != nil {
- payload.Resource = &model.CertificateResource{
- Resource: certModel.Resource.Resource,
- PrivateKey: certModel.Resource.PrivateKey,
- Certificate: certModel.Resource.Certificate,
- IssuerCertificate: certModel.Resource.IssuerCertificate,
- CSR: certModel.Resource.CSR,
- }
- }
- err = IssueCert(payload, log)
- if err != nil {
- log.Error(err)
- notification.Error("Renew Certificate Error", strings.Join(payload.ServerName, ", "), nil)
- return
- }
- notification.Success("Renew Certificate Success", strings.Join(payload.ServerName, ", "), nil)
- err = SyncToRemoteServer(certModel)
- if err != nil {
- notification.Error("Sync Certificate Error", err.Error(), nil)
- return
- }
- }
|