Parcourir la source

enhance: add settings for skip tls cert check

Jacky il y a 9 mois
Parent
commit
f1c0f8ddca

+ 119 - 119
api/openai/openai.go

@@ -1,18 +1,18 @@
 package openai
 
 import (
-	"context"
-	"crypto/tls"
-	"fmt"
-	"github.com/0xJacky/Nginx-UI/api"
-	"github.com/0xJacky/Nginx-UI/internal/chatbot"
-	"github.com/0xJacky/Nginx-UI/settings"
-	"github.com/gin-gonic/gin"
-	"github.com/pkg/errors"
-	"github.com/sashabaranov/go-openai"
-	"io"
-	"net/http"
-	"net/url"
+    "context"
+    "crypto/tls"
+    "fmt"
+    "github.com/0xJacky/Nginx-UI/api"
+    "github.com/0xJacky/Nginx-UI/internal/chatbot"
+    "github.com/0xJacky/Nginx-UI/settings"
+    "github.com/gin-gonic/gin"
+    "github.com/pkg/errors"
+    "github.com/sashabaranov/go-openai"
+    "io"
+    "net/http"
+    "net/url"
 )
 
 const ChatGPTInitPrompt = `You are a assistant who can help users write and optimise the configurations of Nginx,
@@ -22,111 +22,111 @@ Later the language environment depends on the user message.
 The first reply should involve the key information of the file and ask user what can you help them.`
 
 func MakeChatCompletionRequest(c *gin.Context) {
-	var json struct {
-		Filepath string                         `json:"filepath"`
-		Messages []openai.ChatCompletionMessage `json:"messages"`
-	}
-
-	if !api.BindAndValid(c, &json) {
-		return
-	}
-
-	messages := []openai.ChatCompletionMessage{
-		{
-			Role:    openai.ChatMessageRoleSystem,
-			Content: ChatGPTInitPrompt,
-		},
-	}
-
-	messages = append(messages, json.Messages...)
-
-	if json.Filepath != "" {
-		messages = chatbot.ChatCompletionWithContext(json.Filepath, messages)
-	}
-
-	// SSE server
-	c.Writer.Header().Set("Content-Type", "text/event-stream; charset=utf-8")
-	c.Writer.Header().Set("Cache-Control", "no-cache")
-	c.Writer.Header().Set("Connection", "keep-alive")
-	c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
-
-	config := openai.DefaultConfig(settings.OpenAISettings.Token)
-
-	if settings.OpenAISettings.Proxy != "" {
-		proxyUrl, err := url.Parse(settings.OpenAISettings.Proxy)
-		if err != nil {
-			c.Stream(func(w io.Writer) bool {
-				c.SSEvent("message", gin.H{
-					"type":    "error",
-					"content": err.Error(),
-				})
-				return false
-			})
-			return
-		}
-		transport := &http.Transport{
-			Proxy:           http.ProxyURL(proxyUrl),
-			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
-		}
-		config.HTTPClient = &http.Client{
-			Transport: transport,
-		}
-	}
-
-	if settings.OpenAISettings.BaseUrl != "" {
-		config.BaseURL = settings.OpenAISettings.BaseUrl
-	}
-
-	openaiClient := openai.NewClientWithConfig(config)
-	ctx := context.Background()
-
-	req := openai.ChatCompletionRequest{
-		Model:    settings.OpenAISettings.Model,
-		Messages: messages,
-		Stream:   true,
-	}
-	stream, err := openaiClient.CreateChatCompletionStream(ctx, req)
-	if err != nil {
-		fmt.Printf("CompletionStream error: %v\n", err)
-		c.Stream(func(w io.Writer) bool {
-			c.SSEvent("message", gin.H{
-				"type":    "error",
-				"content": err.Error(),
-			})
-			return false
-		})
-		return
-	}
-	defer stream.Close()
-	msgChan := make(chan string)
-	go func() {
-		defer close(msgChan)
-		for {
-			response, err := stream.Recv()
-			if errors.Is(err, io.EOF) {
-				fmt.Println()
-				return
-			}
-
-			if err != nil {
-				fmt.Printf("Stream error: %v\n", err)
-				return
-			}
-
-			message := fmt.Sprintf("%s", response.Choices[0].Delta.Content)
-
-			msgChan <- message
-		}
-	}()
-
-	c.Stream(func(w io.Writer) bool {
-		if m, ok := <-msgChan; ok {
-			c.SSEvent("message", gin.H{
-				"type":    "message",
-				"content": m,
-			})
-			return true
-		}
-		return false
-	})
+    var json struct {
+        Filepath string                         `json:"filepath"`
+        Messages []openai.ChatCompletionMessage `json:"messages"`
+    }
+
+    if !api.BindAndValid(c, &json) {
+        return
+    }
+
+    messages := []openai.ChatCompletionMessage{
+        {
+            Role:    openai.ChatMessageRoleSystem,
+            Content: ChatGPTInitPrompt,
+        },
+    }
+
+    messages = append(messages, json.Messages...)
+
+    if json.Filepath != "" {
+        messages = chatbot.ChatCompletionWithContext(json.Filepath, messages)
+    }
+
+    // SSE server
+    c.Writer.Header().Set("Content-Type", "text/event-stream; charset=utf-8")
+    c.Writer.Header().Set("Cache-Control", "no-cache")
+    c.Writer.Header().Set("Connection", "keep-alive")
+    c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
+
+    config := openai.DefaultConfig(settings.OpenAISettings.Token)
+
+    if settings.OpenAISettings.Proxy != "" {
+        proxyUrl, err := url.Parse(settings.OpenAISettings.Proxy)
+        if err != nil {
+            c.Stream(func(w io.Writer) bool {
+                c.SSEvent("message", gin.H{
+                    "type":    "error",
+                    "content": err.Error(),
+                })
+                return false
+            })
+            return
+        }
+        transport := &http.Transport{
+            Proxy:           http.ProxyURL(proxyUrl),
+            TLSClientConfig: &tls.Config{InsecureSkipVerify: settings.ServerSettings.InsecureSkipVerify},
+        }
+        config.HTTPClient = &http.Client{
+            Transport: transport,
+        }
+    }
+
+    if settings.OpenAISettings.BaseUrl != "" {
+        config.BaseURL = settings.OpenAISettings.BaseUrl
+    }
+
+    openaiClient := openai.NewClientWithConfig(config)
+    ctx := context.Background()
+
+    req := openai.ChatCompletionRequest{
+        Model:    settings.OpenAISettings.Model,
+        Messages: messages,
+        Stream:   true,
+    }
+    stream, err := openaiClient.CreateChatCompletionStream(ctx, req)
+    if err != nil {
+        fmt.Printf("CompletionStream error: %v\n", err)
+        c.Stream(func(w io.Writer) bool {
+            c.SSEvent("message", gin.H{
+                "type":    "error",
+                "content": err.Error(),
+            })
+            return false
+        })
+        return
+    }
+    defer stream.Close()
+    msgChan := make(chan string)
+    go func() {
+        defer close(msgChan)
+        for {
+            response, err := stream.Recv()
+            if errors.Is(err, io.EOF) {
+                fmt.Println()
+                return
+            }
+
+            if err != nil {
+                fmt.Printf("Stream error: %v\n", err)
+                return
+            }
+
+            message := fmt.Sprintf("%s", response.Choices[0].Delta.Content)
+
+            msgChan <- message
+        }
+    }()
+
+    c.Stream(func(w io.Writer) bool {
+        if m, ok := <-msgChan; ok {
+            c.SSEvent("message", gin.H{
+                "type":    "message",
+                "content": m,
+            })
+            return true
+        }
+        return false
+    })
 }

