github.com/bosssauce/ponzu@v0.11.1-0.20200102001432-9bc41b703131/system/tls/enable.go (about) 1 // Package tls provides the functionality to Ponzu systems to encrypt HTTP traffic 2 // through the ability to generate self-signed certificates for local development 3 // and fetch/update production certificates from Let's Encrypt. 4 package tls 5 6 import ( 7 "crypto/tls" 8 "fmt" 9 "log" 10 "net/http" 11 "os" 12 "path/filepath" 13 "time" 14 15 "github.com/ponzu-cms/ponzu/system/db" 16 "github.com/ponzu-cms/ponzu/system/cfg" 17 "golang.org/x/crypto/acme/autocert" 18 ) 19 20 // newManager attempts to locate or create the cert cache directory and the 21 // certs for TLS encryption and returns an autocert.Manager 22 func newManager() autocert.Manager { 23 24 cache := autocert.DirCache(filepath.Join(cfg.TlsDir(), "certs")) 25 if _, err := os.Stat(string(cache)); os.IsNotExist(err) { 26 err := os.MkdirAll(string(cache), os.ModePerm|os.ModeDir) 27 if err != nil { 28 log.Fatalln("Couldn't create cert directory at", cache) 29 } 30 } 31 32 // get host/domain and email from Config to use for TLS request to Let's encryption. 33 // we will fail fatally if either are not found since Let's Encrypt will rate-limit 34 // and sending incomplete requests is wasteful and guaranteed to fail its check 35 host, err := db.Config("domain") 36 if err != nil { 37 log.Fatalln("Error identifying host/domain during TLS set-up.", err) 38 } 39 40 if host == nil { 41 log.Fatalln("No 'domain' field set in Configuration. Please add a domain before attempting to make certificates.") 42 } 43 fmt.Println("Using", string(host), "as host/domain for certificate...") 44 fmt.Println("NOTE: if the host/domain is not configured properly or is unreachable, HTTPS set-up will fail.") 45 46 email, err := db.Config("admin_email") 47 if err != nil { 48 log.Fatalln("Error identifying admin email during TLS set-up.", err) 49 } 50 51 if email == nil { 52 log.Fatalln("No 'admin_email' field set in Configuration. Please add an admin email before attempting to make certificates.") 53 } 54 fmt.Println("Using", string(email), "as contact email for certificate...") 55 56 return autocert.Manager{ 57 Prompt: autocert.AcceptTOS, 58 Cache: cache, 59 HostPolicy: autocert.HostWhitelist(string(host)), 60 RenewBefore: time.Hour * 24 * 30, 61 Email: string(email), 62 } 63 } 64 65 // Enable runs the setup for creating or locating production certificates and 66 // starts the TLS server 67 func Enable() { 68 m := newManager() 69 70 server := &http.Server{ 71 Addr: fmt.Sprintf(":%s", db.ConfigCache("https_port").(string)), 72 TLSConfig: &tls.Config{GetCertificate: m.GetCertificate}, 73 } 74 75 // launch http listener for "http-01" ACME challenge 76 go http.ListenAndServe(":http", m.HTTPHandler(nil)) 77 78 log.Fatalln(server.ListenAndServeTLS("", "")) 79 }