2014-02-19 04:50:53 -05:00
// Copyright 2014 The Gogs Authors. All rights reserved.
2022-11-27 13:20:29 -05:00
// SPDX-License-Identifier: MIT
2014-02-19 04:50:53 -05:00
2014-05-01 20:21:46 -05:00
package cmd
2014-02-19 04:50:53 -05:00
import (
2019-12-15 04:51:28 -05:00
"context"
2014-02-19 04:50:53 -05:00
"fmt"
2020-07-26 15:31:28 -05:00
"net"
2014-02-19 04:50:53 -05:00
"net/http"
2014-04-15 19:01:20 -05:00
"os"
2023-03-16 02:22:54 -05:00
"path/filepath"
"strconv"
2014-09-29 04:38:46 -05:00
"strings"
2014-02-19 04:50:53 -05:00
2021-11-17 07:34:35 -05:00
_ "net/http/pprof" // Used for debugging if enabled and a web server is running
2019-10-23 10:32:19 -05:00
"code.gitea.io/gitea/modules/graceful"
2016-11-10 11:24:48 -05:00
"code.gitea.io/gitea/modules/log"
2022-03-31 12:01:43 -05:00
"code.gitea.io/gitea/modules/process"
2016-11-10 11:24:48 -05:00
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers"
2021-06-08 18:33:54 -05:00
"code.gitea.io/gitea/routers/install"
2016-12-25 20:16:37 -05:00
2022-06-18 05:04:52 -05:00
"github.com/felixge/fgprof"
2016-11-05 11:56:35 -05:00
"github.com/urfave/cli"
2017-12-13 03:57:28 -05:00
ini "gopkg.in/ini.v1"
2014-02-19 04:50:53 -05:00
)
2023-03-16 02:22:54 -05:00
// PIDFile could be set from build tag
var PIDFile = "/run/gitea.pid"
2016-11-04 06:42:18 -05:00
// CmdWeb represents the available web sub-command.
2014-02-19 04:50:53 -05:00
var CmdWeb = cli . Command {
Name : "web" ,
2016-12-21 07:13:17 -05:00
Usage : "Start Gitea web server" ,
Description : ` Gitea web server is the only thing you need to run ,
2014-03-24 06:36:38 -05:00
and it takes care of all the other things for you ` ,
2014-02-19 04:50:53 -05:00
Action : runWeb ,
2015-02-01 12:41:03 -05:00
Flags : [ ] cli . Flag {
2016-11-09 17:18:22 -05:00
cli . StringFlag {
Name : "port, p" ,
Value : "3000" ,
Usage : "Temporary port number to prevent conflict" ,
} ,
2020-10-30 14:26:03 -05:00
cli . StringFlag {
Name : "install-port" ,
Value : "3000" ,
Usage : "Temporary port number to run the install page on to prevent conflict" ,
} ,
2017-01-09 06:54:57 -05:00
cli . StringFlag {
Name : "pid, P" ,
2023-03-16 02:22:54 -05:00
Value : PIDFile ,
2017-01-09 06:54:57 -05:00
Usage : "Custom pid file path" ,
} ,
2021-06-26 19:56:58 -05:00
cli . BoolFlag {
Name : "quiet, q" ,
Usage : "Only display Fatal logging errors until logging is set-up" ,
} ,
cli . BoolFlag {
Name : "verbose" ,
Usage : "Set initial logging to TRACE level until logging is properly set-up" ,
} ,
2015-02-01 12:41:03 -05:00
} ,
2014-02-19 04:50:53 -05:00
}
2017-12-25 17:23:43 -05:00
func runHTTPRedirector ( ) {
2022-03-31 12:01:43 -05:00
_ , _ , finished := process . GetManager ( ) . AddTypedContext ( graceful . GetManager ( ) . HammerContext ( ) , "Web: HTTP Redirector" , process . SystemProcessType , true )
defer finished ( )
2017-12-25 17:23:43 -05:00
source := fmt . Sprintf ( "%s:%s" , setting . HTTPAddr , setting . PortToRedirect )
dest := strings . TrimSuffix ( setting . AppURL , "/" )
log . Info ( "Redirecting: %s to %s" , source , dest )
handler := http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
target := dest + r . URL . Path
if len ( r . URL . RawQuery ) > 0 {
target += "?" + r . URL . RawQuery
}
http . Redirect ( w , r , target , http . StatusTemporaryRedirect )
} )
2022-08-21 13:20:43 -05:00
err := runHTTP ( "tcp" , source , "HTTP Redirector" , handler , setting . RedirectorUseProxyProtocol )
2017-12-25 17:23:43 -05:00
if err != nil {
2019-04-02 02:48:31 -05:00
log . Fatal ( "Failed to start port redirection: %v" , err )
2017-12-25 17:23:43 -05:00
}
}
2023-03-16 02:22:54 -05:00
func createPIDFile ( pidPath string ) {
currentPid := os . Getpid ( )
if err := os . MkdirAll ( filepath . Dir ( pidPath ) , os . ModePerm ) ; err != nil {
log . Fatal ( "Failed to create PID folder: %v" , err )
}
file , err := os . Create ( pidPath )
if err != nil {
log . Fatal ( "Failed to create PID file: %v" , err )
}
defer file . Close ( )
if _ , err := file . WriteString ( strconv . FormatInt ( int64 ( currentPid ) , 10 ) ) ; err != nil {
log . Fatal ( "Failed to write PID information: %v" , err )
}
}
2016-05-12 13:32:28 -05:00
func runWeb ( ctx * cli . Context ) error {
2021-06-26 19:56:58 -05:00
if ctx . Bool ( "verbose" ) {
_ = log . DelLogger ( "console" )
log . NewLogger ( 0 , "console" , "console" , fmt . Sprintf ( ` { "level": "trace", "colorize": %t, "stacktraceLevel": "none"} ` , log . CanColorStdout ) )
} else if ctx . Bool ( "quiet" ) {
_ = log . DelLogger ( "console" )
log . NewLogger ( 0 , "console" , "console" , fmt . Sprintf ( ` { "level": "fatal", "colorize": %t, "stacktraceLevel": "none"} ` , log . CanColorStdout ) )
}
2021-08-23 14:40:59 -05:00
defer func ( ) {
if panicked := recover ( ) ; panicked != nil {
2022-01-20 06:41:25 -05:00
log . Fatal ( "PANIC: %v\n%s" , panicked , log . Stack ( 2 ) )
2021-08-23 14:40:59 -05:00
}
} ( )
2021-06-26 19:56:58 -05:00
2019-12-15 04:51:28 -05:00
managerCtx , cancel := context . WithCancel ( context . Background ( ) )
graceful . InitManager ( managerCtx )
defer cancel ( )
2019-10-15 08:39:51 -05:00
if os . Getppid ( ) > 1 && len ( os . Getenv ( "LISTEN_FDS" ) ) > 0 {
log . Info ( "Restarting Gitea on PID: %d from parent PID: %d" , os . Getpid ( ) , os . Getppid ( ) )
} else {
log . Info ( "Starting Gitea on PID: %d" , os . Getpid ( ) )
}
// Set pid file setting
2017-01-09 06:54:57 -05:00
if ctx . IsSet ( "pid" ) {
2023-03-16 02:22:54 -05:00
createPIDFile ( ctx . String ( "pid" ) )
2017-01-09 06:54:57 -05:00
}
2020-10-19 16:03:08 -05:00
// Perform pre-initialization
2021-06-08 18:33:54 -05:00
needsInstall := install . PreloadSettings ( graceful . GetManager ( ) . HammerContext ( ) )
2020-10-19 16:03:08 -05:00
if needsInstall {
2020-10-30 14:26:03 -05:00
// Flag for port number in case first time run conflict
if ctx . IsSet ( "port" ) {
if err := setPort ( ctx . String ( "port" ) ) ; err != nil {
return err
}
}
if ctx . IsSet ( "install-port" ) {
if err := setPort ( ctx . String ( "install-port" ) ) ; err != nil {
return err
}
}
2022-08-28 04:43:25 -05:00
installCtx , cancel := context . WithCancel ( graceful . GetManager ( ) . HammerContext ( ) )
c := install . Routes ( installCtx )
2020-11-13 07:51:07 -05:00
err := listen ( c , false )
2022-08-28 04:43:25 -05:00
cancel ( )
2021-12-01 02:50:01 -05:00
if err != nil {
log . Critical ( "Unable to open listener for installer. Is Gitea already running?" )
graceful . GetManager ( ) . DoGracefulShutdown ( )
}
2020-10-19 16:03:08 -05:00
select {
case <- graceful . GetManager ( ) . IsShutdown ( ) :
<- graceful . GetManager ( ) . Done ( )
log . Info ( "PID: %d Gitea Web Finished" , os . Getpid ( ) )
log . Close ( )
return err
default :
}
} else {
NoInstallListener ( )
}
if setting . EnablePprof {
go func ( ) {
2022-06-18 05:04:52 -05:00
http . DefaultServeMux . Handle ( "/debug/fgprof" , fgprof . Handler ( ) )
2022-03-31 12:01:43 -05:00
_ , _ , finished := process . GetManager ( ) . AddTypedContext ( context . Background ( ) , "Web: PProf Server" , process . SystemProcessType , true )
2022-07-23 12:33:55 -05:00
// The pprof server is for debug purpose only, it shouldn't be exposed on public network. At the moment it's not worth to introduce a configurable option for it.
2020-10-19 16:03:08 -05:00
log . Info ( "Starting pprof server on localhost:6060" )
2022-07-23 12:33:55 -05:00
log . Info ( "Stopped pprof server: %v" , http . ListenAndServe ( "localhost:6060" , nil ) )
2022-03-31 12:01:43 -05:00
finished ( )
2020-10-19 16:03:08 -05:00
} ( )
}
log . Info ( "Global init" )
2019-10-15 08:39:51 -05:00
// Perform global initialization
2023-02-19 11:12:01 -05:00
setting . InitProviderFromExistingFile ( )
setting . LoadCommonSettings ( )
2021-12-01 02:50:01 -05:00
routers . GlobalInitInstalled ( graceful . GetManager ( ) . HammerContext ( ) )
// We check that AppDataPath exists here (it should have been created during installation)
// We can't check it in `GlobalInitInstalled`, because some integration tests
// use cmd -> GlobalInitInstalled, but the AppDataPath doesn't exist during those tests.
if _ , err := os . Stat ( setting . AppDataPath ) ; err != nil {
log . Fatal ( "Can not find APP_DATA_PATH '%s'" , setting . AppDataPath )
}
2014-02-19 04:50:53 -05:00
2020-10-30 14:26:03 -05:00
// Override the provided port number within the configuration
if ctx . IsSet ( "port" ) {
if err := setPort ( ctx . String ( "port" ) ) ; err != nil {
return err
}
}
2014-03-23 00:48:01 -05:00
2021-01-26 10:36:53 -05:00
// Set up Chi routes
2022-08-28 04:43:25 -05:00
c := routers . NormalRoutes ( graceful . GetManager ( ) . HammerContext ( ) )
2020-11-13 07:51:07 -05:00
err := listen ( c , true )
2020-10-19 16:03:08 -05:00
<- graceful . GetManager ( ) . Done ( )
log . Info ( "PID: %d Gitea Web Finished" , os . Getpid ( ) )
log . Close ( )
return err
}
2017-12-13 03:57:28 -05:00
2020-10-19 16:03:08 -05:00
func setPort ( port string ) error {
setting . AppURL = strings . Replace ( setting . AppURL , setting . HTTPPort , port , 1 )
setting . HTTPPort = port
2017-12-13 03:57:28 -05:00
2020-10-19 16:03:08 -05:00
switch setting . Protocol {
2021-12-05 23:46:11 -05:00
case setting . HTTPUnix :
2020-10-19 16:03:08 -05:00
case setting . FCGI :
case setting . FCGIUnix :
default :
defaultLocalURL := string ( setting . Protocol ) + "://"
if setting . HTTPAddr == "0.0.0.0" {
defaultLocalURL += "localhost"
} else {
defaultLocalURL += setting . HTTPAddr
}
defaultLocalURL += ":" + setting . HTTPPort + "/"
2017-12-13 03:57:28 -05:00
2021-05-29 13:44:14 -05:00
// Save LOCAL_ROOT_URL if port changed
2022-10-01 12:26:33 -05:00
setting . CreateOrAppendToCustomConf ( "server.LOCAL_ROOT_URL" , func ( cfg * ini . File ) {
2021-05-29 13:44:14 -05:00
cfg . Section ( "server" ) . Key ( "LOCAL_ROOT_URL" ) . SetValue ( defaultLocalURL )
} )
2015-02-01 12:41:03 -05:00
}
2020-10-19 16:03:08 -05:00
return nil
}
2015-02-01 12:41:03 -05:00
2020-11-13 07:51:07 -05:00
func listen ( m http . Handler , handleRedirector bool ) error {
2018-01-12 17:16:49 -05:00
listenAddr := setting . HTTPAddr
2021-12-05 23:46:11 -05:00
if setting . Protocol != setting . HTTPUnix && setting . Protocol != setting . FCGIUnix {
2020-07-26 15:31:28 -05:00
listenAddr = net . JoinHostPort ( listenAddr , setting . HTTPPort )
2016-08-11 16:46:33 -05:00
}
2022-03-31 12:01:43 -05:00
_ , _ , finished := process . GetManager ( ) . AddTypedContext ( graceful . GetManager ( ) . HammerContext ( ) , "Web: Gitea Server" , process . SystemProcessType , true )
defer finished ( )
2016-11-27 05:14:25 -05:00
log . Info ( "Listen: %v://%s%s" , setting . Protocol , listenAddr , setting . AppSubURL )
2021-11-01 03:39:52 -05:00
// This can be useful for users, many users do wrong to their config and get strange behaviors behind a reverse-proxy.
// A user may fix the configuration mistake when he sees this log.
// And this is also very helpful to maintainers to provide help to users to resolve their configuration problems.
log . Info ( "AppURL(ROOT_URL): %s" , setting . AppURL )
2016-08-11 16:55:10 -05:00
2016-12-25 20:16:37 -05:00
if setting . LFS . StartServer {
log . Info ( "LFS server enabled" )
}
2016-08-11 16:55:10 -05:00
var err error
2014-05-25 19:11:25 -05:00
switch setting . Protocol {
case setting . HTTP :
2020-10-19 16:03:08 -05:00
if handleRedirector {
NoHTTPRedirector ( )
}
2022-08-21 13:20:43 -05:00
err = runHTTP ( "tcp" , listenAddr , "Web" , m , setting . UseProxyProtocol )
2014-05-25 19:11:25 -05:00
case setting . HTTPS :
2022-02-08 00:45:35 -05:00
if setting . EnableAcme {
err = runACME ( listenAddr , m )
2018-08-21 08:56:50 -05:00
break
2022-08-21 13:20:43 -05:00
}
if handleRedirector {
if setting . RedirectOtherPort {
go runHTTPRedirector ( )
} else {
NoHTTPRedirector ( )
2020-10-19 16:03:08 -05:00
}
2017-12-25 17:23:43 -05:00
}
2022-08-21 13:20:43 -05:00
err = runHTTPS ( "tcp" , listenAddr , "Web" , setting . CertFile , setting . KeyFile , m , setting . UseProxyProtocol , setting . ProxyProtocolTLSBridging )
2014-11-03 20:46:53 -05:00
case setting . FCGI :
2020-10-19 16:03:08 -05:00
if handleRedirector {
NoHTTPRedirector ( )
}
2022-08-21 13:20:43 -05:00
err = runFCGI ( "tcp" , listenAddr , "FCGI Web" , m , setting . UseProxyProtocol )
2021-12-05 23:46:11 -05:00
case setting . HTTPUnix :
2020-10-19 16:03:08 -05:00
if handleRedirector {
NoHTTPRedirector ( )
}
2022-08-21 13:20:43 -05:00
err = runHTTP ( "unix" , listenAddr , "Web" , m , setting . UseProxyProtocol )
2019-12-10 07:23:26 -05:00
case setting . FCGIUnix :
2020-10-19 16:03:08 -05:00
if handleRedirector {
NoHTTPRedirector ( )
}
2022-08-21 13:20:43 -05:00
err = runFCGI ( "unix" , listenAddr , "Web" , m , setting . UseProxyProtocol )
2014-05-25 19:11:25 -05:00
default :
2019-04-02 02:48:31 -05:00
log . Fatal ( "Invalid protocol: %s" , setting . Protocol )
2014-05-25 19:11:25 -05:00
}
if err != nil {
2019-10-15 08:39:51 -05:00
log . Critical ( "Failed to start server: %v" , err )
2014-03-18 08:58:58 -05:00
}
2019-10-15 08:39:51 -05:00
log . Info ( "HTTP Listener: %s Closed" , listenAddr )
2020-10-19 16:03:08 -05:00
return err
2014-02-19 04:50:53 -05:00
}