+ 82 - 81
internal/analytic/node.go

@@ -1,43 +1,44 @@
 package analytic
 
 import (
-	"crypto/tls"
-	"encoding/json"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
-	"github.com/0xJacky/Nginx-UI/internal/upgrader"
-	"github.com/0xJacky/Nginx-UI/model"
-	"github.com/shirou/gopsutil/v3/load"
-	"github.com/shirou/gopsutil/v3/net"
-	"io"
-	"net/http"
-	"net/url"
-	"sync"
-	"time"
+    "crypto/tls"
+    "encoding/json"
+    "github.com/0xJacky/Nginx-UI/internal/logger"
+    "github.com/0xJacky/Nginx-UI/internal/upgrader"
+    "github.com/0xJacky/Nginx-UI/model"
+    "github.com/0xJacky/Nginx-UI/settings"
+    "github.com/shirou/gopsutil/v3/load"
+    "github.com/shirou/gopsutil/v3/net"
+    "io"
+    "net/http"
+    "net/url"
+    "sync"
+    "time"
 )
 
 type NodeInfo struct {
-	NodeRuntimeInfo upgrader.RuntimeInfo `json:"node_runtime_info"`
-	Version         string               `json:"version"`
-	CPUNum          int                  `json:"cpu_num"`
-	MemoryTotal     string               `json:"memory_total"`
-	DiskTotal       string               `json:"disk_total"`
+    NodeRuntimeInfo upgrader.RuntimeInfo `json:"node_runtime_info"`
+    Version         string               `json:"version"`
+    CPUNum          int                  `json:"cpu_num"`
+    MemoryTotal     string               `json:"memory_total"`
+    DiskTotal       string               `json:"disk_total"`
 }
 
 type NodeStat struct {
-	AvgLoad       *load.AvgStat      `json:"avg_load"`
-	CPUPercent    float64            `json:"cpu_percent"`
-	MemoryPercent float64            `json:"memory_percent"`
-	DiskPercent   float64            `json:"disk_percent"`
-	Network       net.IOCountersStat `json:"network"`
-	Status        bool               `json:"status"`
-	ResponseAt    time.Time          `json:"response_at"`
+    AvgLoad       *load.AvgStat      `json:"avg_load"`
+    CPUPercent    float64            `json:"cpu_percent"`
+    MemoryPercent float64            `json:"memory_percent"`
+    DiskPercent   float64            `json:"disk_percent"`
+    Network       net.IOCountersStat `json:"network"`
+    Status        bool               `json:"status"`
+    ResponseAt    time.Time          `json:"response_at"`
 }
 
 type Node struct {
-	EnvironmentID int `json:"environment_id,omitempty"`
-	*model.Environment
-	NodeStat
-	NodeInfo
+    EnvironmentID int `json:"environment_id,omitempty"`
+    *model.Environment
+    NodeStat
+    NodeInfo
 }
 
 var mutex sync.Mutex
