0
Fork 0
mirror of https://github.com/caddyserver/caddy.git synced 2024-12-30 22:34:15 -05:00
caddy/config/letsencrypt/renew.go
2015-10-20 20:16:01 -06:00

94 lines
2.6 KiB
Go

package letsencrypt
import (
"encoding/json"
"io/ioutil"
"log"
"time"
"github.com/mholt/caddy/server"
"github.com/xenolf/lego/acme"
)
// keepCertificatesRenewed is a permanently-blocking function
// that loops indefinitely and, on a regular schedule, checks
// certificates for expiration and initiates a renewal of certs
// that are expiring soon.
func keepCertificatesRenewed(configs []server.Config) {
ticker := time.Tick(renewInterval)
for range ticker {
if err := processCertificateRenewal(configs); err != nil {
log.Printf("[ERROR] cert renewal: %v", err)
}
}
}
// checkCertificateRenewal loops through all configured
// sites and looks for certificates to renew. Nothing is mutated
// through this function. The changes happen directly on disk.
func processCertificateRenewal(configs []server.Config) error {
log.Print("[INFO] Processing certificate renewals...")
for _, cfg := range configs {
// Check if this entry is TLS enabled and managed by LE
if !cfg.TLS.Enabled || !existingCertAndKey(cfg.Host) {
continue
}
// Read the certificate and get the NotAfter time.
certBytes, err := ioutil.ReadFile(storage.SiteCertFile(cfg.Host))
if err != nil {
return err
}
expTime, err := acme.GetPEMCertExpiration(certBytes)
if err != nil {
return err
}
// The time returned from the certificate is always in UTC.
// So calculate the time left with local time as UTC.
// Directly convert it to days for the following checks.
daysLeft := int(expTime.Sub(time.Now().UTC()).Hours() / 24)
// Renew on two or less days remaining.
if daysLeft <= 2 {
log.Printf("[WARN] There are %d days left on the certificate of %s. Trying to renew now.", daysLeft, cfg.Host)
client, err := newClient(getEmail(cfg))
if err != nil {
return err
}
// Read metadata
metaBytes, err := ioutil.ReadFile(storage.SiteMetaFile(cfg.Host))
if err != nil {
return err
}
privBytes, err := ioutil.ReadFile(storage.SiteKeyFile(cfg.Host))
if err != nil {
return err
}
var certMeta acme.CertificateResource
err = json.Unmarshal(metaBytes, &certMeta)
certMeta.Certificate = certBytes
certMeta.PrivateKey = privBytes
// Renew certificate.
// TODO: revokeOld should be an option in the caddyfile
newCertMeta, err := client.RenewCertificate(certMeta, true)
if err != nil {
return err
}
saveCertsAndKeys([]acme.CertificateResource{newCertMeta})
}
// Warn on 14 days remaining
if daysLeft <= 14 {
log.Printf("[WARN] There are %d days left on the certificate of %s. Will renew on two days left.\n", daysLeft, cfg.Host)
}
}
return nil
}