Merge pull request #142 from writeas/autocert
Automatic certificates from Let's Encrypt Resolves T542
This commit is contained in:
commit
3321c750ac
3 changed files with 79 additions and 31 deletions
58
app.go
58
app.go
|
@ -11,6 +11,7 @@
|
||||||
package writefreely
|
package writefreely
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
|
@ -39,6 +40,7 @@ import (
|
||||||
"github.com/writeas/writefreely/key"
|
"github.com/writeas/writefreely/key"
|
||||||
"github.com/writeas/writefreely/migrations"
|
"github.com/writeas/writefreely/migrations"
|
||||||
"github.com/writeas/writefreely/page"
|
"github.com/writeas/writefreely/page"
|
||||||
|
"golang.org/x/crypto/acme/autocert"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -380,19 +382,55 @@ func Serve(app *App, r *mux.Router) {
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
if app.cfg.IsSecureStandalone() {
|
if app.cfg.IsSecureStandalone() {
|
||||||
log.Info("Serving redirects on http://%s:80", bindAddress)
|
if app.cfg.Server.Autocert {
|
||||||
go func() {
|
m := &autocert.Manager{
|
||||||
err = http.ListenAndServe(
|
Prompt: autocert.AcceptTOS,
|
||||||
fmt.Sprintf("%s:80", bindAddress), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
Cache: autocert.DirCache(app.cfg.Server.TLSCertPath),
|
||||||
|
}
|
||||||
|
host, err := url.Parse(app.cfg.App.Host)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("[WARNING] Unable to parse configured host! %s", err)
|
||||||
|
log.Error(`[WARNING] ALL hosts are allowed, which can open you to an attack where
|
||||||
|
clients connect to a server by IP address and pretend to be asking for an
|
||||||
|
incorrect host name, and cause you to reach the CA's rate limit for certificate
|
||||||
|
requests. We recommend supplying a valid host name.`)
|
||||||
|
log.Info("Using autocert on ANY host")
|
||||||
|
} else {
|
||||||
|
log.Info("Using autocert on host %s", host.Host)
|
||||||
|
m.HostPolicy = autocert.HostWhitelist(host.Host)
|
||||||
|
}
|
||||||
|
s := &http.Server{
|
||||||
|
Addr: ":https",
|
||||||
|
Handler: r,
|
||||||
|
TLSConfig: &tls.Config{
|
||||||
|
GetCertificate: m.GetCertificate,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
s.SetKeepAlivesEnabled(false)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
log.Info("Serving redirects on http://%s:80", bindAddress)
|
||||||
|
err = http.ListenAndServe(":80", m.HTTPHandler(nil))
|
||||||
|
log.Error("Unable to start redirect server: %v", err)
|
||||||
|
}()
|
||||||
|
|
||||||
|
log.Info("Serving on https://%s:443", bindAddress)
|
||||||
|
log.Info("---")
|
||||||
|
err = s.ListenAndServeTLS("", "")
|
||||||
|
} else {
|
||||||
|
go func() {
|
||||||
|
log.Info("Serving redirects on http://%s:80", bindAddress)
|
||||||
|
err = http.ListenAndServe(fmt.Sprintf("%s:80", bindAddress), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Redirect(w, r, app.cfg.App.Host, http.StatusMovedPermanently)
|
http.Redirect(w, r, app.cfg.App.Host, http.StatusMovedPermanently)
|
||||||
}))
|
}))
|
||||||
log.Error("Unable to start redirect server: %v", err)
|
log.Error("Unable to start redirect server: %v", err)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
log.Info("Serving on https://%s:443", bindAddress)
|
log.Info("Serving on https://%s:443", bindAddress)
|
||||||
log.Info("---")
|
log.Info("Using manual certificates")
|
||||||
err = http.ListenAndServeTLS(
|
log.Info("---")
|
||||||
fmt.Sprintf("%s:443", bindAddress), app.cfg.Server.TLSCertPath, app.cfg.Server.TLSKeyPath, r)
|
err = http.ListenAndServeTLS(fmt.Sprintf("%s:443", bindAddress), app.cfg.Server.TLSCertPath, app.cfg.Server.TLSKeyPath, r)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Info("Serving on http://%s:%d\n", bindAddress, app.cfg.Server.Port)
|
log.Info("Serving on http://%s:%d\n", bindAddress, app.cfg.Server.Port)
|
||||||
log.Info("---")
|
log.Info("---")
|
||||||
|
|
|
@ -35,6 +35,7 @@ type (
|
||||||
|
|
||||||
TLSCertPath string `ini:"tls_cert_path"`
|
TLSCertPath string `ini:"tls_cert_path"`
|
||||||
TLSKeyPath string `ini:"tls_key_path"`
|
TLSKeyPath string `ini:"tls_key_path"`
|
||||||
|
Autocert bool `ini:"autocert"`
|
||||||
|
|
||||||
TemplatesParentDir string `ini:"templates_parent_dir"`
|
TemplatesParentDir string `ini:"templates_parent_dir"`
|
||||||
StaticParentDir string `ini:"static_parent_dir"`
|
StaticParentDir string `ini:"static_parent_dir"`
|
||||||
|
|
|
@ -101,39 +101,48 @@ func Configure(fname string, configSections string) (*SetupData, error) {
|
||||||
selPrompt = promptui.Select{
|
selPrompt = promptui.Select{
|
||||||
Templates: selTmpls,
|
Templates: selTmpls,
|
||||||
Label: "Web server mode",
|
Label: "Web server mode",
|
||||||
Items: []string{"Insecure (port 80)", "Secure (port 443)"},
|
Items: []string{"Insecure (port 80)", "Secure (port 443), manual certificate", "Secure (port 443), auto certificate"},
|
||||||
}
|
}
|
||||||
sel, _, err := selPrompt.Run()
|
sel, _, err := selPrompt.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return data, err
|
return data, err
|
||||||
}
|
}
|
||||||
if sel == 0 {
|
if sel == 0 {
|
||||||
|
data.Config.Server.Autocert = false
|
||||||
data.Config.Server.Port = 80
|
data.Config.Server.Port = 80
|
||||||
data.Config.Server.TLSCertPath = ""
|
data.Config.Server.TLSCertPath = ""
|
||||||
data.Config.Server.TLSKeyPath = ""
|
data.Config.Server.TLSKeyPath = ""
|
||||||
} else if sel == 1 {
|
} else if sel == 1 || sel == 2 {
|
||||||
data.Config.Server.Port = 443
|
data.Config.Server.Port = 443
|
||||||
|
data.Config.Server.Autocert = sel == 2
|
||||||
|
|
||||||
prompt = promptui.Prompt{
|
if sel == 1 {
|
||||||
Templates: tmpls,
|
// Manual certificate configuration
|
||||||
Label: "Certificate path",
|
prompt = promptui.Prompt{
|
||||||
Validate: validateNonEmpty,
|
Templates: tmpls,
|
||||||
Default: data.Config.Server.TLSCertPath,
|
Label: "Certificate path",
|
||||||
}
|
Validate: validateNonEmpty,
|
||||||
data.Config.Server.TLSCertPath, err = prompt.Run()
|
Default: data.Config.Server.TLSCertPath,
|
||||||
if err != nil {
|
}
|
||||||
return data, err
|
data.Config.Server.TLSCertPath, err = prompt.Run()
|
||||||
}
|
if err != nil {
|
||||||
|
return data, err
|
||||||
|
}
|
||||||
|
|
||||||
prompt = promptui.Prompt{
|
prompt = promptui.Prompt{
|
||||||
Templates: tmpls,
|
Templates: tmpls,
|
||||||
Label: "Key path",
|
Label: "Key path",
|
||||||
Validate: validateNonEmpty,
|
Validate: validateNonEmpty,
|
||||||
Default: data.Config.Server.TLSKeyPath,
|
Default: data.Config.Server.TLSKeyPath,
|
||||||
}
|
}
|
||||||
data.Config.Server.TLSKeyPath, err = prompt.Run()
|
data.Config.Server.TLSKeyPath, err = prompt.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return data, err
|
return data, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Automatic certificate
|
||||||
|
data.Config.Server.TLSCertPath = "certs"
|
||||||
|
data.Config.Server.TLSKeyPath = "certs"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Add table
Reference in a new issue