@@ -47,74 +48,74 @@ type TNodeMap map[int]*Node
 var NodeMap TNodeMap
 
 func init() {
-	NodeMap = make(TNodeMap)
+    NodeMap = make(TNodeMap)
 }
 
 func GetNode(env *model.Environment) (n *Node) {
-	if env == nil {
-		// this should never happen
-		logger.Error("env is nil")
-		return
-	}
-	if !env.Enabled {
-		return &Node{
-			Environment: env,
-		}
-	}
-	n, ok := NodeMap[env.ID]
-	if !ok {
-		n = &Node{}
-	}
-	n.Environment = env
-	return n
+    if env == nil {
+        // this should never happen
+        logger.Error("env is nil")
+        return
+    }
+    if !env.Enabled {
+        return &Node{
+            Environment: env,
+        }
+    }
+    n, ok := NodeMap[env.ID]
+    if !ok {
+        n = &Node{}
+    }
+    n.Environment = env
+    return n
 }
 
 func InitNode(env *model.Environment) (n *Node) {
-	n = &Node{
-		Environment: env,
-	}
+    n = &Node{
+        Environment: env,
+    }
 
-	u, err := url.JoinPath(env.URL, "/api/node")
+    u, err := url.JoinPath(env.URL, "/api/node")
 
-	if err != nil {
-		logger.Error(err)
-		return
-	}
+    if err != nil {
+        logger.Error(err)
+        return
+    }
 
-	client := http.Client{
-		Transport: &http.Transport{
-			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
-		},
-	}
+    client := http.Client{
+        Transport: &http.Transport{
+            TLSClientConfig: &tls.Config{InsecureSkipVerify: settings.ServerSettings.InsecureSkipVerify},
+        },
+    }
 
-	req, err := http.NewRequest("GET", u, nil)
-	if err != nil {
-		logger.Error(err)
-		return
-	}
+    req, err := http.NewRequest("GET", u, nil)
+    if err != nil {
+        logger.Error(err)
+        return
+    }
 
-	req.Header.Set("X-Node-Secret", env.Token)
+    req.Header.Set("X-Node-Secret", env.Token)
 
-	resp, err := client.Do(req)
+    resp, err := client.Do(req)
 
-	if err != nil {
-		logger.Error(err)
-		return
-	}
+    if err != nil {
+        logger.Error(err)
+        return
+    }
 
-	defer resp.Body.Close()
-	bytes, _ := io.ReadAll(resp.Body)
+    defer resp.Body.Close()
+    bytes, _ := io.ReadAll(resp.Body)
 
-	if resp.StatusCode != http.StatusOK {
-		logger.Error(string(bytes))
-		return
-	}
+    if resp.StatusCode != http.StatusOK {
+        logger.Error(string(bytes))
+        return
+    }
 
-	err = json.Unmarshal(bytes, &n.NodeInfo)
-	if err != nil {
-		logger.Error(err)
-		return
-	}
+    err = json.Unmarshal(bytes, &n.NodeInfo)
+    if err != nil {
+        logger.Error(err)
+        return
+    }
 
-	return
+    return
 }

