diff --git a/app.go b/app.go index e061de4..d72ee49 100644 --- a/app.go +++ b/app.go @@ -401,11 +401,26 @@ func Serve() { os.Exit(0) }() - // Start web application server http.Handle("/", r) - log.Info("Serving on http://localhost:%d\n", app.cfg.Server.Port) - log.Info("---") - err = http.ListenAndServe(fmt.Sprintf(":%d", app.cfg.Server.Port), nil) + + // Start web application server + if app.cfg.IsSecureStandalone() { + log.Info("Serving redirects on http://localhost:80") + go func() { + err = http.ListenAndServe(":80", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + http.Redirect(w, r, app.cfg.App.Host, http.StatusMovedPermanently) + })) + log.Error("Unable to start redirect server: %v", err) + }() + + log.Info("Serving on https://localhost:443") + log.Info("---") + err = http.ListenAndServeTLS(":443", app.cfg.Server.TLSCertPath, app.cfg.Server.TLSKeyPath, nil) + } else { + log.Info("Serving on http://localhost:%d\n", app.cfg.Server.Port) + log.Info("---") + err = http.ListenAndServe(fmt.Sprintf(":%d", app.cfg.Server.Port), nil) + } if err != nil { log.Error("Unable to start: %v", err) os.Exit(1) diff --git a/config/config.go b/config/config.go index c3c0628..56d8848 100644 --- a/config/config.go +++ b/config/config.go @@ -13,6 +13,9 @@ type ( HiddenHost string `ini:"hidden_host"` Port int `ini:"port"` + TLSCertPath string `ini:"tls_cert_path"` + TLSKeyPath string `ini:"tls_key_path"` + Dev bool `ini:"-"` } @@ -76,6 +79,10 @@ func New() *Config { } } +func (cfg *Config) IsSecureStandalone() bool { + return cfg.Server.Port == 443 && cfg.Server.TLSCertPath != "" && cfg.Server.TLSKeyPath != "" +} + func Load() (*Config, error) { cfg, err := ini.Load(FileName) if err != nil { diff --git a/config/setup.go b/config/setup.go index 54fa961..6a2f780 100644 --- a/config/setup.go +++ b/config/setup.go @@ -47,17 +47,80 @@ func Configure() (*SetupData, error) { Selected: fmt.Sprintf(`{{.Label}} {{ . | faint }}`), } - prompt := promptui.Prompt{ - Templates: tmpls, - Label: "Local port", - Validate: validatePort, - Default: fmt.Sprintf("%d", data.Config.Server.Port), + // Environment selection + selPrompt := promptui.Select{ + Templates: selTmpls, + Label: "Environment", + Items: []string{"Development", "Production, standalone", "Production, behind reverse proxy"}, } - port, err := prompt.Run() + _, envType, err := selPrompt.Run() if err != nil { return data, err } - data.Config.Server.Port, _ = strconv.Atoi(port) // Ignore error, as we've already validated number + isDevEnv := envType == "Development" + isStandalone := envType == "Production, standalone" + + data.Config.Server.Dev = isDevEnv + + var prompt promptui.Prompt + if isDevEnv || !isStandalone { + // Running in dev environment or behind reverse proxy; ask for port + prompt = promptui.Prompt{ + Templates: tmpls, + Label: "Local port", + Validate: validatePort, + Default: fmt.Sprintf("%d", data.Config.Server.Port), + } + port, err := prompt.Run() + if err != nil { + return data, err + } + data.Config.Server.Port, _ = strconv.Atoi(port) // Ignore error, as we've already validated number + } + + if isStandalone { + selPrompt = promptui.Select{ + Templates: selTmpls, + Label: "Web server mode", + Items: []string{"Insecure (port 80)", "Secure (port 443)"}, + } + sel, _, err := selPrompt.Run() + if err != nil { + return data, err + } + if sel == 0 { + data.Config.Server.Port = 80 + data.Config.Server.TLSCertPath = "" + data.Config.Server.TLSKeyPath = "" + } else if sel == 1 { + data.Config.Server.Port = 443 + + prompt = promptui.Prompt{ + Templates: tmpls, + Label: "Certificate path", + Validate: validateNonEmpty, + Default: data.Config.Server.TLSCertPath, + } + data.Config.Server.TLSCertPath, err = prompt.Run() + if err != nil { + return data, err + } + + prompt = promptui.Prompt{ + Templates: tmpls, + Label: "Key path", + Validate: validateNonEmpty, + Default: data.Config.Server.TLSKeyPath, + } + data.Config.Server.TLSKeyPath, err = prompt.Run() + if err != nil { + return data, err + } + } + } else { + data.Config.Server.TLSCertPath = "" + data.Config.Server.TLSKeyPath = "" + } fmt.Println() title(" Database setup ") @@ -124,7 +187,7 @@ func Configure() (*SetupData, error) { title(" App setup ") fmt.Println() - selPrompt := promptui.Select{ + selPrompt = promptui.Select{ Templates: selTmpls, Label: "Site type", Items: []string{"Single user blog", "Multi-user instance"},