diff --git a/cmd/server/main.go b/cmd/server/main.go index 3cbd1f3da..11677cf73 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -32,6 +32,10 @@ func main() { Usage: "High performance WebRTC server", Description: "run without subcommands to start the server", Flags: []cli.Flag{ + &cli.StringSliceFlag{ + Name: "bind", + Usage: "IP address to listen on, use flag multiple times to specify multiple addresses", + }, &cli.StringFlag{ Name: "config", Usage: "path to LiveKit config file", @@ -92,7 +96,7 @@ func main() { }, &cli.BoolFlag{ Name: "dev", - Usage: "sets log-level to debug, console formatter, and /debug/pprof. insecure for production.", + Usage: "sets log-level to debug, console formatter, and /debug/pprof. insecure for production", }, }, Action: startServer, @@ -108,7 +112,9 @@ func main() { Action: printPorts, }, { + // this subcommand is deprecated, token generation is provided by CLI Name: "create-join-token", + Hidden: true, Usage: "create a room join token for development use", Action: createToken, Flags: []cli.Flag{ @@ -155,9 +161,8 @@ func getConfig(c *cli.Context) (*config.Config, error) { } serverlogger.InitFromConfig(conf.Logging) - if c.String("config") == "" && c.String("config-body") == "" { - // without config, use single port UDP - conf.Development = true + if c.String("config") == "" && c.String("config-body") == "" && conf.Development { + // use single port UDP when no config is provided conf.RTC.UDPPort = 7882 conf.RTC.ICEPortRangeStart = 0 conf.RTC.ICEPortRangeEnd = 0 @@ -171,6 +176,13 @@ func getConfig(c *cli.Context) (*config.Config, error) { conf.Keys = map[string]string{ "devkey": "secret", } + // when dev mode and using shared keys, we'll bind to localhost by default + if conf.BindAddresses == nil { + conf.BindAddresses = []string{ + "127.0.0.1", + "[::1]", + } + } } } return conf, nil diff --git a/go.mod b/go.mod index f82b6bff0..815298552 100644 --- a/go.mod +++ b/go.mod @@ -42,6 +42,7 @@ require ( github.com/urfave/negroni v1.0.0 go.uber.org/atomic v1.9.0 go.uber.org/zap v1.21.0 + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c google.golang.org/protobuf v1.27.1 gopkg.in/yaml.v3 v3.0.0 ) diff --git a/go.sum b/go.sum index 0307111be..93f70a80b 100644 --- a/go.sum +++ b/go.sum @@ -347,6 +347,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/pkg/config/config.go b/pkg/config/config.go index a2ee126db..043a57b0d 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -30,6 +30,7 @@ const ( type Config struct { Port uint32 `yaml:"port"` + BindAddresses []string `yaml:"bind_addresses"` PrometheusPort uint32 `yaml:"prometheus_port,omitempty"` RTC RTCConfig `yaml:"rtc,omitempty"` Redis RedisConfig `yaml:"redis,omitempty"` @@ -347,7 +348,9 @@ func (conf *Config) updateFromCLI(c *cli.Context) error { if c.IsSet("udp-port") { conf.RTC.UDPPort = uint32(c.Int("udp-port")) } - + if c.IsSet("bind") { + conf.BindAddresses = c.StringSlice("bind") + } return nil } diff --git a/pkg/service/server.go b/pkg/service/server.go index 7f56999fb..28e9bff3d 100644 --- a/pkg/service/server.go +++ b/pkg/service/server.go @@ -16,6 +16,7 @@ import ( "github.com/rs/cors" "github.com/urfave/negroni" "go.uber.org/atomic" + "golang.org/x/sync/errgroup" "github.com/livekit/livekit-server/pkg/config" "github.com/livekit/livekit-server/pkg/routing" @@ -94,13 +95,11 @@ func NewLivekitServer(conf *config.Config, mux.HandleFunc("/", s.healthCheck) s.httpServer = &http.Server{ - Addr: fmt.Sprintf(":%d", conf.Port), Handler: configureMiddlewares(mux, middlewares...), } if conf.PrometheusPort > 0 { s.promServer = &http.Server{ - Addr: fmt.Sprintf(":%d", conf.PrometheusPort), Handler: promhttp.Handler(), } } @@ -149,47 +148,69 @@ func (s *LivekitServer) Start() error { s.egressService.Start() - // ensure we could listen - ln, err := net.Listen("tcp", s.httpServer.Addr) - if err != nil { - return err + addresses := s.config.BindAddresses + if addresses == nil { + addresses = []string{""} } - if s.promServer != nil { - promLn, err := net.Listen("tcp", s.promServer.Addr) + // ensure we could listen + listeners := make([]net.Listener, 0) + promListeners := make([]net.Listener, 0) + for _, addr := range addresses { + ln, err := net.Listen("tcp", fmt.Sprintf("%s:%d", addr, s.config.Port)) if err != nil { return err } - go func() { - _ = s.promServer.Serve(promLn) - }() + listeners = append(listeners, ln) + + if s.promServer != nil { + ln, err = net.Listen("tcp", fmt.Sprintf("%s:%d", addr, s.config.PrometheusPort)) + if err != nil { + return err + } + promListeners = append(promListeners, ln) + } } + values := []interface{}{ + "portHttp", s.config.Port, + "nodeID", s.currentNode.Id, + "nodeIP", s.currentNode.Ip, + "version", version.Version, + } + if s.config.BindAddresses != nil { + values = append(values, "bindAddresses", s.config.BindAddresses) + } + if s.config.RTC.TCPPort != 0 { + values = append(values, "rtc.portTCP", s.config.RTC.TCPPort) + } + if !s.config.RTC.ForceTCP && s.config.RTC.UDPPort != 0 { + values = append(values, "rtc.portUDP", s.config.RTC.UDPPort) + } else { + values = append(values, + "rtc.portICERange", []uint32{s.config.RTC.ICEPortRangeStart, s.config.RTC.ICEPortRangeEnd}, + ) + } + if s.config.PrometheusPort != 0 { + values = append(values, "portPrometheus", s.config.PrometheusPort) + } + if s.config.Region != "" { + values = append(values, "region", s.config.Region) + } + logger.Infow("starting LiveKit server", values...) + + for _, promLn := range promListeners { + go s.promServer.Serve(promLn) + } + + httpGroup := &errgroup.Group{} + for _, ln := range listeners { + httpGroup.Go(func() error { + return s.httpServer.Serve(ln) + }) + } go func() { - values := []interface{}{ - "addr", s.httpServer.Addr, - "nodeID", s.currentNode.Id, - "nodeIP", s.currentNode.Ip, - "version", version.Version, - } - if s.config.RTC.TCPPort != 0 { - values = append(values, "rtc.portTCP", s.config.RTC.TCPPort) - } - if !s.config.RTC.ForceTCP && s.config.RTC.UDPPort != 0 { - values = append(values, "rtc.portUDP", s.config.RTC.UDPPort) - } else { - values = append(values, - "rtc.portICERange", []uint32{s.config.RTC.ICEPortRangeStart, s.config.RTC.ICEPortRangeEnd}, - ) - } - if s.config.PrometheusPort != 0 { - values = append(values, "portPrometheus", s.config.PrometheusPort) - } - if s.config.Region != "" { - values = append(values, "region", s.config.Region) - } - logger.Infow("starting LiveKit server", values...) - if err := s.httpServer.Serve(ln); err != http.ErrServerClosed { + if err := httpGroup.Wait(); err != http.ErrServerClosed { logger.Errorw("could not start server", err) s.Stop(true) }