+ 1 - 1
internal/cert/cert.go

@@ -64,7 +64,7 @@ func IssueCert(payload *ConfigPayload, logChan chan string, errChan chan error)
 	// Skip TLS check
 	if config.HTTPClient != nil {
 		config.HTTPClient.Transport = &http.Transport{
-			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+			TLSClientConfig: &tls.Config{InsecureSkipVerify: settings.ServerSettings.InsecureSkipVerify},
 		}
 	}
 

+ 3 - 2
internal/cert/sync.go

@@ -11,7 +11,8 @@ import (
 	"github.com/0xJacky/Nginx-UI/internal/notification"
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/0xJacky/Nginx-UI/query"
-	"github.com/go-acme/lego/v4/certcrypto"
+    "github.com/0xJacky/Nginx-UI/settings"
+    "github.com/go-acme/lego/v4/certcrypto"
 	"io"
 	"net/http"
 	"os"
@@ -89,7 +90,7 @@ type SyncNotificationPayload struct {
 func deploy(env *model.Environment, c *model.Cert, payloadBytes []byte) (err error) {
 	client := http.Client{
 		Transport: &http.Transport{
-			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+			TLSClientConfig: &tls.Config{InsecureSkipVerify: settings.ServerSettings.InsecureSkipVerify},
 		},
 	}
 	url, err := env.GetUrl("/api/cert_sync")

+ 230 - 229
internal/config/sync.go

@@ -1,257 +1,258 @@
 package config
 
 import (
-	"bytes"
-	"crypto/tls"
-	"encoding/json"
-	"fmt"
-	"github.com/0xJacky/Nginx-UI/internal/helper"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
-	"github.com/0xJacky/Nginx-UI/internal/nginx"
-	"github.com/0xJacky/Nginx-UI/internal/notification"
-	"github.com/0xJacky/Nginx-UI/model"
-	"github.com/0xJacky/Nginx-UI/query"
-	"github.com/gin-gonic/gin"
-	"io"
-	"net/http"
-	"os"
-	"path/filepath"
-	"strings"
+    "bytes"
+    "crypto/tls"
+    "encoding/json"
+    "fmt"
+    "github.com/0xJacky/Nginx-UI/internal/helper"
+    "github.com/0xJacky/Nginx-UI/internal/logger"
+    "github.com/0xJacky/Nginx-UI/internal/nginx"
+    "github.com/0xJacky/Nginx-UI/internal/notification"
+    "github.com/0xJacky/Nginx-UI/model"
+    "github.com/0xJacky/Nginx-UI/query"
+    "github.com/0xJacky/Nginx-UI/settings"
+    "github.com/gin-gonic/gin"
+    "io"
+    "net/http"
+    "os"
+    "path/filepath"
+    "strings"
 )
 
 type SyncConfigPayload struct {
-	Name        string `json:"name"`
-	Filepath    string `json:"filepath"`
-	NewFilepath string `json:"new_filepath"`
-	Content     string `json:"content"`
-	Overwrite   bool   `json:"overwrite"`
+    Name        string `json:"name"`
+    Filepath    string `json:"filepath"`
+    NewFilepath string `json:"new_filepath"`
+    Content     string `json:"content"`
+    Overwrite   bool   `json:"overwrite"`
 }
 
 func SyncToRemoteServer(c *model.Config, newFilepath string) (err error) {
-	if c.Filepath == "" || len(c.SyncNodeIds) == 0 {
-		return
-	}
-
-	nginxConfPath := nginx.GetConfPath()
-	if !helper.IsUnderDirectory(c.Filepath, nginxConfPath) {
-		return fmt.Errorf("config: %s is not under the nginx conf path: %s",
-			c.Filepath, nginxConfPath)
-	}
-
-	if newFilepath != "" && !helper.IsUnderDirectory(newFilepath, nginxConfPath) {
-		return fmt.Errorf("config: %s is not under the nginx conf path: %s",
-			c.Filepath, nginxConfPath)
-	}
-
-	currentPath := c.Filepath
-	if newFilepath != "" {
-		currentPath = newFilepath
-	}
-	configBytes, err := os.ReadFile(currentPath)
-	if err != nil {
-		return
-	}
-
-	payload := &SyncConfigPayload{
-		Name:        c.Name,
-		Filepath:    c.Filepath,
-		NewFilepath: newFilepath,
-		Content:     string(configBytes),
-		Overwrite:   c.SyncOverwrite,
-	}
-	payloadBytes, err := json.Marshal(payload)
-	if err != nil {
-		return
-	}
-
-	q := query.Environment
-	envs, _ := q.Where(q.ID.In(c.SyncNodeIds...)).Find()
-	for _, env := range envs {
-		go func() {
-			err := payload.deploy(env, c, payloadBytes)
-			if err != nil {
-				logger.Error(err)
-			}
-		}()
-	}
-
-	return
+    if c.Filepath == "" || len(c.SyncNodeIds) == 0 {
+        return
+    }
+
+    nginxConfPath := nginx.GetConfPath()
+    if !helper.IsUnderDirectory(c.Filepath, nginxConfPath) {
+        return fmt.Errorf("config: %s is not under the nginx conf path: %s",
+            c.Filepath, nginxConfPath)
+    }
+
+    if newFilepath != "" && !helper.IsUnderDirectory(newFilepath, nginxConfPath) {
+        return fmt.Errorf("config: %s is not under the nginx conf path: %s",
+            c.Filepath, nginxConfPath)
+    }
+
+    currentPath := c.Filepath
+    if newFilepath != "" {
+        currentPath = newFilepath
+    }
+    configBytes, err := os.ReadFile(currentPath)
+    if err != nil {
+        return
+    }
+
+    payload := &SyncConfigPayload{
+        Name:        c.Name,
+        Filepath:    c.Filepath,
+        NewFilepath: newFilepath,
+        Content:     string(configBytes),
+        Overwrite:   c.SyncOverwrite,
+    }
+    payloadBytes, err := json.Marshal(payload)
+    if err != nil {
+        return
+    }
+
+    q := query.Environment
+    envs, _ := q.Where(q.ID.In(c.SyncNodeIds...)).Find()
+    for _, env := range envs {
+        go func() {
+            err := payload.deploy(env, c, payloadBytes)
+            if err != nil {
+                logger.Error(err)
+            }
+        }()
+    }
+
+    return
 }
 
 func SyncRenameOnRemoteServer(origPath, newPath string, syncNodeIds []int) (err error) {
-	if origPath == "" || newPath == "" || len(syncNodeIds) == 0 {
-		return
-	}
-
-	nginxConfPath := nginx.GetConfPath()
-	if !helper.IsUnderDirectory(origPath, nginxConfPath) {
-		return fmt.Errorf("config: %s is not under the nginx conf path: %s",
-			origPath, nginxConfPath)
-	}
-
-	if !helper.IsUnderDirectory(newPath, nginxConfPath) {
-		return fmt.Errorf("config: %s is not under the nginx conf path: %s",
-			newPath, nginxConfPath)
-	}
-
-	payload := &RenameConfigPayload{
-		Filepath:    origPath,
-		NewFilepath: newPath,
-	}
-
-	q := query.Environment
-	envs, _ := q.Where(q.ID.In(syncNodeIds...)).Find()
-	for _, env := range envs {
-		go func() {
-			err := payload.rename(env)
-			if err != nil {
-				logger.Error(err)
-			}
-		}()
-	}
-
-	return
+    if origPath == "" || newPath == "" || len(syncNodeIds) == 0 {
+        return
+    }
+
+    nginxConfPath := nginx.GetConfPath()
+    if !helper.IsUnderDirectory(origPath, nginxConfPath) {
+        return fmt.Errorf("config: %s is not under the nginx conf path: %s",
+            origPath, nginxConfPath)
+    }
+
+    if !helper.IsUnderDirectory(newPath, nginxConfPath) {
+        return fmt.Errorf("config: %s is not under the nginx conf path: %s",
+            newPath, nginxConfPath)
+    }
+
+    payload := &RenameConfigPayload{
+        Filepath:    origPath,
+        NewFilepath: newPath,
+    }
+
+    q := query.Environment
+    envs, _ := q.Where(q.ID.In(syncNodeIds...)).Find()
+    for _, env := range envs {
+        go func() {
+            err := payload.rename(env)
+            if err != nil {
+                logger.Error(err)
+            }
+        }()
+    }
+
+    return
 }
 
 type SyncNotificationPayload struct {
-	StatusCode int    `json:"status_code"`
-	ConfigName string `json:"config_name"`
-	EnvName    string `json:"env_name"`
-	RespBody   string `json:"resp_body"`
+    StatusCode int    `json:"status_code"`
+    ConfigName string `json:"config_name"`
+    EnvName    string `json:"env_name"`
+    RespBody   string `json:"resp_body"`
 }
 
 func (p *SyncConfigPayload) deploy(env *model.Environment, c *model.Config, payloadBytes []byte) (err error) {
-	client := http.Client{
-		Transport: &http.Transport{
-			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
-		},
-	}
-	url, err := env.GetUrl("/api/config")
-	if err != nil {
-		return
-	}
-	req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(payloadBytes))
-	if err != nil {
-		return
-	}
-	req.Header.Set("X-Node-Secret", env.Token)
-	resp, err := client.Do(req)
-	if err != nil {
-		return
-	}
-	defer resp.Body.Close()
-
-	respBody, err := io.ReadAll(resp.Body)
-	if err != nil {
-		return
-	}
-
-	notificationPayload := &SyncNotificationPayload{
-		StatusCode: resp.StatusCode,
-		ConfigName: c.Name,
-		EnvName:    env.Name,
-		RespBody:   string(respBody),
-	}
-
-	notificationPayloadBytes, err := json.Marshal(notificationPayload)
-	if err != nil {
-		return
-	}
-
-	if resp.StatusCode != http.StatusOK {
-		notification.Error("Sync Config Error", string(notificationPayloadBytes))
-		return
-	}
-
-	notification.Success("Sync Config Success", string(notificationPayloadBytes))
-
-	// handle rename
-	if p.NewFilepath == "" || p.Filepath == p.NewFilepath {
-		return
-	}
-
-	payload := &RenameConfigPayload{
-		Filepath:    p.Filepath,
-		NewFilepath: p.NewFilepath,
-	}
-
-	err = payload.rename(env)
-
-	return
+    client := http.Client{
+        Transport: &http.Transport{
+            TLSClientConfig: &tls.Config{InsecureSkipVerify: settings.ServerSettings.InsecureSkipVerify},
+        },
+    }
+    url, err := env.GetUrl("/api/config")
+    if err != nil {
+        return
+    }
+    req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(payloadBytes))
+    if err != nil {
+        return
+    }
+    req.Header.Set("X-Node-Secret", env.Token)
+    resp, err := client.Do(req)
+    if err != nil {
+        return
+    }
+    defer resp.Body.Close()
+
+    respBody, err := io.ReadAll(resp.Body)
+    if err != nil {
+        return
+    }
+
+    notificationPayload := &SyncNotificationPayload{
+        StatusCode: resp.StatusCode,
+        ConfigName: c.Name,
+        EnvName:    env.Name,
+        RespBody:   string(respBody),
+    }
+
+    notificationPayloadBytes, err := json.Marshal(notificationPayload)
+    if err != nil {
+        return
+    }
+
+    if resp.StatusCode != http.StatusOK {
+        notification.Error("Sync Config Error", string(notificationPayloadBytes))
+        return
+    }
+
+    notification.Success("Sync Config Success", string(notificationPayloadBytes))
+
+    // handle rename
+    if p.NewFilepath == "" || p.Filepath == p.NewFilepath {
+        return
+    }
+
+    payload := &RenameConfigPayload{
+        Filepath:    p.Filepath,
+        NewFilepath: p.NewFilepath,
+    }
+
+    err = payload.rename(env)
+
+    return
 }
 
 type RenameConfigPayload struct {
-	Filepath    string `json:"filepath"`
-	NewFilepath string `json:"new_filepath"`
+    Filepath    string `json:"filepath"`
+    NewFilepath string `json:"new_filepath"`
 }
 
 type SyncRenameNotificationPayload struct {
-	StatusCode int    `json:"status_code"`
-	OrigPath   string `json:"orig_path"`
-	NewPath    string `json:"new_path"`
-	EnvName    string `json:"env_name"`
-	RespBody   string `json:"resp_body"`
+    StatusCode int    `json:"status_code"`
+    OrigPath   string `json:"orig_path"`
+    NewPath    string `json:"new_path"`
+    EnvName    string `json:"env_name"`
+    RespBody   string `json:"resp_body"`
 }
 
 func (p *RenameConfigPayload) rename(env *model.Environment) (err error) {
-	// handle rename
-	if p.NewFilepath == "" || p.Filepath == p.NewFilepath {
-		return
-	}
-
-	client := http.Client{
-		Transport: &http.Transport{
-			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
-		},
-	}
-
-	payloadBytes, err := json.Marshal(gin.H{
-		"base_path": strings.ReplaceAll(filepath.Dir(p.Filepath), nginx.GetConfPath(), ""),
-		"orig_name": filepath.Base(p.Filepath),
-		"new_name":  filepath.Base(p.NewFilepath),
-	})
-	if err != nil {
-		return
-	}
-	url, err := env.GetUrl("/api/config_rename")
-	if err != nil {
-		return
-	}
-	req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(payloadBytes))
-	if err != nil {
-		return
-	}
-	req.Header.Set("X-Node-Secret", env.Token)
-	resp, err := client.Do(req)
-	if err != nil {
-		return
-	}
-	defer resp.Body.Close()
-
-	respBody, err := io.ReadAll(resp.Body)
-	if err != nil {
-		return
-	}
-
-	notificationPayload := &SyncRenameNotificationPayload{
-		StatusCode: resp.StatusCode,
-		OrigPath:   p.Filepath,
-		NewPath:    p.NewFilepath,
-		EnvName:    env.Name,
-		RespBody:   string(respBody),
-	}
-
-	notificationPayloadBytes, err := json.Marshal(notificationPayload)
-	if err != nil {
-		return
-	}
-
-	if resp.StatusCode != http.StatusOK {
-		notification.Error("Rename Remote Config Error", string(notificationPayloadBytes))
-		return
-	}
-
-	notification.Success("Rename Remote Config Success", string(notificationPayloadBytes))
-
-	return
+    // handle rename
+    if p.NewFilepath == "" || p.Filepath == p.NewFilepath {
+        return
+    }
+
+    client := http.Client{
+        Transport: &http.Transport{
+            TLSClientConfig: &tls.Config{InsecureSkipVerify: settings.ServerSettings.InsecureSkipVerify},
+        },
+    }
+
+    payloadBytes, err := json.Marshal(gin.H{
+        "base_path": strings.ReplaceAll(filepath.Dir(p.Filepath), nginx.GetConfPath(), ""),
+        "orig_name": filepath.Base(p.Filepath),
+        "new_name":  filepath.Base(p.NewFilepath),
+    })
+    if err != nil {
+        return
+    }
+    url, err := env.GetUrl("/api/config_rename")
+    if err != nil {
+        return
+    }
+    req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(payloadBytes))
+    if err != nil {
+        return
+    }
+    req.Header.Set("X-Node-Secret", env.Token)
+    resp, err := client.Do(req)
+    if err != nil {
+        return
+    }
+    defer resp.Body.Close()
+
+    respBody, err := io.ReadAll(resp.Body)
+    if err != nil {
+        return
+    }
+
+    notificationPayload := &SyncRenameNotificationPayload{
+        StatusCode: resp.StatusCode,
+        OrigPath:   p.Filepath,
+        NewPath:    p.NewFilepath,
+        EnvName:    env.Name,
+        RespBody:   string(respBody),
+    }
+
+    notificationPayloadBytes, err := json.Marshal(notificationPayload)
+    if err != nil {
+        return
+    }
+
+    if resp.StatusCode != http.StatusOK {
+        notification.Error("Rename Remote Config Error", string(notificationPayloadBytes))
+        return
+    }
+
+    notification.Success("Rename Remote Config Success", string(notificationPayloadBytes))
+
+    return
 }

