mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2024-11-27 12:39:01 +08:00
feat: 网站增加创建反向代理功能
This commit is contained in:
parent
bd8d96be4d
commit
d900b52a50
@ -648,3 +648,47 @@ func (b *BaseApi) UpdateSiteDirPermission(c *gin.Context) {
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// @Tags Website
|
||||
// @Summary Get proxy conf
|
||||
// @Description 获取反向代理配置
|
||||
// @Accept json
|
||||
// @Param request body request.WebsiteProxyReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/proxies [post]
|
||||
func (b *BaseApi) GetProxyConfig(c *gin.Context) {
|
||||
var req request.WebsiteProxyReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
res, err := websiteService.GetProxies(req.ID)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, res)
|
||||
}
|
||||
|
||||
// @Tags Website
|
||||
// @Summary Update proxy conf
|
||||
// @Description 修改反向代理配置
|
||||
// @Accept json
|
||||
// @Param request body request.WebsiteProxyConfig true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/proxies/update [post]
|
||||
func (b *BaseApi) UpdateProxyConfig(c *gin.Context) {
|
||||
var req request.WebsiteProxyConfig
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
err := websiteService.OperateProxy(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
@ -31,10 +31,12 @@ type NginxParam struct {
|
||||
type NginxKey string
|
||||
|
||||
const (
|
||||
Index NginxKey = "index"
|
||||
LimitConn NginxKey = "limit-conn"
|
||||
SSL NginxKey = "ssl"
|
||||
HttpPer NginxKey = "http-per"
|
||||
Index NginxKey = "index"
|
||||
LimitConn NginxKey = "limit-conn"
|
||||
SSL NginxKey = "ssl"
|
||||
CACHE NginxKey = "cache"
|
||||
HttpPer NginxKey = "http-per"
|
||||
ProxyCache NginxKey = "proxy-cache"
|
||||
)
|
||||
|
||||
var ScopeKeyMap = map[NginxKey][]string{
|
||||
@ -46,5 +48,7 @@ var ScopeKeyMap = map[NginxKey][]string{
|
||||
|
||||
var StaticFileKeyMap = map[NginxKey]struct {
|
||||
}{
|
||||
SSL: {},
|
||||
SSL: {},
|
||||
CACHE: {},
|
||||
ProxyCache: {},
|
||||
}
|
||||
|
@ -156,3 +156,23 @@ type WebsiteUpdateDirPermission struct {
|
||||
User string `json:"user" validate:"required"`
|
||||
Group string `json:"group" validate:"required"`
|
||||
}
|
||||
|
||||
type WebsiteProxyConfig struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Operate string `json:"operate" validate:"required"`
|
||||
Enable bool `json:"enable" validate:"required"`
|
||||
Cache bool `json:"cache" validate:"required"`
|
||||
CacheTime int `json:"cacheTime" validate:"required"`
|
||||
CacheUnit string `json:"cacheUnit" validate:"required"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
Modifier string `json:"modifier" validate:"required"`
|
||||
Match string `json:"match" validate:"required"`
|
||||
ProxyPass string `json:"proxyPass" validate:"required"`
|
||||
ProxyHost string `json:"proxyHost" validate:"required"`
|
||||
FilePath string `json:"filePath"`
|
||||
Replaces []map[string]string `json:"replaces"`
|
||||
}
|
||||
|
||||
type WebsiteProxyReq struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
}
|
||||
|
@ -161,6 +161,10 @@ func getNginxParamsFromStaticFile(scope dto.NginxKey, newParams []dto.NginxParam
|
||||
switch scope {
|
||||
case dto.SSL:
|
||||
newConfig = parser.NewStringParser(string(nginx_conf.SSL)).Parse()
|
||||
case dto.CACHE:
|
||||
newConfig = parser.NewStringParser(string(nginx_conf.Cache)).Parse()
|
||||
case dto.ProxyCache:
|
||||
newConfig = parser.NewStringParser(string(nginx_conf.ProxyCache)).Parse()
|
||||
}
|
||||
for _, dir := range newConfig.GetDirectives() {
|
||||
addParam := dto.NginxParam{
|
||||
|
@ -10,12 +10,16 @@ import (
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/nginx"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/nginx/components"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/nginx/parser"
|
||||
"github.com/1Panel-dev/1Panel/cmd/server/nginx_conf"
|
||||
"gorm.io/gorm"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -64,6 +68,8 @@ type IWebsiteService interface {
|
||||
UpdateRewriteConfig(req request.NginxRewriteUpdate) error
|
||||
UpdateSiteDir(req request.WebsiteUpdateDir) error
|
||||
UpdateSitePermission(req request.WebsiteUpdateDirPermission) error
|
||||
OperateProxy(req request.WebsiteProxyConfig) (err error)
|
||||
GetProxies(id uint) (res []request.WebsiteProxyConfig, err error)
|
||||
}
|
||||
|
||||
func NewIWebsiteService() IWebsiteService {
|
||||
@ -1105,3 +1111,169 @@ func (w WebsiteService) UpdateSitePermission(req request.WebsiteUpdateDirPermiss
|
||||
website.Group = req.Group
|
||||
return websiteRepo.Save(context.Background(), &website)
|
||||
}
|
||||
|
||||
func (w WebsiteService) OperateProxy(req request.WebsiteProxyConfig) (err error) {
|
||||
var (
|
||||
website model.Website
|
||||
params []response.NginxParam
|
||||
nginxInstall model.AppInstall
|
||||
par *parser.Parser
|
||||
oldContent []byte
|
||||
)
|
||||
|
||||
website, err = websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
params, err = getNginxParamsByKeys(constant.NginxScopeHttp, []string{"proxy_cache"}, &website)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
nginxInstall, err = getAppInstallByKey(constant.AppOpenresty)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fileOp := files.NewFileOp()
|
||||
if len(params) == 0 || len(params[0].Params) == 0 {
|
||||
commonDir := path.Join(nginxInstall.GetPath(), "www", "common", "proxy")
|
||||
proxyTempPath := path.Join(commonDir, "proxy_temp_dir")
|
||||
if !fileOp.Stat(proxyTempPath) {
|
||||
_ = fileOp.CreateDir(proxyTempPath, 0755)
|
||||
}
|
||||
proxyCacheDir := path.Join(commonDir, "proxy_temp_dir")
|
||||
if !fileOp.Stat(proxyCacheDir) {
|
||||
_ = fileOp.CreateDir(proxyCacheDir, 0755)
|
||||
}
|
||||
nginxParams := getNginxParamsFromStaticFile(dto.CACHE, nil)
|
||||
if err = updateNginxConfig(constant.NginxScopeHttp, nginxParams, &website); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
includeDir := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "proxy")
|
||||
if !fileOp.Stat(includeDir) {
|
||||
_ = fileOp.CreateDir(includeDir, 0755)
|
||||
}
|
||||
fileName := fmt.Sprintf("%s.conf", req.Name)
|
||||
includePath := path.Join(includeDir, fileName)
|
||||
if !fileOp.Stat(includePath) {
|
||||
_ = fileOp.CreateFile(includePath)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
switch req.Operate {
|
||||
case "create":
|
||||
_ = fileOp.DeleteFile(includePath)
|
||||
case "update":
|
||||
_ = fileOp.WriteFile(includePath, bytes.NewReader(oldContent), 0755)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
var config *components.Config
|
||||
|
||||
switch req.Operate {
|
||||
case "create":
|
||||
config = parser.NewStringParser(string(nginx_conf.Proxy)).Parse()
|
||||
case "update":
|
||||
par, err = parser.NewParser(includePath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
config = par.Parse()
|
||||
oldContent, err = fileOp.GetContent(includePath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
case "delete":
|
||||
_ = fileOp.DeleteFile(includePath)
|
||||
return updateNginxConfig(constant.NginxScopeServer, nil, &website)
|
||||
case "disable":
|
||||
backName := fmt.Sprintf("%s.bak", req.Name)
|
||||
backPath := path.Join(includeDir, backName)
|
||||
_ = fileOp.Rename(includePath, backPath)
|
||||
return updateNginxConfig(constant.NginxScopeServer, nil, &website)
|
||||
}
|
||||
config.FilePath = includePath
|
||||
directives := config.Directives
|
||||
location, ok := directives[0].(*components.Location)
|
||||
if !ok {
|
||||
err = errors.New("error")
|
||||
return
|
||||
}
|
||||
location.UpdateDirective("proxy_pass", []string{req.ProxyPass})
|
||||
location.UpdateDirective("proxy_set_header", []string{"Host", req.ProxyHost})
|
||||
location.ChangePath(req.Modifier, req.Match)
|
||||
if req.Cache {
|
||||
location.AddCache(strconv.Itoa(req.CacheTime) + req.CacheUnit)
|
||||
} else {
|
||||
location.RemoveCache()
|
||||
}
|
||||
|
||||
if err = nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
||||
return buserr.WithErr(constant.ErrUpdateBuWebsite, err)
|
||||
}
|
||||
nginxInclude := path.Join("www", "sites", website.Alias, "proxy", "*.conf")
|
||||
if err = updateNginxConfig(constant.NginxScopeServer, []dto.NginxParam{{Name: "include", Params: []string{nginxInclude}}}, &website); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (w WebsiteService) GetProxies(id uint) (res []request.WebsiteProxyConfig, err error) {
|
||||
var (
|
||||
website model.Website
|
||||
nginxInstall model.AppInstall
|
||||
fileList response.FileInfo
|
||||
)
|
||||
website, err = websiteRepo.GetFirst(commonRepo.WithByID(id))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
nginxInstall, err = getAppInstallByKey(constant.AppOpenresty)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
includeDir := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "proxy")
|
||||
fileOp := files.NewFileOp()
|
||||
if !fileOp.Stat(includeDir) {
|
||||
return
|
||||
}
|
||||
fileList, err = NewIFileService().GetFileList(request.FileOption{FileOption: files.FileOption{Path: includeDir, Expand: true, Page: 1, PageSize: 100}})
|
||||
if len(fileList.Items) == 0 {
|
||||
return
|
||||
}
|
||||
var (
|
||||
content []byte
|
||||
config *components.Config
|
||||
)
|
||||
for _, configFile := range fileList.Items {
|
||||
proxyConfig := request.WebsiteProxyConfig{}
|
||||
parts := strings.Split(configFile.Name, ".")
|
||||
proxyConfig.Name = parts[0]
|
||||
if parts[1] == "conf" {
|
||||
proxyConfig.Enable = true
|
||||
} else {
|
||||
proxyConfig.Enable = false
|
||||
}
|
||||
proxyConfig.FilePath = configFile.Path
|
||||
content, err = fileOp.GetContent(configFile.Path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
config = parser.NewStringParser(string(content)).Parse()
|
||||
directives := config.GetDirectives()
|
||||
|
||||
location, ok := directives[0].(*components.Location)
|
||||
if !ok {
|
||||
err = errors.New("error")
|
||||
return
|
||||
}
|
||||
proxyConfig.ProxyPass = location.ProxyPass
|
||||
proxyConfig.Cache = location.Cache
|
||||
//proxyConfig.CacheTime = location.CacheTime
|
||||
proxyConfig.Match = location.Match
|
||||
res = append(res, proxyConfig)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -5,8 +5,9 @@ const (
|
||||
NginxScopeHttp = "http"
|
||||
NginxScopeOut = "out"
|
||||
|
||||
NginxReload = "reload"
|
||||
NginxCheck = "check"
|
||||
NginxReload = "reload"
|
||||
NginxCheck = "check"
|
||||
NginxRestart = "restart"
|
||||
|
||||
ConfigNew = "add"
|
||||
ConfigUpdate = "update"
|
||||
|
@ -51,5 +51,8 @@ func (a *WebsiteRouter) InitWebsiteRouter(Router *gin.RouterGroup) {
|
||||
|
||||
groupRouter.POST("/dir/update", baseApi.UpdateSiteDir)
|
||||
groupRouter.POST("/dir/permission", baseApi.UpdateSiteDirPermission)
|
||||
|
||||
groupRouter.POST("/proxies", baseApi.GetProxyConfig)
|
||||
groupRouter.POST("/proxies/update", baseApi.UpdateProxyConfig)
|
||||
}
|
||||
}
|
||||
|
@ -62,41 +62,6 @@ func (b *Block) UpdateDirective(key string, params []string) {
|
||||
b.Directives = directives
|
||||
}
|
||||
|
||||
//func (b *Block) UpdateDirectiveBySecondKey(name string, key string, directive Directive) {
|
||||
//
|
||||
// directives := b.GetDirectives()
|
||||
//
|
||||
// index := -1
|
||||
// for i, dir := range directives {
|
||||
// if dir.GetName() == name && dir.GetParameters()[0] == key {
|
||||
// index = i
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// if index > -1 {
|
||||
// directives[index] = &directive
|
||||
// } else {
|
||||
// directives = append(directives, &directive)
|
||||
// }
|
||||
// b.Directives = directives
|
||||
//}
|
||||
|
||||
//func (b *Block) RemoveDirectives(names []string) {
|
||||
// nameMaps := make(map[string]struct{}, len(names))
|
||||
// for _, name := range names {
|
||||
// nameMaps[name] = struct{}{}
|
||||
// }
|
||||
// directives := b.GetDirectives()
|
||||
// var newDirectives []IDirective
|
||||
// for _, dir := range directives {
|
||||
// if _, ok := nameMaps[dir.GetName()]; ok {
|
||||
// continue
|
||||
// }
|
||||
// newDirectives = append(newDirectives, dir)
|
||||
// }
|
||||
// b.Directives = newDirectives
|
||||
//}
|
||||
|
||||
func (b *Block) RemoveDirective(key string, params []string) {
|
||||
directives := b.GetDirectives()
|
||||
var newDirectives []IDirective
|
||||
|
@ -1,32 +1,196 @@
|
||||
package components
|
||||
|
||||
type Location struct {
|
||||
*Directive
|
||||
Modifier string
|
||||
Match string
|
||||
Modifier string
|
||||
Match string
|
||||
Cache bool
|
||||
ProxyPass string
|
||||
Host string
|
||||
CacheTime string
|
||||
|
||||
Comment string
|
||||
Directives []IDirective
|
||||
Line int
|
||||
Parameters []string
|
||||
}
|
||||
|
||||
func NewLocation(directive *Directive) *Location {
|
||||
func NewLocation(directive IDirective) *Location {
|
||||
location := &Location{
|
||||
Modifier: "",
|
||||
Match: "",
|
||||
Directive: directive,
|
||||
Modifier: "",
|
||||
Match: "",
|
||||
}
|
||||
if directive.GetBlock() != nil {
|
||||
directive.Comment = directive.GetBlock().GetComment()
|
||||
}
|
||||
|
||||
if len(directive.Parameters) == 0 {
|
||||
directives := make([]IDirective, 0)
|
||||
if len(directive.GetParameters()) == 0 {
|
||||
panic("no enough parameter for location")
|
||||
}
|
||||
|
||||
if len(directive.Parameters) == 1 {
|
||||
location.Match = directive.Parameters[0]
|
||||
return location
|
||||
} else if len(directive.Parameters) == 2 {
|
||||
location.Match = directive.Parameters[1]
|
||||
location.Modifier = directive.Parameters[0]
|
||||
return location
|
||||
for _, dir := range directive.GetBlock().GetDirectives() {
|
||||
directives = append(directives, dir)
|
||||
params := dir.GetParameters()
|
||||
switch dir.GetName() {
|
||||
case "proxy_pass":
|
||||
location.ProxyPass = params[0]
|
||||
case "proxy_set_header":
|
||||
if params[0] == "Host" {
|
||||
location.Host = params[1]
|
||||
}
|
||||
case "proxy_cache":
|
||||
location.Cache = true
|
||||
case "if":
|
||||
if params[0] == "(" && params[1] == "$uri" && params[2] == "~*" {
|
||||
dirs := dir.GetBlock().GetDirectives()
|
||||
for _, di := range dirs {
|
||||
if di.GetName() == "expires" {
|
||||
location.CacheTime = di.GetParameters()[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
params := directive.GetParameters()
|
||||
if len(params) == 1 {
|
||||
location.Match = params[0]
|
||||
} else if len(params) == 2 {
|
||||
location.Match = params[1]
|
||||
location.Modifier = params[0]
|
||||
}
|
||||
location.Parameters = directive.GetParameters()
|
||||
location.Line = directive.GetLine()
|
||||
location.Comment = directive.GetComment()
|
||||
location.Directives = directives
|
||||
return location
|
||||
}
|
||||
|
||||
func (l *Location) GetName() string {
|
||||
return "location"
|
||||
}
|
||||
|
||||
func (l *Location) GetParameters() []string {
|
||||
return l.Parameters
|
||||
}
|
||||
|
||||
func (l *Location) GetBlock() IBlock {
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *Location) GetComment() string {
|
||||
return l.Comment
|
||||
}
|
||||
|
||||
func (l *Location) GetLine() int {
|
||||
return l.Line
|
||||
}
|
||||
|
||||
func (l *Location) GetDirectives() []IDirective {
|
||||
return l.Directives
|
||||
}
|
||||
|
||||
func (l *Location) FindDirectives(directiveName string) []IDirective {
|
||||
directives := make([]IDirective, 0)
|
||||
for _, directive := range l.Directives {
|
||||
if directive.GetName() == directiveName {
|
||||
directives = append(directives, directive)
|
||||
}
|
||||
if directive.GetBlock() != nil {
|
||||
directives = append(directives, directive.GetBlock().FindDirectives(directiveName)...)
|
||||
}
|
||||
}
|
||||
return directives
|
||||
}
|
||||
|
||||
func (l *Location) UpdateDirective(key string, params []string) {
|
||||
if key == "" || len(params) == 0 {
|
||||
return
|
||||
}
|
||||
directives := l.Directives
|
||||
index := -1
|
||||
for i, dir := range directives {
|
||||
if dir.GetName() == key {
|
||||
if IsRepeatKey(key) {
|
||||
oldParams := dir.GetParameters()
|
||||
if !(len(oldParams) > 0 && oldParams[0] == params[0]) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
newDirective := &Directive{
|
||||
Name: key,
|
||||
Parameters: params,
|
||||
}
|
||||
if index > -1 {
|
||||
directives[index] = newDirective
|
||||
} else {
|
||||
directives = append(directives, newDirective)
|
||||
}
|
||||
l.Directives = directives
|
||||
}
|
||||
|
||||
func (l *Location) RemoveDirective(key string, params []string) {
|
||||
directives := l.Directives
|
||||
var newDirectives []IDirective
|
||||
for _, dir := range directives {
|
||||
if dir.GetName() == key {
|
||||
if len(params) > 0 {
|
||||
oldParams := dir.GetParameters()
|
||||
if oldParams[0] == params[0] {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
newDirectives = append(newDirectives, dir)
|
||||
}
|
||||
l.Directives = newDirectives
|
||||
}
|
||||
|
||||
func (l *Location) ChangePath(Modifier string, Match string) {
|
||||
if Match != "" && Modifier != "" {
|
||||
l.Parameters = []string{Modifier, Match}
|
||||
}
|
||||
if Match != "" && Modifier == "" {
|
||||
l.Parameters = []string{Match}
|
||||
}
|
||||
l.Modifier = Modifier
|
||||
l.Match = Match
|
||||
}
|
||||
|
||||
func (l *Location) AddCache(cacheTime string) {
|
||||
l.RemoveDirective("add_header", []string{"Cache-Control", "no-cache"})
|
||||
directives := l.GetDirectives()
|
||||
newDir := &Directive{
|
||||
Name: "if",
|
||||
Parameters: []string{"(", "$uri", "~*", `"\.(gif|png|jpg|css|js|woff|woff2)$"`, ")"},
|
||||
Block: &Block{},
|
||||
}
|
||||
block := &Block{}
|
||||
block.Directives = append(block.Directives, &Directive{
|
||||
Name: "expires",
|
||||
Parameters: []string{cacheTime},
|
||||
})
|
||||
newDir.Block = block
|
||||
directives = append(directives, newDir)
|
||||
l.Directives = directives
|
||||
l.UpdateDirective("proxy_ignore_headers", []string{"Set-Cookie", "Cache-Control", "expires"})
|
||||
l.UpdateDirective("proxy_cache", []string{"proxy_cache_panel"})
|
||||
l.UpdateDirective("proxy_cache_key", []string{"$host$uri$is_args$args"})
|
||||
l.UpdateDirective("proxy_cache_valid", []string{"200", "304", "301", "302", "10m"})
|
||||
l.Cache = true
|
||||
l.CacheTime = cacheTime
|
||||
}
|
||||
|
||||
func (l *Location) RemoveCache() {
|
||||
l.RemoveDirective("if", []string{"(", "$uri", "~*", `"\.(gif|png|jpg|css|js|woff|woff2)$"`, ")"})
|
||||
l.RemoveDirective("proxy_ignore_headers", []string{"Set-Cookie"})
|
||||
l.RemoveDirective("proxy_cache", []string{"proxy_cache_panel"})
|
||||
l.RemoveDirective("proxy_cache_key", []string{"$host$uri$is_args$args"})
|
||||
l.RemoveDirective("proxy_cache_valid", []string{"200"})
|
||||
|
||||
l.UpdateDirective("add_header", []string{"Cache-Control", "no-cache"})
|
||||
|
||||
l.CacheTime = ""
|
||||
l.Cache = false
|
||||
}
|
||||
|
@ -5,8 +5,9 @@ import (
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
Comment string
|
||||
Listens []*ServerListen
|
||||
Comment string
|
||||
Listens []*ServerListen
|
||||
//Locations []*Location
|
||||
Directives []IDirective
|
||||
Line int
|
||||
}
|
||||
@ -21,6 +22,15 @@ func NewServer(directive IDirective) (*Server, error) {
|
||||
switch dir.GetName() {
|
||||
case "listen":
|
||||
server.Listens = append(server.Listens, NewServerListen(dir.GetParameters(), dir.GetLine()))
|
||||
//case "location":
|
||||
// locationDirective := &Directive{
|
||||
// Name: "location",
|
||||
// Parameters: dir.GetParameters(),
|
||||
// Block: dir.GetBlock(),
|
||||
// Line: dir.GetLine(),
|
||||
// Comment: dir.GetComment(),
|
||||
// }
|
||||
// server.Locations = append(server.Locations, NewLocation(locationDirective))
|
||||
default:
|
||||
server.Directives = append(server.Directives, dir)
|
||||
}
|
||||
@ -51,6 +61,9 @@ func (s *Server) GetDirectives() []IDirective {
|
||||
for _, ls := range s.Listens {
|
||||
directives = append(directives, ls)
|
||||
}
|
||||
//for _, la := range s.Locations {
|
||||
// directives = append(directives, la)
|
||||
//}
|
||||
directives = append(directives, s.Directives...)
|
||||
return directives
|
||||
}
|
||||
@ -116,22 +129,14 @@ func (s *Server) RemoveDirective(key string, params []string) {
|
||||
directives := s.Directives
|
||||
var newDirectives []IDirective
|
||||
for _, dir := range directives {
|
||||
if key == "location" {
|
||||
if location, ok := dir.(*Location); ok {
|
||||
if len(params) == 2 && location.Match == params[1] && location.Modifier == params[0] {
|
||||
continue
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if dir.GetName() == key {
|
||||
if len(params) > 0 {
|
||||
oldParams := dir.GetParameters()
|
||||
if oldParams[0] == params[0] {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
if dir.GetName() == key {
|
||||
if len(params) > 0 {
|
||||
oldParams := dir.GetParameters()
|
||||
if oldParams[0] == params[0] {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
newDirectives = append(newDirectives, dir)
|
||||
|
@ -74,7 +74,6 @@ func DumpBlock(b components.IBlock, style *Style, startLine int) string {
|
||||
}
|
||||
|
||||
directives := b.GetDirectives()
|
||||
|
||||
for i, directive := range directives {
|
||||
|
||||
if directive.GetLine() > line {
|
||||
|
@ -84,7 +84,6 @@ func (p *Parser) Parse() *components.Config {
|
||||
}
|
||||
|
||||
func (p *Parser) parseBlock() *components.Block {
|
||||
|
||||
context := &components.Block{
|
||||
Comment: "",
|
||||
Directives: make([]components.IDirective, 0),
|
||||
|
12
cmd/server/nginx_conf/cache.conf
Normal file
12
cmd/server/nginx_conf/cache.conf
Normal file
@ -0,0 +1,12 @@
|
||||
proxy_temp_path /www/common/proxy/proxy_temp_dir;
|
||||
proxy_cache_path /www/common/proxy/proxy_cache_dir levels=1:2 keys_zone=proxy_cache_panel:20m inactive=1d max_size=5g;
|
||||
client_body_buffer_size 512k;
|
||||
proxy_connect_timeout 60;
|
||||
proxy_read_timeout 60;
|
||||
proxy_send_timeout 60;
|
||||
proxy_buffer_size 32k;
|
||||
proxy_buffers 4 64k;
|
||||
proxy_busy_buffers_size 128k;
|
||||
proxy_temp_file_write_size 128k;
|
||||
proxy_next_upstream error timeout invalid_header http_500 http_503 http_404;
|
||||
proxy_cache proxy_cache_panel;
|
@ -19,3 +19,12 @@ var IndexPHP []byte
|
||||
|
||||
//go:embed rewrite/*
|
||||
var Rewrites embed.FS
|
||||
|
||||
//go:embed cache.conf
|
||||
var Cache []byte
|
||||
|
||||
//go:embed proxy.conf
|
||||
var Proxy []byte
|
||||
|
||||
//go:embed proxy_cache.conf
|
||||
var ProxyCache []byte
|
||||
|
12
cmd/server/nginx_conf/proxy.conf
Normal file
12
cmd/server/nginx_conf/proxy.conf
Normal file
@ -0,0 +1,12 @@
|
||||
location ^~ /test {
|
||||
proxy_pass http://1panel.cloud/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header REMOTE-HOST $remote_addr;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_http_version 1.1;
|
||||
|
||||
add_header X-Cache $upstream_cache_status;
|
||||
}
|
4
cmd/server/nginx_conf/proxy_cache.conf
Normal file
4
cmd/server/nginx_conf/proxy_cache.conf
Normal file
@ -0,0 +1,4 @@
|
||||
proxy_ignore_headers Set-Cookie Cache-Control expires;
|
||||
proxy_cache cache_one;
|
||||
proxy_cache_key $host$uri$is_args$args;
|
||||
proxy_cache_valid 200 304 301 302 10m;
|
10
cmd/server/nginx_conf/proxy_no_cache.conf
Normal file
10
cmd/server/nginx_conf/proxy_no_cache.conf
Normal file
@ -0,0 +1,10 @@
|
||||
set $static_fileg 0;
|
||||
if ( $uri ~* "\.(gif|png|jpg|css|js|woff|woff2)$" )
|
||||
{
|
||||
set $static_fileg 1;
|
||||
expires 1m;
|
||||
}
|
||||
if ( $static_fileg = 0 )
|
||||
{
|
||||
add_header Cache-Control no-cache;
|
||||
}
|
@ -307,4 +307,28 @@ export namespace Website {
|
||||
user: string;
|
||||
group: string;
|
||||
}
|
||||
|
||||
export interface ProxyReq {
|
||||
id: number;
|
||||
}
|
||||
|
||||
export interface ProxyConfig {
|
||||
id: number;
|
||||
operate: string;
|
||||
enable: boolean;
|
||||
cache: boolean;
|
||||
cacheTime: number;
|
||||
cacheUnit: string;
|
||||
name: string;
|
||||
modifier: string;
|
||||
match: string;
|
||||
proxyPass: string;
|
||||
proxyHost: string;
|
||||
filePath?: string;
|
||||
replaces?: ProxReplace;
|
||||
}
|
||||
|
||||
interface ProxReplace {
|
||||
[key: string]: string;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import http from '@/api';
|
||||
import { ReqPage, ResPage } from '../interface';
|
||||
import { Website } from '../interface/Website';
|
||||
import { Website } from '../interface/website';
|
||||
import { File } from '../interface/file';
|
||||
|
||||
export const SearchWebsites = (req: Website.WebSiteSearch) => {
|
||||
@ -186,3 +186,11 @@ export const UpdateWebsiteDir = (req: Website.DirUpdate) => {
|
||||
export const UpdateWebsiteDirPermission = (req: Website.DirPermissionUpdate) => {
|
||||
return http.post<any>(`/websites/dir/permission`, req);
|
||||
};
|
||||
|
||||
export const GetProxyConfig = (req: Website.ProxyReq) => {
|
||||
return http.post<Website.ProxyConfig[]>(`/websites/proxies`, req);
|
||||
};
|
||||
|
||||
export const CreateProxyConfig = (req: Website.ProxyReq) => {
|
||||
return http.post<any>(`/websites/proxies/update`, req);
|
||||
};
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { CompressType } from '@/enums/files';
|
||||
import i18n from '@/lang';
|
||||
|
||||
export const Mimetypes = new Map([
|
||||
['application/zip', CompressType.Zip],
|
||||
@ -110,3 +111,13 @@ export const Rewrites = [
|
||||
'shopex',
|
||||
'zblog',
|
||||
];
|
||||
|
||||
export const Units = [
|
||||
{ label: i18n.global.t('commons.units.second'), value: 's' },
|
||||
{ label: i18n.global.t('commons.units.miniute'), value: 'm' },
|
||||
{ label: i18n.global.t('commons.units.hour'), value: 'h' },
|
||||
{ label: i18n.global.t('commons.units.day'), value: 'd' },
|
||||
{ label: i18n.global.t('commons.units.week'), value: 'w' },
|
||||
{ label: i18n.global.t('commons.units.month'), value: 'M' },
|
||||
{ label: i18n.global.t('commons.units.year'), value: 'Y' },
|
||||
];
|
||||
|
@ -201,6 +201,15 @@ const message = {
|
||||
normal: '正常',
|
||||
building: '制作镜像中',
|
||||
},
|
||||
units: {
|
||||
second: '秒',
|
||||
miniute: '分钟',
|
||||
hour: '小时',
|
||||
day: '天',
|
||||
week: '周',
|
||||
month: '月',
|
||||
year: '年',
|
||||
},
|
||||
},
|
||||
menu: {
|
||||
home: '概览',
|
||||
@ -1174,6 +1183,17 @@ const message = {
|
||||
userGroup: '运行用户/组',
|
||||
user: '用户',
|
||||
uGroup: '用户组',
|
||||
addProxy: '添加反向代理',
|
||||
proxyPath: '代理目录',
|
||||
proxyPass: '目标URL',
|
||||
cache: '缓存',
|
||||
status: '状态',
|
||||
createProxy: '创建反向代理',
|
||||
editProxy: '编辑反向代理',
|
||||
cacheTime: '缓存时间',
|
||||
enableCache: '开启缓存',
|
||||
proxyHost: '发送域名',
|
||||
disabled: '已停止',
|
||||
},
|
||||
php: {
|
||||
short_open_tag: '短标签支持',
|
||||
|
@ -34,7 +34,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Website } from '@/api/interface/Website';
|
||||
import { Website } from '@/api/interface/website';
|
||||
import { RenewSSL } from '@/api/modules/website';
|
||||
import i18n from '@/lang';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
|
@ -12,14 +12,17 @@
|
||||
<el-tab-pane :label="$t('website.rate')">
|
||||
<LimitConn :id="id" v-if="tabIndex == '3'"></LimitConn>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('website.proxy')">
|
||||
<Proxy :id="id" v-if="tabIndex == '4'"></Proxy>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="'HTTPS'">
|
||||
<HTTPS :id="id" v-if="tabIndex == '4'"></HTTPS>
|
||||
<HTTPS :id="id" v-if="tabIndex == '5'"></HTTPS>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('website.rewrite')">
|
||||
<Rewrite :id="id" v-if="tabIndex == '5'"></Rewrite>
|
||||
<Rewrite :id="id" v-if="tabIndex == '6'"></Rewrite>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('website.other')">
|
||||
<Other :id="id" v-if="tabIndex == '6'"></Other>
|
||||
<Other :id="id" v-if="tabIndex == '7'"></Other>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
@ -34,6 +37,7 @@ import Other from './other/index.vue';
|
||||
import HTTPS from './https/index.vue';
|
||||
import SitePath from './site-folder/index.vue';
|
||||
import Rewrite from './rewrite/index.vue';
|
||||
import Proxy from './proxy/index.vue';
|
||||
|
||||
const props = defineProps({
|
||||
id: {
|
||||
@ -41,11 +45,9 @@ const props = defineProps({
|
||||
default: -1,
|
||||
},
|
||||
});
|
||||
|
||||
const id = computed(() => {
|
||||
return props.id;
|
||||
});
|
||||
|
||||
const tabIndex = ref('0');
|
||||
|
||||
onMounted(() => {});
|
||||
|
@ -0,0 +1,130 @@
|
||||
<template>
|
||||
<el-drawer v-model="open" :close-on-click-modal="false" size="40%" :before-close="handleClose">
|
||||
<template #header>
|
||||
<DrawerHeader :header="$t('website.createProxy')" :back="handleClose" />
|
||||
</template>
|
||||
<el-row v-loading="loading">
|
||||
<el-col :span="22" :offset="1">
|
||||
<el-form ref="proxyForm" label-position="top" :model="proxy" :rules="rules">
|
||||
<el-form-item :label="$t('commons.table.name')" prop="name">
|
||||
<el-input v-model.trim="proxy.name"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('website.proxyPath')" prop="match">
|
||||
<el-input v-model.trim="proxy.match"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('website.enableCache')" prop="cache">
|
||||
<el-switch v-model="proxy.cache"></el-switch>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('website.cacheTime')" prop="cacheTime" v-if="proxy.cache">
|
||||
<el-input v-model.number="proxy.cacheTime" maxlength="15">
|
||||
<template #append>
|
||||
<el-select v-model="proxy.cacheUnit" style="width: 80px">
|
||||
<el-option
|
||||
v-for="(unit, index) in Units"
|
||||
:key="index"
|
||||
:label="unit.label"
|
||||
:value="unit.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('website.proxyPass')" prop="proxyPass">
|
||||
<el-input v-model.trim="proxy.proxyPass"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('website.proxyHost')" prop="proxyHost">
|
||||
<el-input v-model.trim="proxy.proxyHost"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="submit(proxyForm)" :disabled="loading">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { CreateProxyConfig } from '@/api/modules/website';
|
||||
import { checkNumberRange, Rules } from '@/global/form-rules';
|
||||
import i18n from '@/lang';
|
||||
import { FormInstance } from 'element-plus';
|
||||
import { ref } from 'vue';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { Website } from '@/api/interface/website';
|
||||
import { Units } from '@/global/mimetype';
|
||||
// import { Website } from '@/api/interface/website';
|
||||
|
||||
const proxyForm = ref<FormInstance>();
|
||||
const rules = ref({
|
||||
name: [Rules.requiredInput, Rules.appName],
|
||||
match: [Rules.requiredInput],
|
||||
cacheTime: [Rules.requiredInput, checkNumberRange(1, 65535)],
|
||||
proxyPass: [Rules.requiredInput],
|
||||
proxyHost: [Rules.requiredInput],
|
||||
});
|
||||
const open = ref(false);
|
||||
const loading = ref(false);
|
||||
|
||||
const initData = (): Website.ProxyConfig => ({
|
||||
id: 0,
|
||||
operate: 'create',
|
||||
enable: true,
|
||||
cache: false,
|
||||
cacheTime: 1,
|
||||
cacheUnit: 'm',
|
||||
name: '',
|
||||
modifier: '^~',
|
||||
match: '/',
|
||||
proxyPass: 'http://',
|
||||
proxyHost: '$host',
|
||||
filePath: '',
|
||||
});
|
||||
let proxy = ref(initData());
|
||||
|
||||
const em = defineEmits(['close']);
|
||||
const handleClose = () => {
|
||||
proxyForm.value?.resetFields();
|
||||
open.value = false;
|
||||
em('close', false);
|
||||
};
|
||||
|
||||
const acceptParams = async (proxyParam: Website.ProxyConfig) => {
|
||||
proxy.value = proxyParam;
|
||||
open.value = true;
|
||||
};
|
||||
|
||||
const submit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid) => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
loading.value = true;
|
||||
CreateProxyConfig(proxy.value)
|
||||
.then(() => {
|
||||
MsgSuccess(i18n.global.t('commons.msg.createSuccess'));
|
||||
handleClose();
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<ComplexTable :data="data" @search="search" v-loading="loading">
|
||||
<template #toolbar>
|
||||
<el-button type="primary" plain @click="openCreate">{{ $t('website.addProxy') }}</el-button>
|
||||
</template>
|
||||
<el-table-column :label="$t('commons.table.name')" prop="name"></el-table-column>
|
||||
<el-table-column :label="$t('website.proxyPath')" prop="match"></el-table-column>
|
||||
<el-table-column :label="$t('website.proxyPass')" prop="proxyPass"></el-table-column>
|
||||
<el-table-column :label="$t('website.cache')" prop="cache">
|
||||
<template #default="{ row }">
|
||||
<el-switch v-model="row.cache"></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('commons.table.status')" prop="enable">
|
||||
<template #default="{ row }">
|
||||
<el-button v-if="row.enable" link type="success" :icon="VideoPlay">
|
||||
{{ $t('commons.status.running') }}
|
||||
</el-button>
|
||||
<el-button v-else link type="danger" :icon="VideoPause">
|
||||
{{ $t('commons.status.stopped') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ComplexTable>
|
||||
<Create ref="createRef" @close="search()" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup name="proxy">
|
||||
import { Website } from '@/api/interface/website';
|
||||
import { GetProxyConfig } from '@/api/modules/website';
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import Create from './create/index.vue';
|
||||
import { VideoPlay, VideoPause } from '@element-plus/icons-vue';
|
||||
|
||||
const props = defineProps({
|
||||
id: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
const id = computed(() => {
|
||||
return props.id;
|
||||
});
|
||||
const loading = ref(false);
|
||||
const data = ref();
|
||||
const createRef = ref();
|
||||
|
||||
const initData = (id: number): Website.ProxyConfig => ({
|
||||
id: id,
|
||||
operate: 'create',
|
||||
enable: true,
|
||||
cache: false,
|
||||
cacheTime: 1,
|
||||
cacheUnit: 'm',
|
||||
name: '',
|
||||
modifier: '^~',
|
||||
match: '/',
|
||||
proxyPass: 'http://',
|
||||
proxyHost: '$host',
|
||||
});
|
||||
|
||||
const openCreate = () => {
|
||||
createRef.value.acceptParams(initData(id.value));
|
||||
};
|
||||
const search = async () => {
|
||||
try {
|
||||
loading.value = true;
|
||||
const res = await GetProxyConfig({ id: id.value });
|
||||
data.value = res.data || [];
|
||||
} catch (error) {
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
search();
|
||||
});
|
||||
</script>
|
@ -38,7 +38,7 @@
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { Website } from '@/api/interface/Website';
|
||||
import { Website } from '@/api/interface/website';
|
||||
import { ChangeDefaultServer, ListWebsites } from '@/api/modules/website';
|
||||
import i18n from '@/lang';
|
||||
import { ref } from 'vue';
|
||||
|
Loading…
Reference in New Issue
Block a user