diff --git a/README.md b/README.md index ee2201ba8e..a3f7fb4de4 100644 --- a/README.md +++ b/README.md @@ -197,6 +197,7 @@ _this is the recommended way to run remark42_ | simple-view | SIMPLE_VIEW | `false` | minimized UI with basic info only | | proxy-cors | PROXY_CORS | `false` | disable internal CORS and delegate it to proxy | | allowed-hosts | ALLOWED_HOSTS | enable all | limit hosts/sources allowed to embed comments | +| address | REMARK_ADDRESS | all interfaces | web server listening address | | port | REMARK_PORT | `8080` | web server port | | web-root | REMARK_WEB_ROOT | `./web` | web server root directory | | update-limit | UPDATE_LIMIT | `0.5` | updates/sec limit | diff --git a/backend/app/cmd/server.go b/backend/app/cmd/server.go index 898ef3568c..161681e847 100644 --- a/backend/app/cmd/server.go +++ b/backend/app/cmd/server.go @@ -70,6 +70,7 @@ type ServerCommand struct { EditDuration time.Duration `long:"edit-time" env:"EDIT_TIME" default:"5m" description:"edit window"` AdminEdit bool `long:"admin-edit" env:"ADMIN_EDIT" description:"unlimited edit for admins"` Port int `long:"port" env:"REMARK_PORT" default:"8080" description:"port"` + Address string `long:"address" env:"REMARK_ADDRESS" default:"" description:"listening address"` WebRoot string `long:"web-root" env:"REMARK_WEB_ROOT" default:"./web" description:"web root directory"` UpdateLimit float64 `long:"update-limit" env:"UPDATE_LIMIT" default:"0.5" description:"updates/sec limit"` RestrictedWords []string `long:"restricted-words" env:"RESTRICTED_WORDS" description:"words prohibited to use in comments" env-delim:","` @@ -262,7 +263,7 @@ type serverApp struct { // Execute is the entry point for "server" command, called by flag parser func (s *ServerCommand) Execute(_ []string) error { - log.Printf("[INFO] start server on port %d", s.Port) + log.Printf("[INFO] start server on port %s:%d", s.Address, s.Port) resetEnv("SECRET", "AUTH_GOOGLE_CSEC", "AUTH_GITHUB_CSEC", "AUTH_FACEBOOK_CSEC", "AUTH_YANDEX_CSEC", "ADMIN_PASSWD") ctx, cancel := context.WithCancel(context.Background()) @@ -511,7 +512,7 @@ func (a *serverApp) run(ctx context.Context) error { go a.imageService.Cleanup(ctx) // pictures cleanup for staging images - a.restSrv.Run(a.Port) + a.restSrv.Run(a.Address, a.Port) // shutdown procedures after HTTP server is stopped if a.devAuth != nil { diff --git a/backend/app/rest/api/rest.go b/backend/app/rest/api/rest.go index 4de75d9466..bc3734fa8b 100644 --- a/backend/app/rest/api/rest.go +++ b/backend/app/rest/api/rest.go @@ -91,31 +91,36 @@ type commentsWithInfo struct { } // Run the lister and request's router, activate rest server -func (s *Rest) Run(port int) { +func (s *Rest) Run(address string, port int) { + + if address == "*" { + address = "" + } + switch s.SSLConfig.SSLMode { case None: - log.Printf("[INFO] activate http rest server on port %d", port) + log.Printf("[INFO] activate http rest server on %s:%d", address, port) s.lock.Lock() - s.httpServer = s.makeHTTPServer(port, s.routes()) + s.httpServer = s.makeHTTPServer(address, port, s.routes()) s.httpServer.ErrorLog = log.ToStdLogger(log.Default(), "WARN") s.lock.Unlock() err := s.httpServer.ListenAndServe() log.Printf("[WARN] http server terminated, %s", err) case Static: - log.Printf("[INFO] activate https server in 'static' mode on port %d", s.SSLConfig.Port) + log.Printf("[INFO] activate https server in 'static' mode on %s:%d", address, s.SSLConfig.Port) s.lock.Lock() - s.httpsServer = s.makeHTTPSServer(s.SSLConfig.Port, s.routes()) + s.httpsServer = s.makeHTTPSServer(address, s.SSLConfig.Port, s.routes()) s.httpsServer.ErrorLog = log.ToStdLogger(log.Default(), "WARN") - s.httpServer = s.makeHTTPServer(port, s.httpToHTTPSRouter()) + s.httpServer = s.makeHTTPServer(address, port, s.httpToHTTPSRouter()) s.httpServer.ErrorLog = log.ToStdLogger(log.Default(), "WARN") s.lock.Unlock() go func() { - log.Printf("[INFO] activate http redirect server on port %d", port) + log.Printf("[INFO] activate http redirect server on %s:%d", address, port) err := s.httpServer.ListenAndServe() log.Printf("[WARN] http redirect server terminated, %s", err) }() @@ -123,14 +128,14 @@ func (s *Rest) Run(port int) { err := s.httpsServer.ListenAndServeTLS(s.SSLConfig.Cert, s.SSLConfig.Key) log.Printf("[WARN] https server terminated, %s", err) case Auto: - log.Printf("[INFO] activate https server in 'auto' mode on port %d", s.SSLConfig.Port) + log.Printf("[INFO] activate https server in 'auto' mode on %s:%d", address, s.SSLConfig.Port) m := s.makeAutocertManager() s.lock.Lock() - s.httpsServer = s.makeHTTPSAutocertServer(s.SSLConfig.Port, s.routes(), m) + s.httpsServer = s.makeHTTPSAutocertServer(address, s.SSLConfig.Port, s.routes(), m) s.httpsServer.ErrorLog = log.ToStdLogger(log.Default(), "WARN") - s.httpServer = s.makeHTTPServer(port, s.httpChallengeRouter(m)) + s.httpServer = s.makeHTTPServer(address, port, s.httpChallengeRouter(m)) s.httpServer.ErrorLog = log.ToStdLogger(log.Default(), "WARN") s.lock.Unlock() @@ -170,9 +175,9 @@ func (s *Rest) Shutdown() { s.lock.Unlock() } -func (s *Rest) makeHTTPServer(port int, router http.Handler) *http.Server { +func (s *Rest) makeHTTPServer(address string, port int, router http.Handler) *http.Server { return &http.Server{ - Addr: fmt.Sprintf(":%d", port), + Addr: fmt.Sprintf("%s:%d", address, port), Handler: router, ReadHeaderTimeout: 5 * time.Second, // WriteTimeout: 120 * time.Second, // TODO: such a long timeout needed for blocking export (backup) request diff --git a/backend/app/rest/api/rest_test.go b/backend/app/rest/api/rest_test.go index f59158cf3e..5611f070b7 100644 --- a/backend/app/rest/api/rest_test.go +++ b/backend/app/rest/api/rest_test.go @@ -92,7 +92,7 @@ func TestRest_Shutdown(t *testing.T) { }() st := time.Now() - srv.Run(0) + srv.Run("127.0.0.1", 0) assert.True(t, time.Since(st).Seconds() < 1, "should take about 100ms") <-done } @@ -132,7 +132,7 @@ func TestRest_RunStaticSSLMode(t *testing.T) { port := chooseRandomUnusedPort() go func() { - srv.Run(port) + srv.Run("", port) }() waitForHTTPSServerStart(sslPort) @@ -181,7 +181,7 @@ func TestRest_RunAutocertModeHTTPOnly(t *testing.T) { port := chooseRandomUnusedPort() go func() { // can't check https server locally, just only http server - srv.Run(port) + srv.Run("", port) }() waitForHTTPSServerStart(sslPort) diff --git a/backend/app/rest/api/ssl.go b/backend/app/rest/api/ssl.go index adae64ace8..18dbd3f6c2 100644 --- a/backend/app/rest/api/ssl.go +++ b/backend/app/rest/api/ssl.go @@ -84,8 +84,8 @@ func (s *Rest) makeAutocertManager() *autocert.Manager { } // makeHTTPSAutoCertServer makes https server with autocert mode (LE support) -func (s *Rest) makeHTTPSAutocertServer(port int, router http.Handler, m *autocert.Manager) *http.Server { - server := s.makeHTTPServer(port, router) +func (s *Rest) makeHTTPSAutocertServer(address string, port int, router http.Handler, m *autocert.Manager) *http.Server { + server := s.makeHTTPServer(address, port, router) cfg := s.makeTLSConfig() cfg.GetCertificate = m.GetCertificate server.TLSConfig = cfg @@ -93,8 +93,8 @@ func (s *Rest) makeHTTPSAutocertServer(port int, router http.Handler, m *autocer } // makeHTTPSServer makes https server for static mode -func (s *Rest) makeHTTPSServer(port int, router http.Handler) *http.Server { - server := s.makeHTTPServer(port, router) +func (s *Rest) makeHTTPSServer(address string, port int, router http.Handler) *http.Server { + server := s.makeHTTPServer(address, port, router) server.TLSConfig = s.makeTLSConfig() return server }