+
Certificate Status
Intermediate Certification Authorities: %{issuer}
Subject Name: %{name}
@@ -57,6 +57,14 @@ export default {
diff --git a/frontend/src/views/domain/columns.js b/frontend/src/views/domain/columns.js
index c9d2931f..b5eb28d2 100644
--- a/frontend/src/views/domain/columns.js
+++ b/frontend/src/views/domain/columns.js
@@ -1,4 +1,4 @@
-import $gettext from "@/lib/translate/gettext";
+import $gettext from '@/lib/translate/gettext'
const columns = [{
title: $gettext('Configuration Name'),
@@ -12,6 +12,13 @@ const columns = [{
edit: {
type: 'input'
}
+}, {
+ title: $gettext('HTTP Listen Port'),
+ dataIndex: 'http_listen_port',
+ edit: {
+ type: 'number',
+ min: 80
+ }
}, {
title: $gettext('Root Directory (root)'),
dataIndex: 'root',
@@ -24,51 +31,46 @@ const columns = [{
edit: {
type: 'input'
}
-}, {
- title: $gettext('HTTP Listen Port'),
- dataIndex: 'http_listen_port',
- edit: {
- type: 'number',
- min: 80
- }
-}, {
- title: $gettext('Enable TLS'),
- dataIndex: 'support_ssl',
- edit: {
- type: 'switch',
- event: 'change_support_ssl'
- }
}]
-const columnsSSL = [{
- title: $gettext('Certificate Auto-renewal'),
- dataIndex: 'auto_cert',
- edit: {
- type: 'switch',
- event: 'change_auto_cert'
- },
- description: $gettext('The certificate for the domain will be checked every hour, ' +
- 'and will be renewed if it has been more than 1 month since it was last issued.' +
- '
If you do not have a certificate before, please click "Getting Certificate from Let\'s Encrypt" first.')
-}, {
- title: $gettext('HTTPS Listen Port'),
- dataIndex: 'https_listen_port',
- edit: {
- type: 'number',
- min: 443
+const columnsSSL = [
+ {
+ title: $gettext('Enable TLS'),
+ dataIndex: 'support_ssl',
+ edit: {
+ type: 'switch',
+ event: 'change_support_ssl'
+ }
+ }, {
+ title: $gettext('Certificate Auto-renewal'),
+ dataIndex: 'auto_cert',
+ edit: {
+ type: 'switch',
+ event: 'change_auto_cert'
+ },
+ description: $gettext('The certificate for the domain will be checked every hour, ' +
+ 'and will be renewed if it has been more than 1 month since it was last issued.' +
+ '
If you do not have a certificate before, please click "Getting Certificate from Let\'s Encrypt" first.')
+ }, {
+ title: $gettext('HTTPS Listen Port'),
+ dataIndex: 'https_listen_port',
+ edit: {
+ type: 'number',
+ min: 443
+ }
+ }, {
+ title: $gettext('Certificate Path (ssl_certificate)'),
+ dataIndex: 'ssl_certificate',
+ edit: {
+ type: 'input'
+ }
+ }, {
+ title: $gettext('Private Key Path (ssl_certificate_key)'),
+ dataIndex: 'ssl_certificate_key',
+ edit: {
+ type: 'input'
+ }
}
-}, {
- title: $gettext('Certificate Path (ssl_certificate)'),
- dataIndex: 'ssl_certificate',
- edit: {
- type: 'input'
- }
-}, {
- title: $gettext('Private Key Path (ssl_certificate_key)'),
- dataIndex: 'ssl_certificate_key',
- edit: {
- type: 'input'
- }
-}]
+]
export {columns, columnsSSL}
diff --git a/frontend/src/views/domain/methods.js b/frontend/src/views/domain/methods.js
index c91c6dae..21908ed1 100644
--- a/frontend/src/views/domain/methods.js
+++ b/frontend/src/views/domain/methods.js
@@ -1,36 +1,8 @@
import $gettext from '@/lib/translate/gettext'
import store from '@/lib/store'
import Vue from 'vue'
-const unparse = (text, config) => {
- // http_listen_port: /listen (.*);/i,
- // https_listen_port: /listen (.*) ssl/i,
- const reg = {
- server_name: /server_name[\s](.*);/ig,
- index: /index[\s](.*);/i,
- root: /root[\s](.*);/i,
- ssl_certificate: /ssl_certificate[\s](.*);/i,
- ssl_certificate_key: /ssl_certificate_key[\s](.*);/i
- }
- text = text.replace(/listen[\s](.*);/i, 'listen\t'
- + config['http_listen_port'] + ';')
- text = text.replace(/listen[\s](.*) ssl/i, 'listen\t'
- + config['https_listen_port'] + ' ssl')
-
- text = text.replace(/listen(.*):(.*);/i, 'listen\t[::]:'
- + config['http_listen_port'] + ';')
- text = text.replace(/listen(.*):(.*) ssl/i, 'listen\t[::]:'
- + config['https_listen_port'] + ' ssl')
-
- for (let k in reg) {
- text = text.replace(new RegExp(reg[k]), k + '\t' +
- (config[k] !== undefined ? config[k] : ' ') + ';')
- }
-
- return text
-}
const issue_cert = (server_name, callback) => {
- Vue.prototype.$message.info($gettext('Note: The server_name in the current configuration must be the domain name you need to get the certificate.'), 15)
Vue.prototype.$message.info($gettext('Getting the certificate, please wait...'), 15)
const ws = new WebSocket(Vue.prototype.getWebSocketRoot() + '/cert/issue/' + server_name
+ '?token=' + btoa(store.state.user.token))
@@ -57,6 +29,9 @@ const issue_cert = (server_name, callback) => {
callback(r.ssl_certificate, r.ssl_certificate_key)
}
}
+ // setTimeout(() => {
+ // callback('a', 'b')
+ // }, 10000)
}
-export {unparse, issue_cert}
+export {issue_cert}
diff --git a/frontend/src/views/domain/ngx_conf/LocationEditor.vue b/frontend/src/views/domain/ngx_conf/LocationEditor.vue
new file mode 100644
index 00000000..0319a140
--- /dev/null
+++ b/frontend/src/views/domain/ngx_conf/LocationEditor.vue
@@ -0,0 +1,78 @@
+
+
+
+
+
+ {{ v.comments }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ $gettext('Add Location') }}
+
+
+
+
+
+
+
diff --git a/frontend/src/views/domain/ngx_conf/NgxConfigEditor.vue b/frontend/src/views/domain/ngx_conf/NgxConfigEditor.vue
new file mode 100644
index 00000000..b9d10f6b
--- /dev/null
+++ b/frontend/src/views/domain/ngx_conf/NgxConfigEditor.vue
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ v.comments }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/views/domain/ngx_conf/directive/DirectiveAdd.vue b/frontend/src/views/domain/ngx_conf/directive/DirectiveAdd.vue
new file mode 100644
index 00000000..f460529e
--- /dev/null
+++ b/frontend/src/views/domain/ngx_conf/directive/DirectiveAdd.vue
@@ -0,0 +1,74 @@
+
+
+
+
+
+ {{ $gettext('Single Directive') }}
+
+
+ if
+
+
+
+
+
+
+
+
+
+
+
{{ $gettext('Add Directive Below') }}
+
{{ $gettext('Save Directive') }}
+
+
+
+
+
+
+
diff --git a/frontend/src/views/domain/ngx_conf/directive/DirectiveEditor.vue b/frontend/src/views/domain/ngx_conf/directive/DirectiveEditor.vue
new file mode 100644
index 00000000..4f583b3f
--- /dev/null
+++ b/frontend/src/views/domain/ngx_conf/directive/DirectiveEditor.vue
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/views/domain/ngx_conf/ngx_constant.js b/frontend/src/views/domain/ngx_conf/ngx_constant.js
new file mode 100644
index 00000000..794d3d22
--- /dev/null
+++ b/frontend/src/views/domain/ngx_conf/ngx_constant.js
@@ -0,0 +1 @@
+export const If = "if"
diff --git a/server/api/cert.go b/server/api/cert.go
index f37dfaa4..158c5776 100644
--- a/server/api/cert.go
+++ b/server/api/cert.go
@@ -1,164 +1,128 @@
package api
import (
- "encoding/json"
- "github.com/0xJacky/Nginx-UI/server/settings"
- "github.com/0xJacky/Nginx-UI/server/tool"
- "github.com/0xJacky/Nginx-UI/server/tool/nginx"
- "github.com/gin-gonic/gin"
- "github.com/gorilla/websocket"
- "log"
- "net/http"
- "os"
+ "github.com/0xJacky/Nginx-UI/server/tool"
+ "github.com/0xJacky/Nginx-UI/server/tool/nginx"
+ "github.com/gin-gonic/gin"
+ "github.com/gorilla/websocket"
+ "log"
+ "net/http"
+ "os"
)
func CertInfo(c *gin.Context) {
- domain := c.Param("domain")
+ domain := c.Param("domain")
- key, err := tool.GetCertInfo(domain)
+ key, err := tool.GetCertInfo(domain)
- c.JSON(http.StatusOK, gin.H{
- "error": err,
- "subject_name": key.Subject.CommonName,
- "issuer_name": key.Issuer.CommonName,
- "not_after": key.NotAfter,
- "not_before": key.NotBefore,
- })
+ c.JSON(http.StatusOK, gin.H{
+ "error": err,
+ "subject_name": key.Subject.CommonName,
+ "issuer_name": key.Issuer.CommonName,
+ "not_after": key.NotAfter,
+ "not_before": key.NotBefore,
+ })
}
func IssueCert(c *gin.Context) {
- domain := c.Param("domain")
- var upGrader = websocket.Upgrader{
- CheckOrigin: func(r *http.Request) bool {
- return true
- },
- }
+ domain := c.Param("domain")
+ var upGrader = websocket.Upgrader{
+ CheckOrigin: func(r *http.Request) bool {
+ return true
+ },
+ }
- // upgrade http to websocket
- ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
- if err != nil {
- log.Println(err)
- return
- }
+ // upgrade http to websocket
+ ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
+ if err != nil {
+ log.Println(err)
+ return
+ }
- defer func(ws *websocket.Conn) {
- err := ws.Close()
- if err != nil {
- log.Println("defer websocket close err", err)
- }
- }(ws)
+ defer func(ws *websocket.Conn) {
+ err := ws.Close()
+ if err != nil {
+ log.Println("defer websocket close err", err)
+ }
+ }(ws)
- for {
- // read
- mt, message, err := ws.ReadMessage()
- if err != nil {
- break
- }
- if string(message) == "go" {
- var m []byte
+ // read
+ mt, message, err := ws.ReadMessage()
+ if err != nil {
+ log.Println(err)
+ return
+ }
- if settings.ServerSettings.Demo {
- m, _ = json.Marshal(gin.H{
- "status": "error",
- "message": "this feature is not available in demo",
- })
- _ = ws.WriteMessage(mt, m)
- return
- }
+ if mt == websocket.TextMessage && string(message) == "go" {
- err = tool.IssueCert(domain)
+ err = tool.IssueCert(domain)
- if err != nil {
+ if err != nil {
- log.Println(err)
+ log.Println(err)
- m, err = json.Marshal(gin.H{
- "status": "error",
- "message": err.Error(),
- })
+ err = ws.WriteJSON(gin.H{
+ "status": "error",
+ "message": err.Error(),
+ })
- if err != nil {
- log.Println(err)
- return
- }
+ if err != nil {
+ log.Println(err)
+ return
+ }
- err = ws.WriteMessage(mt, m)
+ return
+ }
- if err != nil {
- log.Println(err)
- return
- }
+ sslCertificatePath := nginx.GetNginxConfPath("ssl/" + domain + "/fullchain.cer")
+ _, err = os.Stat(sslCertificatePath)
- return
- }
+ if err != nil {
+ log.Println(err)
+ return
+ }
- sslCertificatePath := nginx.GetNginxConfPath("ssl/" + domain + "/fullchain.cer")
- _, err = os.Stat(sslCertificatePath)
+ log.Println("[found]", "fullchain.cer")
- if err != nil {
- log.Println(err)
- return
- }
+ err = ws.WriteJSON(gin.H{
+ "status": "success",
+ "message": "[found] fullchain.cer",
+ })
- log.Println("[found]", "fullchain.cer")
- m, err = json.Marshal(gin.H{
- "status": "success",
- "message": "[found] fullchain.cer",
- })
+ if err != nil {
+ log.Println(err)
+ return
+ }
- if err != nil {
- log.Println(err)
- return
- }
+ sslCertificateKeyPath := nginx.GetNginxConfPath("ssl/" + domain + "/" + domain + ".key")
+ _, err = os.Stat(sslCertificateKeyPath)
- err = ws.WriteMessage(mt, m)
+ if err != nil {
+ log.Println(err)
+ return
+ }
- if err != nil {
- log.Println(err)
- return
- }
+ log.Println("[found]", "cert key")
+ err = ws.WriteJSON(gin.H{
+ "status": "success",
+ "message": "[found] Certificate Key",
+ })
- sslCertificateKeyPath := nginx.GetNginxConfPath("ssl/" + domain + "/" + domain + ".key")
- _, err = os.Stat(sslCertificateKeyPath)
+ if err != nil {
+ log.Println(err)
+ return
+ }
- if err != nil {
- log.Println(err)
- return
- }
+ err = ws.WriteJSON(gin.H{
+ "status": "success",
+ "message": "Issued certificate successfully",
+ "ssl_certificate": sslCertificatePath,
+ "ssl_certificate_key": sslCertificateKeyPath,
+ })
- log.Println("[found]", "cert key")
- m, err = json.Marshal(gin.H{
- "status": "success",
- "message": "[found] cert key",
- })
-
- if err != nil {
- log.Println(err)
- }
-
- err = ws.WriteMessage(mt, m)
-
- if err != nil {
- log.Println(err)
- }
-
- log.Println("申请成功")
- m, err = json.Marshal(gin.H{
- "status": "success",
- "message": "申请成功",
- "ssl_certificate": sslCertificatePath,
- "ssl_certificate_key": sslCertificateKeyPath,
- })
-
- if err != nil {
- log.Println(err)
- }
-
- err = ws.WriteMessage(mt, m)
-
- if err != nil {
- log.Println(err)
- }
- }
- }
+ if err != nil {
+ log.Println(err)
+ return
+ }
+ }
}
diff --git a/server/api/domain.go b/server/api/domain.go
index c335adfd..ffb65feb 100644
--- a/server/api/domain.go
+++ b/server/api/domain.go
@@ -1,267 +1,270 @@
package api
import (
- "github.com/0xJacky/Nginx-UI/server/model"
- "github.com/0xJacky/Nginx-UI/server/tool"
- "github.com/0xJacky/Nginx-UI/server/tool/nginx"
- "github.com/gin-gonic/gin"
- "io/ioutil"
- "net/http"
- "os"
- "path/filepath"
- "strings"
+ "github.com/0xJacky/Nginx-UI/server/model"
+ "github.com/0xJacky/Nginx-UI/server/tool"
+ "github.com/0xJacky/Nginx-UI/server/tool/nginx"
+ "github.com/gin-gonic/gin"
+ "io/ioutil"
+ "net/http"
+ "os"
+ "path/filepath"
+ "strings"
)
func GetDomains(c *gin.Context) {
- orderBy := c.Query("order_by")
- sort := c.DefaultQuery("sort", "desc")
+ orderBy := c.Query("order_by")
+ sort := c.DefaultQuery("sort", "desc")
- mySort := map[string]string{
- "enabled": "bool",
- "name": "string",
- "modify": "time",
- }
+ mySort := map[string]string{
+ "enabled": "bool",
+ "name": "string",
+ "modify": "time",
+ }
- configFiles, err := ioutil.ReadDir(nginx.GetNginxConfPath("sites-available"))
+ configFiles, err := ioutil.ReadDir(nginx.GetNginxConfPath("sites-available"))
- if err != nil {
- ErrHandler(c, err)
- return
- }
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
- enabledConfig, err := ioutil.ReadDir(filepath.Join(nginx.GetNginxConfPath("sites-enabled")))
+ enabledConfig, err := ioutil.ReadDir(filepath.Join(nginx.GetNginxConfPath("sites-enabled")))
- if err != nil {
- ErrHandler(c, err)
- return
- }
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
- enabledConfigMap := make(map[string]bool)
- for i := range enabledConfig {
- enabledConfigMap[enabledConfig[i].Name()] = true
- }
+ enabledConfigMap := make(map[string]bool)
+ for i := range enabledConfig {
+ enabledConfigMap[enabledConfig[i].Name()] = true
+ }
- var configs []gin.H
+ var configs []gin.H
- for i := range configFiles {
- file := configFiles[i]
- if !file.IsDir() {
- configs = append(configs, gin.H{
- "name": file.Name(),
- "size": file.Size(),
- "modify": file.ModTime(),
- "enabled": enabledConfigMap[file.Name()],
- })
- }
- }
+ for i := range configFiles {
+ file := configFiles[i]
+ if !file.IsDir() {
+ configs = append(configs, gin.H{
+ "name": file.Name(),
+ "size": file.Size(),
+ "modify": file.ModTime(),
+ "enabled": enabledConfigMap[file.Name()],
+ })
+ }
+ }
- configs = tool.Sort(orderBy, sort, mySort[orderBy], configs)
+ configs = tool.Sort(orderBy, sort, mySort[orderBy], configs)
- c.JSON(http.StatusOK, gin.H{
- "configs": configs,
- })
+ c.JSON(http.StatusOK, gin.H{
+ "configs": configs,
+ })
}
func GetDomain(c *gin.Context) {
- name := c.Param("name")
- path := filepath.Join(nginx.GetNginxConfPath("sites-available"), name)
+ name := c.Param("name")
+ path := filepath.Join(nginx.GetNginxConfPath("sites-available"), name)
- enabled := true
- if _, err := os.Stat(filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)); os.IsNotExist(err) {
- enabled = false
- }
+ enabled := true
+ if _, err := os.Stat(filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)); os.IsNotExist(err) {
+ enabled = false
+ }
- config, err := nginx.ParseNgxConfig(path)
+ config, err := nginx.ParseNgxConfig(path)
- if err != nil {
- ErrHandler(c, err)
- return
- }
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
- _, err = model.FirstCert(name)
+ _, err = model.FirstCert(name)
- c.JSON(http.StatusOK, gin.H{
- "enabled": enabled,
- "name": name,
- "config": config.BuildConfig(),
- "tokenized": config,
- })
+ c.JSON(http.StatusOK, gin.H{
+ "enabled": enabled,
+ "name": name,
+ "config": config.BuildConfig(),
+ "tokenized": config,
+ "auto_cert": err == nil,
+ })
}
func EditDomain(c *gin.Context) {
- var err error
- name := c.Param("name")
- request := make(gin.H)
- err = c.BindJSON(&request)
- path := filepath.Join(nginx.GetNginxConfPath("sites-available"), name)
+ var err error
+ name := c.Param("name")
+ request := make(gin.H)
+ err = c.BindJSON(&request)
+ path := filepath.Join(nginx.GetNginxConfPath("sites-available"), name)
- err = ioutil.WriteFile(path, []byte(request["content"].(string)), 0644)
- if err != nil {
- ErrHandler(c, err)
- return
- }
+ err = ioutil.WriteFile(path, []byte(request["content"].(string)), 0644)
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
- enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)
- if _, err = os.Stat(enabledConfigFilePath); err == nil {
- // 测试配置文件
- err = nginx.TestNginxConf()
- if err != nil {
- c.JSON(http.StatusInternalServerError, gin.H{
- "message": err.Error(),
- })
- return
- }
+ enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)
+ if _, err = os.Stat(enabledConfigFilePath); err == nil {
+ // Test nginx configuration
+ err = nginx.TestNginxConf()
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{
+ "message": err.Error(),
+ })
+ return
+ }
- output := nginx.ReloadNginx()
+ output := nginx.ReloadNginx()
- if output != "" && strings.Contains(output, "error") {
- c.JSON(http.StatusInternalServerError, gin.H{
- "message": output,
- })
- return
- }
- }
+ if output != "" && strings.Contains(output, "error") {
+ c.JSON(http.StatusInternalServerError, gin.H{
+ "message": output,
+ })
+ return
+ }
+ }
- GetDomain(c)
+ GetDomain(c)
}
func EnableDomain(c *gin.Context) {
- configFilePath := filepath.Join(nginx.GetNginxConfPath("sites-available"), c.Param("name"))
- enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), c.Param("name"))
+ configFilePath := filepath.Join(nginx.GetNginxConfPath("sites-available"), c.Param("name"))
+ enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), c.Param("name"))
- _, err := os.Stat(configFilePath)
+ _, err := os.Stat(configFilePath)
- if err != nil {
- ErrHandler(c, err)
- return
- }
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
- err = os.Symlink(configFilePath, enabledConfigFilePath)
+ if _, err = os.Stat(enabledConfigFilePath); os.IsNotExist(err) {
+ err = os.Symlink(configFilePath, enabledConfigFilePath)
- if err != nil {
- ErrHandler(c, err)
- return
- }
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
+ }
- // Test nginx config, if not pass then rollback.
- err = nginx.TestNginxConf()
- if err != nil {
- _ = os.Remove(enabledConfigFilePath)
- c.JSON(http.StatusInternalServerError, gin.H{
- "message": err.Error(),
- })
- return
- }
+ // Test nginx config, if not pass then rollback.
+ err = nginx.TestNginxConf()
+ if err != nil {
+ _ = os.Remove(enabledConfigFilePath)
+ c.JSON(http.StatusInternalServerError, gin.H{
+ "message": err.Error(),
+ })
+ return
+ }
- output := nginx.ReloadNginx()
+ output := nginx.ReloadNginx()
- if output != "" && strings.Contains(output, "error") {
- c.JSON(http.StatusInternalServerError, gin.H{
- "message": output,
- })
- return
- }
+ if output != "" && strings.Contains(output, "error") {
+ c.JSON(http.StatusInternalServerError, gin.H{
+ "message": output,
+ })
+ return
+ }
- c.JSON(http.StatusOK, gin.H{
- "message": "ok",
- })
+ c.JSON(http.StatusOK, gin.H{
+ "message": "ok",
+ })
}
func DisableDomain(c *gin.Context) {
- enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), c.Param("name"))
+ enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), c.Param("name"))
- _, err := os.Stat(enabledConfigFilePath)
+ _, err := os.Stat(enabledConfigFilePath)
- if err != nil {
- ErrHandler(c, err)
- return
- }
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
- err = os.Remove(enabledConfigFilePath)
+ err = os.Remove(enabledConfigFilePath)
- if err != nil {
- ErrHandler(c, err)
- return
- }
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
- // delete auto cert record
- cert := model.Cert{Domain: c.Param("name")}
- err = cert.Remove()
- if err != nil {
- ErrHandler(c, err)
- return
- }
+ // delete auto cert record
+ cert := model.Cert{Domain: c.Param("name")}
+ err = cert.Remove()
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
- output := nginx.ReloadNginx()
+ output := nginx.ReloadNginx()
- if output != "" {
- c.JSON(http.StatusInternalServerError, gin.H{
- "message": output,
- })
- return
- }
+ if output != "" {
+ c.JSON(http.StatusInternalServerError, gin.H{
+ "message": output,
+ })
+ return
+ }
- c.JSON(http.StatusOK, gin.H{
- "message": "ok",
- })
+ c.JSON(http.StatusOK, gin.H{
+ "message": "ok",
+ })
}
func DeleteDomain(c *gin.Context) {
- var err error
- name := c.Param("name")
- availablePath := filepath.Join(nginx.GetNginxConfPath("sites-available"), name)
- enabledPath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)
+ var err error
+ name := c.Param("name")
+ availablePath := filepath.Join(nginx.GetNginxConfPath("sites-available"), name)
+ enabledPath := filepath.Join(nginx.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(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
- }
+ if _, err = os.Stat(enabledPath); err == nil {
+ c.JSON(http.StatusNotAcceptable, gin.H{
+ "message": "site is enabled",
+ })
+ return
+ }
- cert := model.Cert{Domain: name}
- _ = cert.Remove()
+ cert := model.Cert{Domain: name}
+ _ = cert.Remove()
- err = os.Remove(availablePath)
+ err = os.Remove(availablePath)
- if err != nil {
- ErrHandler(c, err)
- return
- }
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
- c.JSON(http.StatusOK, gin.H{
- "message": "ok",
- })
+ c.JSON(http.StatusOK, gin.H{
+ "message": "ok",
+ })
}
func AddDomainToAutoCert(c *gin.Context) {
- domain := c.Param("domain")
- cert, err := model.FirstOrCreateCert(domain)
- if err != nil {
- ErrHandler(c, err)
- return
- }
- c.JSON(http.StatusOK, cert)
+ domain := c.Param("domain")
+ cert, err := model.FirstOrCreateCert(domain)
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
+ c.JSON(http.StatusOK, cert)
}
func RemoveDomainFromAutoCert(c *gin.Context) {
- cert := model.Cert{
- Domain: c.Param("domain"),
- }
- err := cert.Remove()
+ cert := model.Cert{
+ Domain: c.Param("domain"),
+ }
+ err := cert.Remove()
- if err != nil {
- ErrHandler(c, err)
- return
- }
- c.JSON(http.StatusOK, nil)
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
+ c.JSON(http.StatusOK, nil)
}
diff --git a/server/api/ngx.go b/server/api/ngx.go
new file mode 100644
index 00000000..bbfd32eb
--- /dev/null
+++ b/server/api/ngx.go
@@ -0,0 +1,42 @@
+package api
+
+import (
+ "bufio"
+ "github.com/0xJacky/Nginx-UI/server/tool/nginx"
+ "github.com/gin-gonic/gin"
+ "net/http"
+ "strings"
+)
+
+func BuildNginxConfig(c *gin.Context) {
+ var ngxConf nginx.NgxConfig
+ if !BindAndValid(c, &ngxConf) {
+ return
+ }
+
+ c.JSON(http.StatusOK, gin.H{
+ "content": ngxConf.BuildConfig(),
+ })
+}
+
+func TokenizeNginxConfig(c *gin.Context) {
+ var json struct {
+ Content string `json:"content" binding:"required"`
+ }
+
+ if !BindAndValid(c, &json) {
+ return
+ }
+
+ scanner := bufio.NewScanner(strings.NewReader(json.Content))
+
+ ngxConfig, err := nginx.ParseNgxConfigByScanner("", scanner)
+
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
+
+ c.JSON(http.StatusOK, ngxConfig)
+
+}
diff --git a/server/api/template.go b/server/api/template.go
index 67990492..4dab63d0 100644
--- a/server/api/template.go
+++ b/server/api/template.go
@@ -2,34 +2,58 @@ package api
import (
"github.com/0xJacky/Nginx-UI/server/settings"
- "github.com/0xJacky/Nginx-UI/server/template"
+ "github.com/0xJacky/Nginx-UI/server/tool/nginx"
"github.com/gin-gonic/gin"
"net/http"
- "os"
"strings"
)
func GetTemplate(c *gin.Context) {
- name := c.Param("name")
- content, err := template.DistFS.ReadFile(name)
-
- _content := string(content)
- _content = strings.ReplaceAll(_content, "{{ HTTP01PORT }}",
+ content := `proxy_set_header Host $host;
+proxy_set_header X-Real_IP $remote_addr;
+proxy_set_header X-Forwarded-For $remote_addr:$remote_port;
+proxy_pass http://127.0.0.1:{{ HTTP01PORT }};
+`
+ content = strings.ReplaceAll(content, "{{ HTTP01PORT }}",
settings.ServerSettings.HTTPChallengePort)
- if err != nil {
- if os.IsNotExist(err) {
- c.JSON(http.StatusNotFound, gin.H{
- "message": err.Error(),
- })
- return
- }
- ErrHandler(c, err)
- return
+ var ngxConfig *nginx.NgxConfig
+
+ ngxConfig = &nginx.NgxConfig{
+ Servers: []*nginx.NgxServer{
+ {
+ Directives: []*nginx.NgxDirective{
+ {
+ Directive: "listen",
+ Params: "80",
+ },
+ {
+ Directive: "listen",
+ Params: "[::]:80",
+ },
+ {
+ Directive: "server_name",
+ },
+ {
+ Directive: "root",
+ },
+ {
+ Directive: "index",
+ },
+ },
+ Locations: []*nginx.NgxLocation{
+ {
+ Path: "/.well-known/acme-challenge",
+ Content: content,
+ },
+ },
+ },
+ },
}
c.JSON(http.StatusOK, gin.H{
- "message": "ok",
- "template": _content,
+ "message": "ok",
+ "template": ngxConfig.BuildConfig(),
+ "tokenized": ngxConfig,
})
}
diff --git a/server/router/middleware.go b/server/router/middleware.go
index 2bb175b8..d09d8eea 100644
--- a/server/router/middleware.go
+++ b/server/router/middleware.go
@@ -34,7 +34,7 @@ func authRequired() gin.HandlerFunc {
token = string(tmp)
if token == "" {
c.JSON(http.StatusForbidden, gin.H{
- "message": "auth fail",
+ "message": "Authorization failed",
})
c.Abort()
return
@@ -45,7 +45,7 @@ func authRequired() gin.HandlerFunc {
if n < 1 {
c.JSON(http.StatusForbidden, gin.H{
- "message": "auth fail",
+ "message": "Authorization failed",
})
c.Abort()
return
diff --git a/server/router/routers.go b/server/router/routers.go
index cd870c5d..feeebcfc 100644
--- a/server/router/routers.go
+++ b/server/router/routers.go
@@ -1,92 +1,100 @@
package router
import (
- "bufio"
- "github.com/0xJacky/Nginx-UI/server/api"
- "github.com/0xJacky/Nginx-UI/server/settings"
- "github.com/gin-contrib/static"
- "github.com/gin-gonic/gin"
- "net/http"
- "strings"
+ "bufio"
+ "github.com/0xJacky/Nginx-UI/server/api"
+ "github.com/0xJacky/Nginx-UI/server/settings"
+ "github.com/gin-contrib/static"
+ "github.com/gin-gonic/gin"
+ "net/http"
+ "strings"
)
func InitRouter() *gin.Engine {
- r := gin.New()
- r.Use(gin.Logger())
+ r := gin.New()
+ r.Use(gin.Logger())
- r.Use(recovery())
+ r.Use(recovery())
- r.Use(cacheJs())
+ r.Use(cacheJs())
- r.Use(static.Serve("/", mustFS("")))
+ r.Use(static.Serve("/", mustFS("")))
- r.NoRoute(func(c *gin.Context) {
- accept := c.Request.Header.Get("Accept")
- if strings.Contains(accept, "text/html") {
- file, _ := mustFS("").Open("index.html")
- defer file.Close()
- stat, _ := file.Stat()
- c.DataFromReader(http.StatusOK, stat.Size(), "text/html",
- bufio.NewReader(file), nil)
- return
- }
- })
+ r.NoRoute(func(c *gin.Context) {
+ accept := c.Request.Header.Get("Accept")
+ if strings.Contains(accept, "text/html") {
+ file, _ := mustFS("").Open("index.html")
+ defer file.Close()
+ stat, _ := file.Stat()
+ c.DataFromReader(http.StatusOK, stat.Size(), "text/html",
+ bufio.NewReader(file), nil)
+ return
+ }
+ })
- g := r.Group("/api")
- {
+ g := r.Group("/api")
+ {
- g.GET("settings", func(c *gin.Context) {
- c.JSON(http.StatusOK, gin.H{
- "demo": settings.ServerSettings.Demo,
- })
- })
+ g.GET("settings", func(c *gin.Context) {
+ c.JSON(http.StatusOK, gin.H{
+ "demo": settings.ServerSettings.Demo,
+ })
+ })
- g.GET("install", api.InstallLockCheck)
- g.POST("install", api.InstallNginxUI)
+ g.GET("install", api.InstallLockCheck)
+ g.POST("install", api.InstallNginxUI)
- g.POST("/login", api.Login)
- g.DELETE("/logout", api.Logout)
+ g.POST("/login", api.Login)
+ g.DELETE("/logout", api.Logout)
- g := g.Group("/", authRequired())
- {
- g.GET("/analytic", api.Analytic)
- g.GET("/analytic/init", api.GetAnalyticInit)
+ g := g.Group("/", authRequired())
+ {
+ g.GET("analytic", api.Analytic)
+ g.GET("analytic/init", api.GetAnalyticInit)
- g.GET("/users", api.GetUsers)
- g.GET("/user/:id", api.GetUser)
- g.POST("/user", api.AddUser)
- g.POST("/user/:id", api.EditUser)
- g.DELETE("/user/:id", api.DeleteUser)
+ g.GET("users", api.GetUsers)
+ g.GET("user/:id", api.GetUser)
+ g.POST("user", api.AddUser)
+ g.POST("user/:id", api.EditUser)
+ g.DELETE("user/:id", api.DeleteUser)
- g.GET("domains", api.GetDomains)
- g.GET("domain/:name", api.GetDomain)
- g.POST("domain/:name", api.EditDomain)
- g.POST("domain/:name/enable", api.EnableDomain)
- g.POST("domain/:name/disable", api.DisableDomain)
- g.DELETE("domain/:name", api.DeleteDomain)
+ g.GET("domains", api.GetDomains)
+ g.GET("domain/:name", api.GetDomain)
- g.GET("configs", api.GetConfigs)
- g.GET("config/:name", api.GetConfig)
- g.POST("config", api.AddConfig)
- g.POST("config/:name", api.EditConfig)
+ // Modify site configuration directly
+ g.POST("domain/:name", api.EditDomain)
- g.GET("backups", api.GetFileBackupList)
- g.GET("backup/:id", api.GetFileBackup)
+ // Transform NgxConf to nginx configuration
+ g.POST("ngx/build_config", api.BuildNginxConfig)
+ // Tokenized nginx configuration to NgxConf
+ g.POST("ngx/tokenize_config", api.TokenizeNginxConfig)
- g.GET("template/:name", api.GetTemplate)
+ g.POST("domain/:name/enable", api.EnableDomain)
+ g.POST("domain/:name/disable", api.DisableDomain)
+ g.DELETE("domain/:name", api.DeleteDomain)
- g.GET("cert/issue/:domain", api.IssueCert)
- g.GET("cert/:domain/info", api.CertInfo)
+ g.GET("configs", api.GetConfigs)
+ g.GET("config/:name", api.GetConfig)
+ g.POST("config", api.AddConfig)
+ g.POST("config/:name", api.EditConfig)
- // 添加域名到自动续期列表
- g.POST("cert/:domain", api.AddDomainToAutoCert)
- // 从自动续期列表中删除域名
- g.DELETE("cert/:domain", api.RemoveDomainFromAutoCert)
+ //g.GET("backups", api.GetFileBackupList)
+ //g.GET("backup/:id", api.GetFileBackup)
- // pty
- g.GET("pty", api.Pty)
- }
- }
+ g.GET("template", api.GetTemplate)
- return r
+ g.GET("cert/issue/:domain", api.IssueCert)
+ g.GET("cert/:domain/info", api.CertInfo)
+
+ // Add domain to auto-renew cert list
+ g.POST("cert/:domain", api.AddDomainToAutoCert)
+ // Delete domain from auto-renew cert list
+ g.DELETE("cert/:domain", api.RemoveDomainFromAutoCert)
+
+ // pty
+ g.GET("pty", api.Pty)
+ }
+ }
+
+ return r
}
diff --git a/server/template/http-conf b/server/template/http-conf
deleted file mode 100644
index 7c633463..00000000
--- a/server/template/http-conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
- listen {{ http_listen_port }};
- listen [::]:{{ http_listen_port }};
-
- server_name {{ server_name }};
-
- location /.well-known {
- proxy_set_header Host $host;
- proxy_set_header X-Real_IP $remote_addr;
- proxy_set_header X-Forwarded-For $remote_addr:$remote_port;
- proxy_pass http://127.0.0.1:{{ HTTP01PORT }};
- }
-}
diff --git a/server/template/https-conf b/server/template/https-conf
deleted file mode 100644
index b04d92f4..00000000
--- a/server/template/https-conf
+++ /dev/null
@@ -1,25 +0,0 @@
-server {
- listen {{ http_listen_port }};
- listen [::]:{{ http_listen_port }};
-
- server_name {{ server_name }};
-
- rewrite ^(.*)$ https://$host$1 permanent;
-}
-
-server {
- listen {{ https_listen_port }} ssl http2;
- listen [::]:{{ https_listen_port }} ssl http2;
-
- server_name {{ server_name }};
-
- ssl_certificate {{ ssl_certificate }};
- ssl_certificate_key {{ ssl_certificate_key }};
-
- location /.well-known {
- proxy_set_header Host $host;
- proxy_set_header X-Real_IP $remote_addr;
- proxy_set_header X-Forwarded-For $remote_addr:$remote_port;
- proxy_pass http://127.0.0.1:{{ HTTP01PORT }};
- }
-}
diff --git a/server/template/template.go b/server/template/template.go
deleted file mode 100644
index e22bb476..00000000
--- a/server/template/template.go
+++ /dev/null
@@ -1,6 +0,0 @@
-package template
-
-import "embed"
-
-//go:embed http-conf https-conf
-var DistFS embed.FS
diff --git a/server/tool/cert.go b/server/tool/cert.go
index 7d7994ab..3a65232a 100644
--- a/server/tool/cert.go
+++ b/server/tool/cert.go
@@ -1,185 +1,189 @@
package tool
import (
- "crypto"
- "crypto/ecdsa"
- "crypto/elliptic"
- "crypto/rand"
- "crypto/tls"
- "crypto/x509"
- "github.com/0xJacky/Nginx-UI/server/model"
- "github.com/0xJacky/Nginx-UI/server/settings"
- "github.com/0xJacky/Nginx-UI/server/tool/nginx"
- "github.com/go-acme/lego/v4/certcrypto"
- "github.com/go-acme/lego/v4/certificate"
- "github.com/go-acme/lego/v4/challenge/http01"
- "github.com/go-acme/lego/v4/lego"
- "github.com/go-acme/lego/v4/registration"
- "github.com/pkg/errors"
- "io"
- "io/ioutil"
- "log"
- "net"
- "net/http"
- "os"
- "path/filepath"
- "time"
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/tls"
+ "crypto/x509"
+ "github.com/0xJacky/Nginx-UI/server/model"
+ "github.com/0xJacky/Nginx-UI/server/settings"
+ "github.com/0xJacky/Nginx-UI/server/tool/nginx"
+ "github.com/go-acme/lego/v4/certcrypto"
+ "github.com/go-acme/lego/v4/certificate"
+ "github.com/go-acme/lego/v4/challenge/http01"
+ "github.com/go-acme/lego/v4/lego"
+ "github.com/go-acme/lego/v4/registration"
+ "github.com/pkg/errors"
+ "io"
+ "io/ioutil"
+ "log"
+ "net"
+ "net/http"
+ "os"
+ "path/filepath"
+ "time"
)
// MyUser You'll need a user or account type that implements acme.User
type MyUser struct {
- Email string
- Registration *registration.Resource
- key crypto.PrivateKey
+ Email string
+ Registration *registration.Resource
+ key crypto.PrivateKey
}
func (u *MyUser) GetEmail() string {
- return u.Email
+ return u.Email
}
func (u MyUser) GetRegistration() *registration.Resource {
- return u.Registration
+ return u.Registration
}
func (u *MyUser) GetPrivateKey() crypto.PrivateKey {
- return u.key
+ return u.key
}
func AutoCert() {
- defer func() {
- if err := recover(); err != nil {
- log.Println("[AutoCert] Recover", err)
- }
- }()
- log.Println("[AutoCert] Start")
- autoCertList := model.GetAutoCertList()
- for i := range autoCertList {
- domain := autoCertList[i].Domain
- key, err := GetCertInfo(domain)
- if err != nil {
- log.Println("GetCertInfo Err", err)
- // 获取证书信息失败,本次跳过
- continue
- }
- // 未到一个月
- if time.Now().Before(key.NotBefore.AddDate(0, 1, 0)) {
- continue
- }
- // 过一个月了,重新申请证书
- err = IssueCert(domain)
- if err != nil {
- log.Println(err)
- }
- }
+ defer func() {
+ if err := recover(); err != nil {
+ log.Println("[AutoCert] Recover", err)
+ }
+ }()
+ log.Println("[AutoCert] Start")
+ autoCertList := model.GetAutoCertList()
+ for i := range autoCertList {
+ domain := autoCertList[i].Domain
+ key, err := GetCertInfo(domain)
+ if err != nil {
+ log.Println("GetCertInfo Err", err)
+ // 获取证书信息失败,本次跳过
+ continue
+ }
+ // 未到一个月
+ if time.Now().Before(key.NotBefore.AddDate(0, 1, 0)) {
+ continue
+ }
+ // 过一个月了,重新申请证书
+ err = IssueCert(domain)
+ if err != nil {
+ log.Println(err)
+ }
+ }
}
func GetCertInfo(domain string) (key *x509.Certificate, err error) {
- var response *http.Response
+ var response *http.Response
- client := &http.Client{
- Transport: &http.Transport{
- DialContext: (&net.Dialer{
- Timeout: 5 * time.Second,
- }).DialContext,
- DisableKeepAlives: true,
- TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
- },
- Timeout: 5 * time.Second,
- }
+ client := &http.Client{
+ Transport: &http.Transport{
+ DialContext: (&net.Dialer{
+ Timeout: 5 * time.Second,
+ }).DialContext,
+ DisableKeepAlives: true,
+ TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+ },
+ Timeout: 5 * time.Second,
+ }
- response, err = client.Get("https://" + domain)
+ response, err = client.Get("https://" + domain)
- if err != nil {
- err = errors.Wrap(err, "get cert info error")
- return
- }
+ if err != nil {
+ err = errors.Wrap(err, "get cert info error")
+ return
+ }
- defer func(Body io.ReadCloser) {
- err = Body.Close()
- if err != nil {
- log.Println(err)
- return
- }
- }(response.Body)
+ defer func(Body io.ReadCloser) {
+ err = Body.Close()
+ if err != nil {
+ log.Println(err)
+ return
+ }
+ }(response.Body)
- key = response.TLS.PeerCertificates[0]
+ key = response.TLS.PeerCertificates[0]
- return
+ return
}
func IssueCert(domain string) error {
- // Create a user. New accounts need an email and private key to start.
- privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
- if err != nil {
- return errors.Wrap(err, "issue cert generate key error")
- }
+ // Create a user. New accounts need an email and private key to start.
+ privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ return errors.Wrap(err, "issue cert generate key error")
+ }
- myUser := MyUser{
- Email: settings.ServerSettings.Email,
- key: privateKey,
- }
+ myUser := MyUser{
+ Email: settings.ServerSettings.Email,
+ key: privateKey,
+ }
- config := lego.NewConfig(&myUser)
+ config := lego.NewConfig(&myUser)
- if settings.ServerSettings.Demo {
- config.CADirURL = "https://acme-staging-v02.api.letsencrypt.org/directory"
- }
- config.Certificate.KeyType = certcrypto.RSA2048
+ if settings.ServerSettings.Demo {
+ config.CADirURL = "https://acme-staging-v02.api.letsencrypt.org/directory"
+ }
- // A client facilitates communication with the CA server.
- client, err := lego.NewClient(config)
- if err != nil {
- return errors.Wrap(err, "issue cert new client error")
- }
+ config.Certificate.KeyType = certcrypto.RSA2048
- err = client.Challenge.SetHTTP01Provider(
- http01.NewProviderServer("",
- settings.ServerSettings.HTTPChallengePort,
- ),
- )
- if err != nil {
- return errors.Wrap(err, "issue cert challenge fail")
- }
+ // A client facilitates communication with the CA server.
+ client, err := lego.NewClient(config)
+ if err != nil {
+ return errors.Wrap(err, "issue cert new client error")
+ }
- // New users will need to register
- reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
- if err != nil {
- log.Println(err)
- return errors.Wrap(err, "issue cert register fail")
- }
- myUser.Registration = reg
+ err = client.Challenge.SetHTTP01Provider(
+ http01.NewProviderServer("",
+ settings.ServerSettings.HTTPChallengePort,
+ ),
+ )
+ if err != nil {
+ return errors.Wrap(err, "issue cert challenge fail")
+ }
- request := certificate.ObtainRequest{
- Domains: []string{domain},
- Bundle: true,
- }
- certificates, err := client.Certificate.Obtain(request)
- if err != nil {
- return errors.Wrap(err, "issue cert fail to obtain")
- }
- saveDir := nginx.GetNginxConfPath("ssl/" + domain)
- if _, err := os.Stat(saveDir); os.IsNotExist(err) {
- err = os.Mkdir(saveDir, 0755)
- if err != nil {
- return errors.Wrap(err, "issue cert fail to create")
- }
- }
+ // New users will need to register
+ reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
+ if err != nil {
+ log.Println(err)
+ return errors.Wrap(err, "issue cert register fail")
+ }
+ myUser.Registration = reg
- // Each certificate comes back with the cert bytes, the bytes of the client's
- // private key, and a certificate URL. SAVE THESE TO DISK.
- err = ioutil.WriteFile(filepath.Join(saveDir, "fullchain.cer"),
- certificates.Certificate, 0644)
- if err != nil {
- log.Println(err)
- return errors.Wrap(err, "issue cert write fullchain.cer fail")
- }
- err = ioutil.WriteFile(filepath.Join(saveDir, domain+".key"),
- certificates.PrivateKey, 0644)
- if err != nil {
- log.Println(err)
- return errors.Wrap(err, "issue cert write key fail")
- }
+ request := certificate.ObtainRequest{
+ Domains: []string{domain},
+ Bundle: true,
+ }
+ certificates, err := client.Certificate.Obtain(request)
+ if err != nil {
+ return errors.Wrap(err, "issue cert fail to obtain")
+ }
+ saveDir := nginx.GetNginxConfPath("ssl/" + domain)
+ if _, err = os.Stat(saveDir); os.IsNotExist(err) {
+ err = os.Mkdir(saveDir, 0755)
+ if err != nil {
+ return errors.Wrap(err, "issue cert fail to create")
+ }
+ }
- nginx.ReloadNginx()
+ // Each certificate comes back with the cert bytes, the bytes of the client's
+ // private key, and a certificate URL. SAVE THESE TO DISK.
+ err = ioutil.WriteFile(filepath.Join(saveDir, "fullchain.cer"),
+ certificates.Certificate, 0644)
- return nil
+ if err != nil {
+ log.Println(err)
+ return errors.Wrap(err, "issue cert write fullchain.cer fail")
+ }
+
+ err = ioutil.WriteFile(filepath.Join(saveDir, domain+".key"),
+ certificates.PrivateKey, 0644)
+
+ if err != nil {
+ log.Println(err)
+ return errors.Wrap(err, "issue cert write key fail")
+ }
+
+ nginx.ReloadNginx()
+
+ return nil
}
diff --git a/server/tool/nginx/build_config.go b/server/tool/nginx/build_config.go
index d438dde5..1aae1c5b 100644
--- a/server/tool/nginx/build_config.go
+++ b/server/tool/nginx/build_config.go
@@ -50,7 +50,7 @@ func (c *NgxConfig) BuildConfig() (content string) {
}
if directive.Directive == If {
server += fmt.Sprintf("%s%s\n", comments, fmtCodeWithIndent(directive.Params, 1))
- } else {
+ } else if directive.Params != "" {
server += fmt.Sprintf("%s\t%s;\n", comments, directive.Orig())
}
}
diff --git a/server/tool/nginx/parse.go b/server/tool/nginx/parse.go
index bfb45d9a..a8e49070 100644
--- a/server/tool/nginx/parse.go
+++ b/server/tool/nginx/parse.go
@@ -105,15 +105,9 @@ func parseDirective(scanner *bufio.Scanner) (d NgxDirective) {
return
}
-func ParseNgxConfig(filename string) (c *NgxConfig, err error) {
- file, err := os.Open(filename)
- if err != nil {
- return nil, errors.Wrap(err, "error open file in ParseNgxConfig")
- }
- defer file.Close()
-
- scanner := bufio.NewScanner(file)
+func ParseNgxConfigByScanner(filename string, scanner *bufio.Scanner) (c *NgxConfig, err error) {
c = NewNgxConfig(filename)
+
for scanner.Scan() {
d := parseDirective(scanner)
paramsScanner := bufio.NewScanner(strings.NewReader(d.Params))
@@ -142,3 +136,15 @@ func ParseNgxConfig(filename string) (c *NgxConfig, err error) {
return c, nil
}
+
+func ParseNgxConfig(filename string) (c *NgxConfig, err error) {
+ file, err := os.Open(filename)
+ if err != nil {
+ return nil, errors.Wrap(err, "error open file in ParseNgxConfig")
+ }
+ defer file.Close()
+
+ scanner := bufio.NewScanner(file)
+
+ return ParseNgxConfigByScanner(filename, scanner)
+}
diff --git a/server/tool/nginx/type.go b/server/tool/nginx/type.go
index 693e99c9..f547a52b 100644
--- a/server/tool/nginx/type.go
+++ b/server/tool/nginx/type.go
@@ -36,8 +36,6 @@ type NgxDirective struct {
Comments string `json:"comments"`
}
-type NgxDirectives map[string][]NgxDirective
-
type NgxLocation struct {
Path string `json:"path"`
Content string `json:"content"`