+ 3 - 2
internal/middleware/proxy.go

@@ -4,7 +4,8 @@ import (
 	"crypto/tls"
 	"github.com/0xJacky/Nginx-UI/internal/logger"
 	"github.com/0xJacky/Nginx-UI/query"
-	"github.com/gin-gonic/gin"
+    "github.com/0xJacky/Nginx-UI/settings"
+    "github.com/gin-gonic/gin"
 	"github.com/spf13/cast"
 	"io"
 	"net/http"
@@ -58,7 +59,7 @@ func Proxy() gin.HandlerFunc {
 		logger.Debug("Proxy request", proxyUrl.String())
 		client := http.Client{
 			Transport: &http.Transport{
-				TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+				TLSClientConfig: &tls.Config{InsecureSkipVerify: settings.ServerSettings.InsecureSkipVerify},
 			},
 		}
 

+ 3 - 2
model/acme_user.go

@@ -6,7 +6,8 @@ import (
 	"crypto/elliptic"
 	"crypto/rand"
 	"crypto/tls"
-	"github.com/go-acme/lego/v4/lego"
+    "github.com/0xJacky/Nginx-UI/settings"
+    "github.com/go-acme/lego/v4/lego"
 	"github.com/go-acme/lego/v4/registration"
 	"math/big"
 	"net/http"
@@ -63,7 +64,7 @@ func (u *AcmeUser) Register() error {
 	// Skip TLS check
 	if config.HTTPClient != nil {
 		config.HTTPClient.Transport = &http.Transport{
-			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+			TLSClientConfig: &tls.Config{InsecureSkipVerify: settings.ServerSettings.InsecureSkipVerify},
 		}
 	}
 

+ 1 - 0
settings/server.go

@@ -21,6 +21,7 @@ type Server struct {
 	CertRenewalInterval  int      `json:"cert_renewal_interval" binding:"min=7,max=21"`
 	RecursiveNameservers []string `json:"recursive_nameservers" binding:"omitempty,dive,hostname_port"`
 	SkipInstallation     bool     `json:"skip_installation" protected:"true"`
+	InsecureSkipVerify   bool     `json:"insecure_skip_verify" protected:"true"`
 	Name                 string   `json:"name" binding:"omitempty,safety_text"`
 }