diff --git a/cmd/root.go b/cmd/root.go index f852869..8077adf 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -6,6 +6,7 @@ import ( "github.com/NYTimes/logrotate" "github.com/apex/log/handlers/multi" "github.com/gammazero/workerpool" + "golang.org/x/crypto/acme" "net/http" "os" "path" @@ -132,14 +133,15 @@ func rootCmdRun(*cobra.Command, []string) { config.SetDebugViaFlag(debug) if err := c.System.ConfigureDirectories(); err != nil { - log.Fatal("failed to configure system directories for pterodactyl") - panic(err) + log.WithError(err).Fatal("failed to configure system directories for pterodactyl") + os.Exit(1) + return } log.WithField("username", c.System.Username).Info("checking for pterodactyl system user") if su, err := c.EnsurePterodactylUser(); err != nil { - log.Error("failed to create pterodactyl system user") - panic(err) + log.WithError(err).Error("failed to create pterodactyl system user") + os.Exit(1) return } else { log.WithFields(log.Fields{ @@ -217,15 +219,19 @@ func rootCmdRun(*cobra.Command, []string) { // Addresses potentially invalid data in the stored file that can cause Wings to lose // track of what the actual server state is. - s.SetState(server.ProcessOfflineState) + _ = s.SetState(server.ProcessOfflineState) }) } - // Wait until all of the servers are ready to go before we fire up the HTTP server. + // Wait until all of the servers are ready to go before we fire up the SFTP and HTTP servers. pool.StopWait() - // Initalize SFTP. - sftp.Initialize(c) + // Initialize the SFTP server. + if err := sftp.Initialize(c); err != nil { + log.WithError(err).Error("failed to initialize the sftp server") + os.Exit(1) + return + } // Ensure the archive directory exists. if err := os.MkdirAll(c.System.ArchiveDirectory, 0755); err != nil { @@ -244,9 +250,46 @@ func rootCmdRun(*cobra.Command, []string) { "host_port": c.Api.Port, }).Info("configuring internal webserver") + // Configure the router. r := router.Configure() - addr := fmt.Sprintf("%s:%d", c.Api.Host, c.Api.Port) + s := &http.Server{ + Addr: fmt.Sprintf("%s:%d", c.Api.Host, c.Api.Port), + Handler: r, + + TLSConfig: &tls.Config{ + NextProtos: []string{ + "h2", // enable HTTP/2 + "http/1.1", + }, + + // https://blog.cloudflare.com/exposing-go-on-the-internet + CipherSuites: []uint16{ + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + }, + + PreferServerCipherSuites: true, + + MinVersion: tls.VersionTLS12, + MaxVersion: tls.VersionTLS13, + + CurvePreferences: []tls.CurveID{ + tls.X25519, + tls.CurveP256, + }, + // END https://blog.cloudflare.com/exposing-go-on-the-internet + }, + } + + // Check if the server should run with TLS but using autocert. if useAutomaticTls && len(tlsHostname) > 0 { m := autocert.Manager{ Prompt: autocert.AcceptTOS, @@ -255,28 +298,43 @@ func rootCmdRun(*cobra.Command, []string) { } log.WithField("hostname", tlsHostname). - Info("webserver is now listening with auto-TLS enabled; certifcates will be automatically generated by Let's Encrypt") + Info("webserver is now listening with auto-TLS enabled; certificates will be automatically generated by Let's Encrypt") - // We don't use the autotls runner here since we need to specify a port other than 443 - // to be using for SSL connections for Wings. - s := &http.Server{Addr: addr, TLSConfig: m.TLSConfig(), Handler: r} + // Hook autocert into the main http server. + s.TLSConfig.GetCertificate = m.GetCertificate + s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, acme.ALPNProto) // enable tls-alpn ACME challenges - go http.ListenAndServe(":http", m.HTTPHandler(nil)) + // Start the autocert server. + go func() { + if err := http.ListenAndServe(":http", m.HTTPHandler(nil)); err != nil { + log.WithError(err).Error("failed to serve autocert http server") + } + }() + + // Start the main http server with TLS using autocert. if err := s.ListenAndServeTLS("", ""); err != nil { log.WithFields(log.Fields{"auto_tls": true, "tls_hostname": tlsHostname, "error": err}). Fatal("failed to configure HTTP server using auto-tls") os.Exit(1) } - } else if c.Api.Ssl.Enabled { - if err := r.RunTLS(addr, c.Api.Ssl.CertificateFile, c.Api.Ssl.KeyFile); err != nil { + + return + } + + // Check if main http server should run with TLS. + if c.Api.Ssl.Enabled { + if err := s.ListenAndServeTLS(c.Api.Ssl.CertificateFile, c.Api.Ssl.KeyFile); err != nil { log.WithFields(log.Fields{"auto_tls": false, "error": err}).Fatal("failed to configure HTTPS server") os.Exit(1) } - } else { - if err := r.Run(addr); err != nil { - log.WithField("error", err).Fatal("failed to configure HTTP server") - os.Exit(1) - } + return + } + + // Run the main http server without TLS. + s.TLSConfig = nil + if err := s.ListenAndServe(); err != nil { + log.WithField("error", err).Fatal("failed to configure HTTP server") + os.Exit(1) } }