From 0ad1b3af4be95e5912aae02f863fb3b9a50aa0ba Mon Sep 17 00:00:00 2001 From: Jacky Date: Tue, 9 Mar 2021 19:24:28 +0800 Subject: [PATCH] bug fix and auto detect nginx config dir path --- .gitignore | 1 + server/api/api.go | 7 +- server/api/backup.go | 1 - server/api/config.go | 76 +++++++++++++++------ server/api/domain.go | 132 ++++++++++++++++++++++++++++--------- server/main.go | 3 + server/model/models.go | 9 ++- server/router/routers.go | 2 + server/template/http-conf | 4 +- server/template/https-conf | 8 ++- server/test/nginx_test.go | 20 ++++++ server/tool/nginx.go | 15 ++++- 12 files changed, 219 insertions(+), 59 deletions(-) create mode 100644 server/test/nginx_test.go diff --git a/.gitignore b/.gitignore index 36b6cdae..9d60a758 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ database.db +server/tmp/main diff --git a/server/api/api.go b/server/api/api.go index 6b0acb29..b844975a 100644 --- a/server/api/api.go +++ b/server/api/api.go @@ -1,9 +1,14 @@ package api import ( + "github.com/gin-gonic/gin" "log" + "net/http" ) -func ErrorHandler(err error) { +func ErrorHandler(c *gin.Context, err error) { log.Println(err) + c.JSON(http.StatusInternalServerError, gin.H{ + "message": err.Error(), + }) } diff --git a/server/api/backup.go b/server/api/backup.go index c7b8ab4b..9b42c55e 100644 --- a/server/api/backup.go +++ b/server/api/backup.go @@ -21,5 +21,4 @@ func GetFileBackup(c *gin.Context) { backup := model.GetBackup(com.StrTo(id).MustInt()) c.JSON(http.StatusOK, backup) - } \ No newline at end of file diff --git a/server/api/config.go b/server/api/config.go index 3d562b97..b10b57d3 100644 --- a/server/api/config.go +++ b/server/api/config.go @@ -7,15 +7,17 @@ import ( "io/ioutil" "log" "net/http" + "os" "path/filepath" "strconv" ) func GetConfigs(c *gin.Context) { - configFiles, err := ioutil.ReadDir(filepath.Join("/usr/local/etc/nginx")) + configFiles, err := ioutil.ReadDir(tool.GetNginxConfPath("/")) if err != nil { - log.Println(err) + ErrorHandler(c, err) + return } var configs []gin.H @@ -25,9 +27,9 @@ func GetConfigs(c *gin.Context) { if !file.IsDir() && "." != file.Name()[0:1] { configs = append(configs, gin.H{ - "name": file.Name(), - "size": file.Size(), - "modify": file.ModTime(), + "name": file.Name(), + "size": file.Size(), + "modify": file.ModTime(), }) } } @@ -39,12 +41,13 @@ func GetConfigs(c *gin.Context) { func GetConfig(c *gin.Context) { name := c.Param("name") - path := filepath.Join("/usr/local/etc/nginx", name) + path := filepath.Join(tool.GetNginxConfPath("/"), name) content, err := ioutil.ReadFile(path) if err != nil { - log.Println(err) + ErrorHandler(c, err) + return } c.JSON(http.StatusOK, gin.H{ @@ -53,51 +56,82 @@ func GetConfig(c *gin.Context) { } -func AddConfig(c *gin.Context) { - name := c.PostForm("name") - content := c.PostForm("content") - path := filepath.Join(tool.GetNginxConfPath("/"), name) +type AddConfigJson struct { + Name string `json:"name" binding:"required"` + Content string `json:"content" binding:"required"` +} - s, err := strconv.Unquote(`"` + content + `"`) +func AddConfig(c *gin.Context) { + var request AddConfigJson + err := c.BindJSON(&request) if err != nil { - log.Println(err) + ErrorHandler(c, err) + return } - if s != "" { - err := ioutil.WriteFile(path, []byte(s), 0644) + name := request.Name + content := request.Content + + path := filepath.Join(tool.GetNginxConfPath("/"), name) + + log.Println(path) + if _, err = os.Stat(path); err == nil { + c.JSON(http.StatusNotAcceptable, gin.H{ + "message": "config exist", + }) + return + } + + if content != "" { + err := ioutil.WriteFile(path, []byte(content), 0644) if err != nil { - log.Println(err) + ErrorHandler(c, err) + return } } tool.ReloadNginx() c.JSON(http.StatusOK, gin.H{ - "message": "ok", + "name": name, + "content": content, }) } +type EditConfigJson struct { + Content string `json:"content" binding:"required"` +} + func EditConfig(c *gin.Context) { name := c.Param("name") - content := c.PostForm("content") + var request EditConfigJson + err := c.BindJSON(&request) + if err != nil { + ErrorHandler(c, err) + return + } path := filepath.Join(tool.GetNginxConfPath("/"), name) + content := request.Content s, err := strconv.Unquote(`"` + content + `"`) if err != nil { - log.Println(err) + ErrorHandler(c, err) + return } origContent, err := ioutil.ReadFile(path) if err != nil { - log.Println(err) + ErrorHandler(c, err) + return } if s != "" && s != string(origContent) { model.CreateBackup(path) err := ioutil.WriteFile(path, []byte(s), 0644) if err != nil { - log.Println(err) + ErrorHandler(c, err) + return } } diff --git a/server/api/domain.go b/server/api/domain.go index 0d55aaf0..695c0c7c 100644 --- a/server/api/domain.go +++ b/server/api/domain.go @@ -9,7 +9,6 @@ import ( "net/http" "os" "path/filepath" - "strconv" "strings" ) @@ -17,7 +16,8 @@ func GetDomains(c *gin.Context) { configFiles, err := ioutil.ReadDir(tool.GetNginxConfPath("sites-available")) if err != nil { - log.Println(err) + ErrorHandler(c, err) + return } enabledConfig, err := ioutil.ReadDir(filepath.Join(tool.GetNginxConfPath("sites-enabled"))) @@ -28,7 +28,8 @@ func GetDomains(c *gin.Context) { } if err != nil { - log.Println(err) + ErrorHandler(c, err) + return } var configs []gin.H @@ -67,7 +68,7 @@ func GetDomain(c *gin.Context) { "message": err.Error(), }) } - log.Println(err) + ErrorHandler(c, err) return } @@ -79,28 +80,45 @@ func GetDomain(c *gin.Context) { } func AddDomain(c *gin.Context) { - name := c.PostForm("name") - SupportSSL := c.PostForm("support_ssl") + request := make(gin.H) + err := c.BindJSON(&request) + if err != nil { + ErrorHandler(c, err) + return + } + + name := request["name"].(string) + path := filepath.Join(tool.GetNginxConfPath("sites-available"), name) + log.Println(path) + if _, err = os.Stat(path); err == nil { + c.JSON(http.StatusNotAcceptable, gin.H{ + "message": "site exist", + }) + return + } + + SupportSSL := request["support_ssl"] baseKeys := []string{"http_listen_port", "https_listen_port", "server_name", "ssl_certificate", "ssl_certificate_key", - "root", "extra", + "index", "root", "extra", } tmp, err := ioutil.ReadFile("template/http-conf") - log.Println(SupportSSL) - if SupportSSL == "true" { + if err != nil { + ErrorHandler(c, err) + return + } + + if SupportSSL == true { tmp, err = ioutil.ReadFile("template/https-conf") } if err != nil { - log.Println(err) - c.JSON(http.StatusInternalServerError, gin.H{ - "message": "server error", - }) + ErrorHandler(c, err) return } @@ -109,13 +127,25 @@ func AddDomain(c *gin.Context) { content := template for i := range baseKeys { - content = strings.Replace(content, "{{ " + baseKeys[i] +" }}", - c.PostForm(baseKeys[i]), - -1) + val, ok := request[baseKeys[i]] + replace := "" + if ok { + replace = val.(string) + } + content = strings.Replace(content, "{{ "+baseKeys[i]+" }}", + replace, -1) } log.Println(name, content) + err = ioutil.WriteFile(path, []byte(content), 0644) + + if err != nil { + ErrorHandler(c, err) + return + } + + c.JSON(http.StatusOK, gin.H{ "name": name, "content": content, @@ -124,29 +154,36 @@ func AddDomain(c *gin.Context) { } func EditDomain(c *gin.Context) { + var err error + var origContent []byte name := c.Param("name") - content := c.PostForm("content") + request := make(gin.H) + err = c.BindJSON(&request) path := filepath.Join(tool.GetNginxConfPath("sites-available"), name) - s, err := strconv.Unquote(`"` + content + `"`) - if err != nil { - log.Println(err) + if _, err = os.Stat(path); os.IsNotExist(err) { + c.JSON(http.StatusNotFound, gin.H{ + "message": "site not found", + }) + return } - origContent, err := ioutil.ReadFile(path) + origContent, err = ioutil.ReadFile(path) if err != nil { - log.Println(err) + ErrorHandler(c, err) + return } - if s != "" && s != string(origContent) { + if request["content"] != "" && request["content"] != string(origContent) { model.CreateBackup(path) - err := ioutil.WriteFile(path, []byte(s), 0644) + err := ioutil.WriteFile(path, []byte(request["content"].(string)), 0644) if err != nil { - log.Println(err) + ErrorHandler(c, err) + return } } - if _, err := os.Stat(filepath.Join(tool.GetNginxConfPath("sites-enabled"), name)); os.IsExist(err) { + if _, err := os.Stat(filepath.Join(tool.GetNginxConfPath("sites-enabled"), name)); err == nil { tool.ReloadNginx() } @@ -160,13 +197,15 @@ func EnableDomain(c *gin.Context) { _, err := os.Stat(configFilePath) if err != nil { - log.Println(err) + ErrorHandler(c, err) + return } err = os.Symlink(configFilePath, enabledConfigFilePath) if err != nil { - log.Println(err) + ErrorHandler(c, err) + return } tool.ReloadNginx() @@ -182,13 +221,15 @@ func DisableDomain(c *gin.Context) { _, err := os.Stat(enabledConfigFilePath) if err != nil { - log.Println(err) + ErrorHandler(c, err) + return } err = os.Remove(enabledConfigFilePath) if err != nil { - log.Println(err) + ErrorHandler(c, err) + return } tool.ReloadNginx() @@ -199,5 +240,36 @@ func DisableDomain(c *gin.Context) { } func DeleteDomain(c *gin.Context) { + var err error + name := c.Param("name") + request := make(gin.H) + err = c.BindJSON(request) + availablePath := filepath.Join(tool.GetNginxConfPath("sites-available"), name) + enabledPath := filepath.Join(tool.GetNginxConfPath("sites-enabled"), name) + + if _, err = os.Stat(availablePath); os.IsNotExist(err) { + c.JSON(http.StatusNotFound, gin.H{ + "message": "site not found", + }) + return + } + + if _, err = os.Stat(enabledPath); err == nil { + c.JSON(http.StatusNotAcceptable, gin.H{ + "message": "site is enabled", + }) + return + } + + err = os.Remove(availablePath) + + if err != nil { + ErrorHandler(c, err) + return + } + + c.JSON(http.StatusOK, gin.H{ + "message": "ok", + }) } diff --git a/server/main.go b/server/main.go index 81e24902..a0068089 100644 --- a/server/main.go +++ b/server/main.go @@ -4,6 +4,7 @@ import ( "github.com/0xJacky/Nginx-UI/model" "github.com/0xJacky/Nginx-UI/router" "github.com/0xJacky/Nginx-UI/settings" + "github.com/0xJacky/Nginx-UI/tool" "log" ) @@ -14,6 +15,8 @@ func main() { model.Init() + log.Printf("nginx config dir path: %s", tool.GetNginxConfPath("")) + err := r.Run(":" + settings.ServerSettings.HttpPort) if err != nil { diff --git a/server/model/models.go b/server/model/models.go index d4cd55a4..dd3877f1 100644 --- a/server/model/models.go +++ b/server/model/models.go @@ -22,5 +22,12 @@ func Init() { } // Migrate the schema - db.AutoMigrate(&ConfigBackup{}) + AutoMigrate(&ConfigBackup{}) +} + +func AutoMigrate(model interface{}) { + err := db.AutoMigrate(model) + if err != nil { + log.Fatal(err) + } } diff --git a/server/router/routers.go b/server/router/routers.go index 3e4461b1..26dc8c92 100644 --- a/server/router/routers.go +++ b/server/router/routers.go @@ -26,9 +26,11 @@ func InitRouter() *gin.Engine { endpoint.POST("domain/:name", api.EditDomain) endpoint.POST("domain/:name/enable", api.EnableDomain) endpoint.POST("domain/:name/disable", api.DisableDomain) + endpoint.DELETE("domain/:name", api.DeleteDomain) endpoint.GET("configs", api.GetConfigs) endpoint.GET("config/:name", api.GetConfig) + endpoint.POST("config", api.AddConfig) endpoint.POST("config/:name", api.EditConfig) endpoint.GET("backups", api.GetFileBackupList) diff --git a/server/template/http-conf b/server/template/http-conf index 52aaaca9..13c94f07 100644 --- a/server/template/http-conf +++ b/server/template/http-conf @@ -4,7 +4,9 @@ server { server_name {{ server_name }}; - root {{ root }} + {{ index }} + + {{ root }} # extra {{ extra }} diff --git a/server/template/https-conf b/server/template/https-conf index 78f923cd..7345bf62 100644 --- a/server/template/https-conf +++ b/server/template/https-conf @@ -8,12 +8,14 @@ server { } server { - listen {{ https_listen_port }}; - listen [::]:{{ https_listen_port }}; + listen {{ https_listen_port }} ssl http2; + listen [::]:{{ https_listen_port }} ssl http2; server_name {{ server_name }}; - root {{ root }} + {{ index }} + + {{ root }} # extra {{ extra }} diff --git a/server/test/nginx_test.go b/server/test/nginx_test.go new file mode 100644 index 00000000..dbeb1d75 --- /dev/null +++ b/server/test/nginx_test.go @@ -0,0 +1,20 @@ +package test + +import ( + "fmt" + "log" + "os/exec" + "regexp" + "testing" +) + +func TestGetNginx(t *testing.T) { + out, err := exec.Command("nginx", "-V").CombinedOutput() + if err != nil { + log.Fatal(err) + } + fmt.Printf("%s\n", out) + + r, _ := regexp.Compile("--conf-path=(.*)/(.*.conf)") + fmt.Println(r.FindStringSubmatch(string(out))[1]) +} diff --git a/server/tool/nginx.go b/server/tool/nginx.go index 8b570e6b..13c55d4b 100644 --- a/server/tool/nginx.go +++ b/server/tool/nginx.go @@ -5,6 +5,7 @@ import ( "log" "os/exec" "path/filepath" + "regexp" ) func ReloadNginx() { @@ -21,5 +22,17 @@ func ReloadNginx() { } func GetNginxConfPath(dir string) string { - return filepath.Join("/etc/nginx", dir) + out, err := exec.Command("nginx", "-V").CombinedOutput() + if err != nil { + log.Fatal(err) + } + // fmt.Printf("%s\n", out) + + r, _ := regexp.Compile("--conf-path=(.*)/(.*.conf)") + + confPath := r.FindStringSubmatch(string(out))[1] + + // fmt.Println(confPath) + + return filepath.Join(confPath, dir) }