github.com/rpdict/ponzu@v0.10.1-0.20190226054626-477f29d6bf5e/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/rpdict/ponzu/system/db" 16 "golang.org/x/crypto/acme/autocert" 17 ) 18 19 // newManager attempts to locate or create the cert cache directory and the 20 // certs for TLS encryption and returns an autocert.Manager 21 func newManager() autocert.Manager { 22 pwd, err := os.Getwd() 23 if err != nil { 24 log.Fatalln("Couldn't find working directory to locate or save certificates.") 25 } 26 27 cache := autocert.DirCache(filepath.Join(pwd, "system", "tls", "certs")) 28 if _, err := os.Stat(string(cache)); os.IsNotExist(err) { 29 err := os.MkdirAll(string(cache), os.ModePerm|os.ModeDir) 30 if err != nil { 31 log.Fatalln("Couldn't create cert directory at", cache) 32 } 33 } 34 35 // get host/domain and email from Config to use for TLS request to Let's encryption. 36 // we will fail fatally if either are not found since Let's Encrypt will rate-limit 37 // and sending incomplete requests is wasteful and guaranteed to fail its check 38 host, err := db.Config("domain") 39 if err != nil { 40 log.Fatalln("Error identifying host/domain during TLS set-up.", err) 41 } 42 43 if host == nil { 44 log.Fatalln("No 'domain' field set in Configuration. Please add a domain before attempting to make certificates.") 45 } 46 fmt.Println("Using", string(host), "as host/domain for certificate...") 47 fmt.Println("NOTE: if the host/domain is not configured properly or is unreachable, HTTPS set-up will fail.") 48 49 email, err := db.Config("admin_email") 50 if err != nil { 51 log.Fatalln("Error identifying admin email during TLS set-up.", err) 52 } 53 54 if email == nil { 55 log.Fatalln("No 'admin_email' field set in Configuration. Please add an admin email before attempting to make certificates.") 56 } 57 fmt.Println("Using", string(email), "as contact email for certificate...") 58 59 return autocert.Manager{ 60 Prompt: autocert.AcceptTOS, 61 Cache: cache, 62 HostPolicy: autocert.HostWhitelist(string(host)), 63 RenewBefore: time.Hour * 24 * 30, 64 Email: string(email), 65 } 66 } 67 68 // Enable runs the setup for creating or locating production certificates and 69 // starts the TLS server 70 func Enable() { 71 m := newManager() 72 73 server := &http.Server{ 74 Addr: fmt.Sprintf(":%s", db.ConfigCache("https_port").(string)), 75 TLSConfig: &tls.Config{GetCertificate: m.GetCertificate}, 76 } 77 78 // launch http listener for "http-01" ACME challenge 79 go http.ListenAndServe(":http", m.HTTPHandler(nil)) 80 81 log.Fatalln(server.ListenAndServeTLS("", "")) 82 }