diff --git a/cmd/web.go b/cmd/web.go index f7ab661d4..9358dc140 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -8,6 +8,7 @@ import ( "crypto/tls" "fmt" "io/ioutil" + "net" "net/http" "net/http/fcgi" "os" @@ -582,6 +583,9 @@ func runWeb(ctx *cli.Context) error { var err error listenAddr := fmt.Sprintf("%s:%s", setting.HttpAddr, setting.HttpPort) + if setting.Protocol == setting.UNIX_SOCKET { + listenAddr = fmt.Sprintf("%s", setting.HttpAddr) + } log.Info("Listen: %v://%s%s", setting.Protocol, listenAddr, setting.AppSubUrl) switch setting.Protocol { case setting.HTTP: @@ -591,6 +595,20 @@ func runWeb(ctx *cli.Context) error { err = server.ListenAndServeTLS(setting.CertFile, setting.KeyFile) case setting.FCGI: err = fcgi.Serve(nil, m) + case setting.UNIX_SOCKET: + os.Remove(listenAddr) + listener, err := net.ListenUnix("unix", &net.UnixAddr{listenAddr, "unix"}) + if err != nil { + break + } + // FIXME add proper implementation of signal capture on all protocols + // execute this on SIGTERM or SIGINT: listener.Close() + err = os.Chmod(listenAddr, os.FileMode(setting.UnixSocketPermission)) + if err != nil { + log.Fatal(4, "Failed to set permission of unix socket: %v", err) + } + err = http.Serve(listener, m) + default: log.Fatal(4, "Invalid protocol: %s", setting.Protocol) } diff --git a/conf/app.ini b/conf/app.ini index 5b46365cb..ea0ca1629 100644 --- a/conf/app.ini +++ b/conf/app.ini @@ -61,6 +61,8 @@ DOMAIN = localhost ROOT_URL = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/ HTTP_ADDR = 0.0.0.0 HTTP_PORT = 3000 +; Permission for unix socket +UNIX_SOCKET_PERMISSION = 666 ; Local (DMZ) URL for Gogs workers (such as SSH update) accessing web service. ; In most cases you do not need to change the default value. ; Alter it only if your SSH server node is not the same as HTTP node. diff --git a/modules/setting/setting.go b/modules/setting/setting.go index a51cbf53b..559ff088c 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -12,6 +12,7 @@ import ( "path" "path/filepath" "runtime" + "strconv" "strings" "time" @@ -31,9 +32,10 @@ import ( type Scheme string const ( - HTTP Scheme = "http" - HTTPS Scheme = "https" - FCGI Scheme = "fcgi" + HTTP Scheme = "http" + HTTPS Scheme = "https" + FCGI Scheme = "fcgi" + UNIX_SOCKET Scheme = "unix" ) type LandingPage string @@ -58,16 +60,17 @@ var ( AppDataPath string // Server settings - Protocol Scheme - Domain string - HttpAddr, HttpPort string - LocalURL string - OfflineMode bool - DisableRouterLog bool - CertFile, KeyFile string - StaticRootPath string - EnableGzip bool - LandingPageUrl LandingPage + Protocol Scheme + Domain string + HttpAddr, HttpPort string + LocalURL string + OfflineMode bool + DisableRouterLog bool + CertFile, KeyFile string + StaticRootPath string + EnableGzip bool + LandingPageUrl LandingPage + UnixSocketPermission uint32 SSH struct { Disabled bool `ini:"DISABLE_SSH"` @@ -367,11 +370,19 @@ func NewContext() { KeyFile = sec.Key("KEY_FILE").String() } else if sec.Key("PROTOCOL").String() == "fcgi" { Protocol = FCGI + } else if sec.Key("PROTOCOL").String() == "unix" { + Protocol = UNIX_SOCKET } Domain = sec.Key("DOMAIN").MustString("localhost") HttpAddr = sec.Key("HTTP_ADDR").MustString("0.0.0.0") HttpPort = sec.Key("HTTP_PORT").MustString("3000") LocalURL = sec.Key("LOCAL_ROOT_URL").MustString(string(Protocol) + "://localhost:" + HttpPort + "/") + UnixSocketPermissionRaw := sec.Key("UNIX_SOCKET_PERMISSION").MustString("666") + UnixSocketPermissionParsed, err := strconv.ParseUint(UnixSocketPermissionRaw, 8, 32) + if err != nil || UnixSocketPermissionParsed > 0777 { + log.Fatal(4, "Fail to parse unixSocketPermission: %s", UnixSocketPermissionRaw) + } + UnixSocketPermission = uint32(UnixSocketPermissionParsed) OfflineMode = sec.Key("OFFLINE_MODE").MustBool() DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool() StaticRootPath = sec.Key("STATIC_ROOT_PATH").MustString(workDir)