diff --git a/cmd/web.go b/cmd/web.go
index 8722ddb60..11620c6b0 100644
--- a/cmd/web.go
+++ b/cmd/web.go
@@ -9,6 +9,8 @@ import (
 	"net"
 	"net/http"
 	"os"
+	"path/filepath"
+	"strconv"
 	"strings"
 
 	_ "net/http/pprof" // Used for debugging if enabled and a web server is running
@@ -25,6 +27,9 @@ import (
 	ini "gopkg.in/ini.v1"
 )
 
+// PIDFile could be set from build tag
+var PIDFile = "/run/gitea.pid"
+
 // CmdWeb represents the available web sub-command.
 var CmdWeb = cli.Command{
 	Name:  "web",
@@ -45,7 +50,7 @@ and it takes care of all the other things for you`,
 		},
 		cli.StringFlag{
 			Name:  "pid, P",
-			Value: setting.PIDFile,
+			Value: PIDFile,
 			Usage: "Custom pid file path",
 		},
 		cli.BoolFlag{
@@ -81,6 +86,22 @@ func runHTTPRedirector() {
 	}
 }
 
+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)
+	}
+}
+
 func runWeb(ctx *cli.Context) error {
 	if ctx.Bool("verbose") {
 		_ = log.DelLogger("console")
@@ -107,8 +128,7 @@ func runWeb(ctx *cli.Context) error {
 
 	// Set pid file setting
 	if ctx.IsSet("pid") {
-		setting.PIDFile = ctx.String("pid")
-		setting.WritePIDFile = true
+		createPIDFile(ctx.String("pid"))
 	}
 
 	// Perform pre-initialization
diff --git a/docs/content/doc/installation/from-source.en-us.md b/docs/content/doc/installation/from-source.en-us.md
index ae3ddc5c4..d0db639b0 100644
--- a/docs/content/doc/installation/from-source.en-us.md
+++ b/docs/content/doc/installation/from-source.en-us.md
@@ -159,7 +159,7 @@ using the `LDFLAGS` environment variable for `make`. The appropriate settings ar
 - For _`CustomConf`_ you should use `-X \"code.gitea.io/gitea/modules/setting.CustomConf=conf.ini\"`
 - For _`AppWorkPath`_ you should use `-X \"code.gitea.io/gitea/modules/setting.AppWorkPath=working-path\"`
 - For _`StaticRootPath`_ you should use `-X \"code.gitea.io/gitea/modules/setting.StaticRootPath=static-root-path\"`
-- To change the default PID file location use `-X \"code.gitea.io/gitea/modules/setting.PIDFile=/run/gitea.pid\"`
+- To change the default PID file location use `-X \"code.gitea.io/gitea/cmd.PIDFile=/run/gitea.pid\"`
 
 Add as many of the strings with their preceding `-X` to the `LDFLAGS` variable and run `make build`
 with the appropriate `TAGS` as above.
diff --git a/modules/setting/database.go b/modules/setting/database.go
index d7a5078fe..8c4dfb21d 100644
--- a/modules/setting/database.go
+++ b/modules/setting/database.go
@@ -54,7 +54,11 @@ var (
 
 // LoadDBSetting loads the database settings
 func LoadDBSetting() {
-	sec := CfgProvider.Section("database")
+	loadDBSetting(CfgProvider)
+}
+
+func loadDBSetting(rootCfg ConfigProvider) {
+	sec := rootCfg.Section("database")
 	Database.Type = DatabaseType(sec.Key("DB_TYPE").String())
 	defaultCharset := "utf8"
 
diff --git a/modules/setting/setting.go b/modules/setting/setting.go
index 87b1e2797..4d7a7caab 100644
--- a/modules/setting/setting.go
+++ b/modules/setting/setting.go
@@ -12,7 +12,6 @@ import (
 	"path"
 	"path/filepath"
 	"runtime"
-	"strconv"
 	"strings"
 	"time"
 
@@ -42,15 +41,13 @@ var (
 	AppWorkPath string
 
 	// Global setting objects
-	CfgProvider  ConfigProvider
-	CustomPath   string // Custom directory path
-	CustomConf   string
-	PIDFile      = "/run/gitea.pid"
-	WritePIDFile bool
-	RunMode      string
-	RunUser      string
-	IsProd       bool
-	IsWindows    bool
+	CfgProvider ConfigProvider
+	CustomPath  string // Custom directory path
+	CustomConf  string
+	RunMode     string
+	RunUser     string
+	IsProd      bool
+	IsWindows   bool
 )
 
 func getAppPath() (string, error) {
@@ -141,22 +138,6 @@ func IsRunUserMatchCurrentUser(runUser string) (string, bool) {
 	return currentUser, runUser == currentUser
 }
 
-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)
-	}
-}
-
 // SetCustomPathAndConf will set CustomPath and CustomConf with reference to the
 // GITEA_CUSTOM environment variable and with provided overrides before stepping
 // back to the default
@@ -218,17 +199,17 @@ func PrepareAppDataPath() error {
 
 // InitProviderFromExistingFile initializes config provider from an existing config file (app.ini)
 func InitProviderFromExistingFile() {
-	CfgProvider = newFileProviderFromConf(CustomConf, WritePIDFile, false, PIDFile, "")
+	CfgProvider = newFileProviderFromConf(CustomConf, false, "")
 }
 
 // InitProviderAllowEmpty initializes config provider from file, it's also fine that if the config file (app.ini) doesn't exist
 func InitProviderAllowEmpty() {
-	CfgProvider = newFileProviderFromConf(CustomConf, WritePIDFile, true, PIDFile, "")
+	CfgProvider = newFileProviderFromConf(CustomConf, true, "")
 }
 
 // InitProviderAndLoadCommonSettingsForTest initializes config provider and load common setttings for tests
 func InitProviderAndLoadCommonSettingsForTest(extraConfigs ...string) {
-	CfgProvider = newFileProviderFromConf(CustomConf, WritePIDFile, true, PIDFile, strings.Join(extraConfigs, "\n"))
+	CfgProvider = newFileProviderFromConf(CustomConf, true, strings.Join(extraConfigs, "\n"))
 	loadCommonSettingsFrom(CfgProvider)
 	if err := PrepareAppDataPath(); err != nil {
 		log.Fatal("Can not prepare APP_DATA_PATH: %v", err)
@@ -241,13 +222,9 @@ func InitProviderAndLoadCommonSettingsForTest(extraConfigs ...string) {
 
 // newFileProviderFromConf initializes configuration context.
 // NOTE: do not print any log except error.
-func newFileProviderFromConf(customConf string, writePIDFile, allowEmpty bool, pidFile, extraConfig string) *ini.File {
+func newFileProviderFromConf(customConf string, allowEmpty bool, extraConfig string) *ini.File {
 	cfg := ini.Empty()
 
-	if writePIDFile && len(pidFile) > 0 {
-		createPIDFile(pidFile)
-	}
-
 	isFile, err := util.IsFile(customConf)
 	if err != nil {
 		log.Error("Unable to check if %s is a file. Error: %v", customConf, err)
@@ -380,7 +357,7 @@ func CreateOrAppendToCustomConf(purpose string, callback func(cfg *ini.File)) {
 
 // LoadSettings initializes the settings for normal start up
 func LoadSettings() {
-	LoadDBSetting()
+	loadDBSetting(CfgProvider)
 	loadServiceFrom(CfgProvider)
 	loadOAuth2ClientFrom(CfgProvider)
 	InitLogs(false)
@@ -401,7 +378,7 @@ func LoadSettings() {
 
 // LoadSettingsForInstall initializes the settings for install
 func LoadSettingsForInstall() {
-	LoadDBSetting()
+	loadDBSetting(CfgProvider)
 	loadServiceFrom(CfgProvider)
 	loadMailerFrom(CfgProvider)
 }