2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 14:57:16 +08:00
Files
panel/pkg/webserver/nginx/setter.go
2025-12-01 16:29:37 +08:00

598 lines
15 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package nginx
import (
"fmt"
"slices"
"strings"
"github.com/tufanbarisyildirim/gonginx/config"
)
func (p *Parser) SetListen(listen [][]string) error {
var directives []*config.Directive
for _, l := range listen {
directives = append(directives, &config.Directive{
Name: "listen",
Parameters: p.slices2Parameters(l),
})
}
if err := p.Clear("server.listen"); err != nil {
return err
}
return p.Set("server", directives)
}
func (p *Parser) SetServerName(serverName []string) error {
if err := p.Clear("server.server_name"); err != nil {
return err
}
return p.Set("server", []*config.Directive{
{
Name: "server_name",
Parameters: p.slices2Parameters(serverName),
},
})
}
func (p *Parser) SetIndex(index []string) error {
if err := p.Clear("server.index"); err != nil {
return err
}
return p.Set("server", []*config.Directive{
{
Name: "index",
Parameters: p.slices2Parameters(index),
},
})
}
func (p *Parser) SetIndexWithComment(index []string, comment []string) error {
if err := p.Clear("server.index"); err != nil {
return err
}
return p.Set("server", []*config.Directive{
{
Name: "index",
Parameters: p.slices2Parameters(index),
Comment: comment,
},
})
}
func (p *Parser) SetRoot(root string) error {
if err := p.Clear("server.root"); err != nil {
return err
}
return p.Set("server", []*config.Directive{
{
Name: "root",
Parameters: []config.Parameter{{Value: root}},
},
})
}
func (p *Parser) SetRootWithComment(root string, comment []string) error {
if err := p.Clear("server.root"); err != nil {
return err
}
return p.Set("server", []*config.Directive{
{
Name: "root",
Parameters: []config.Parameter{{Value: root}},
Comment: comment,
},
})
}
func (p *Parser) SetIncludes(includes []string, comments [][]string) error {
if err := p.Clear("server.include"); err != nil {
return err
}
var directives []*config.Directive
for i, item := range includes {
var comment []string
if i < len(comments) {
comment = comments[i]
}
directives = append(directives, &config.Directive{
Name: "include",
Parameters: []config.Parameter{{Value: item}},
Comment: comment,
})
}
return p.Set("server", directives)
}
func (p *Parser) SetPHP(php int) error {
old, err := p.Find("server.include")
if err != nil {
return err
}
if err = p.Clear("server.include"); err != nil {
return err
}
var directives []*config.Directive
var foundFlag bool
for _, item := range old {
// 查找enable-php的配置
if slices.ContainsFunc(p.parameters2Slices(item.GetParameters()), func(s string) bool {
return strings.HasPrefix(s, "enable-php-") && strings.HasSuffix(s, ".conf")
}) {
foundFlag = true
directives = append(directives, &config.Directive{
Name: item.GetName(),
Parameters: []config.Parameter{{Value: fmt.Sprintf("enable-php-%d.conf", php)}},
Comment: item.GetComment(),
})
} else {
// 其余的原样保留
directives = append(directives, &config.Directive{
Name: item.GetName(),
Parameters: item.GetParameters(),
Comment: item.GetComment(),
})
}
}
// 如果没有找到enable-php的配置直接添加一个
if !foundFlag {
directives = append(directives, &config.Directive{
Name: "include",
Parameters: []config.Parameter{{Value: fmt.Sprintf("enable-php-%d.conf", php)}},
})
}
return p.Set("server", directives)
}
func (p *Parser) ClearHTTPS() error {
if err := p.Clear("server.ssl_certificate"); err != nil {
return err
}
if err := p.Clear("server.ssl_certificate_key"); err != nil {
return err
}
if err := p.Clear("server.ssl_session_timeout"); err != nil {
return err
}
if err := p.Clear("server.ssl_session_cache"); err != nil {
return err
}
if err := p.Clear("server.ssl_protocols"); err != nil {
return err
}
if err := p.Clear("server.ssl_ciphers"); err != nil {
return err
}
if err := p.Clear("server.ssl_prefer_server_ciphers"); err != nil {
return err
}
if err := p.Clear("server.ssl_early_data"); err != nil {
return err
}
return nil
}
func (p *Parser) SetHTTPSCert(cert, key string) error {
if err := p.ClearHTTPS(); err != nil {
return err
}
return p.Set("server", []*config.Directive{
{
Name: "ssl_certificate",
Parameters: []config.Parameter{{Value: cert}},
},
{
Name: "ssl_certificate_key",
Parameters: []config.Parameter{{Value: key}},
},
{
Name: "ssl_session_timeout",
Parameters: []config.Parameter{{Value: "1d"}},
},
{
Name: "ssl_session_cache",
Parameters: []config.Parameter{{Value: "shared:SSL:10m"}},
},
{
Name: "ssl_protocols",
Parameters: []config.Parameter{{Value: "TLSv1.2"}, {Value: "TLSv1.3"}},
},
{
Name: "ssl_ciphers",
Parameters: []config.Parameter{{Value: "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305"}},
},
{
Name: "ssl_prefer_server_ciphers",
Parameters: []config.Parameter{{Value: "off"}},
},
{
Name: "ssl_early_data",
Parameters: []config.Parameter{{Value: "on"}},
},
}, "root")
}
func (p *Parser) SetHTTPSProtocols(protocols []string) error {
if err := p.Clear("server.ssl_protocols"); err != nil {
return err
}
return p.Set("server", []*config.Directive{
{
Name: "ssl_protocols",
Parameters: p.slices2Parameters(protocols),
},
})
}
func (p *Parser) SetHTTPSCiphers(ciphers string) error {
if err := p.Clear("server.ssl_ciphers"); err != nil {
return err
}
return p.Set("server", []*config.Directive{
{
Name: "ssl_ciphers",
Parameters: []config.Parameter{{Value: ciphers}},
},
})
}
func (p *Parser) SetOCSP(ocsp bool) error {
if err := p.Clear("server.ssl_stapling"); err != nil {
return err
}
if err := p.Clear("server.ssl_stapling_verify"); err != nil {
return err
}
if ocsp {
return p.Set("server", []*config.Directive{
{
Name: "ssl_stapling",
Parameters: []config.Parameter{{Value: "on"}},
},
{
Name: "ssl_stapling_verify",
Parameters: []config.Parameter{{Value: "on"}},
},
})
}
return nil
}
func (p *Parser) SetHSTS(hsts bool) error {
old, err := p.Find("server.add_header")
if err != nil {
return err
}
if err = p.Clear("server.add_header"); err != nil {
return err
}
var directives []*config.Directive
var foundFlag bool
for _, dir := range old {
if slices.Contains(p.parameters2Slices(dir.GetParameters()), "Strict-Transport-Security") {
foundFlag = true
if hsts {
directives = append(directives, &config.Directive{
Name: dir.GetName(),
Parameters: []config.Parameter{{Value: "Strict-Transport-Security"}, {Value: "max-age=31536000"}},
Comment: dir.GetComment(),
})
}
} else {
directives = append(directives, &config.Directive{
Name: dir.GetName(),
Parameters: dir.GetParameters(),
Comment: dir.GetComment(),
})
}
}
if !foundFlag && hsts {
directives = append(directives, &config.Directive{
Name: "add_header",
Parameters: []config.Parameter{{Value: "Strict-Transport-Security"}, {Value: "max-age=31536000"}},
})
}
return p.Set("server", directives)
}
func (p *Parser) SetHTTPSRedirect(httpRedirect bool) error {
// if 重定向
ifs, err := p.Find("server.if")
if err != nil {
return err
}
if err = p.Clear("server.if"); err != nil {
return err
}
var directives []*config.Directive
var foundFlag bool
for _, dir := range ifs { // 所有 if
if !httpRedirect {
if len(dir.GetParameters()) == 3 && dir.GetParameters()[0].GetValue() == "($scheme" && dir.GetParameters()[1].GetValue() == "=" && dir.GetParameters()[2].GetValue() == "http)" {
continue
}
}
var ifDirectives []config.IDirective
for _, dir2 := range dir.GetBlock().GetDirectives() { // 每个 if 中所有指令
if !httpRedirect {
// 不启用http重定向则判断并移除特定的return指令
if dir2.GetName() != "return" && !slices.Contains(p.parameters2Slices(dir2.GetParameters()), "https://$host$request_uri") {
ifDirectives = append(ifDirectives, dir2)
}
} else {
// 启用http重定向需要检查防止重复添加
if dir2.GetName() == "return" && slices.Contains(p.parameters2Slices(dir2.GetParameters()), "https://$host$request_uri") {
foundFlag = true
}
ifDirectives = append(ifDirectives, dir2)
}
}
// 写回 if 指令
if block, ok := dir.GetBlock().(*config.Block); ok {
block.Directives = ifDirectives
}
directives = append(directives, &config.Directive{
Block: dir.GetBlock(),
Name: dir.GetName(),
Parameters: dir.GetParameters(),
Comment: dir.GetComment(),
})
}
if !foundFlag && httpRedirect {
ifDir := &config.Directive{
Name: "if",
Block: &config.Block{},
Parameters: []config.Parameter{{Value: "($scheme"}, {Value: "="}, {Value: "http)"}},
}
redirectDir := &config.Directive{
Name: "return",
Parameters: []config.Parameter{{Value: "308"}, {Value: "https://$host$request_uri"}},
}
redirectDir.SetParent(ifDir.GetParent())
ifBlock := ifDir.GetBlock().(*config.Block)
ifBlock.Directives = append(ifBlock.Directives, redirectDir)
directives = append(directives, ifDir)
}
if err = p.Set("server", directives); err != nil {
return err
}
// error_page 497 重定向
directives = nil
errorPages, err := p.Find("server.error_page")
if err != nil {
return err
}
if err = p.Clear("server.error_page"); err != nil {
return err
}
var found497 bool
for _, dir := range errorPages {
if !httpRedirect {
// 不启用https重定向则判断并移除特定的return指令
if !slices.Contains(p.parameters2Slices(dir.GetParameters()), "497") && !slices.Contains(p.parameters2Slices(dir.GetParameters()), "https://$host:$server_port$request_uri") {
directives = append(directives, &config.Directive{
Block: dir.GetBlock(),
Name: dir.GetName(),
Parameters: dir.GetParameters(),
Comment: dir.GetComment(),
})
}
} else {
// 启用https重定向需要检查防止重复添加
if slices.Contains(p.parameters2Slices(dir.GetParameters()), "497") && slices.Contains(p.parameters2Slices(dir.GetParameters()), "https://$host:$server_port$request_uri") {
found497 = true
}
directives = append(directives, &config.Directive{
Block: dir.GetBlock(),
Name: dir.GetName(),
Parameters: dir.GetParameters(),
Comment: dir.GetComment(),
})
}
}
if !found497 && httpRedirect {
directives = append(directives, &config.Directive{
Name: "error_page",
Parameters: []config.Parameter{{Value: "497"}, {Value: "=308"}, {Value: "https://$host:$server_port$request_uri"}},
})
}
return p.Set("server", directives)
}
func (p *Parser) SetAltSvc(altSvc string) error {
old, err := p.Find("server.add_header")
if err != nil {
return err
}
if err = p.Clear("server.add_header"); err != nil {
return err
}
var directives []*config.Directive
var foundFlag bool
for _, dir := range old {
if slices.Contains(p.parameters2Slices(dir.GetParameters()), "Alt-Svc") {
foundFlag = true
if altSvc != "" { // 为空表示要删除
directives = append(directives, &config.Directive{
Name: dir.GetName(),
Parameters: []config.Parameter{{Value: "Alt-Svc"}, {Value: altSvc}},
Comment: dir.GetComment(),
})
}
} else {
directives = append(directives, &config.Directive{
Name: dir.GetName(),
Parameters: dir.GetParameters(),
Comment: dir.GetComment(),
})
}
}
if !foundFlag && altSvc != "" {
directives = append(directives, &config.Directive{
Name: "add_header",
Parameters: []config.Parameter{{Value: "Alt-Svc"}, {Value: altSvc}},
})
}
return p.Set("server", directives)
}
func (p *Parser) SetAccessLog(accessLog string) error {
if err := p.Clear("server.access_log"); err != nil {
return err
}
return p.Set("server", []*config.Directive{
{
Name: "access_log",
Parameters: []config.Parameter{{Value: accessLog}},
},
})
}
func (p *Parser) SetErrorLog(errorLog string) error {
if err := p.Clear("server.error_log"); err != nil {
return err
}
return p.Set("server", []*config.Directive{
{
Name: "error_log",
Parameters: []config.Parameter{{Value: errorLog}},
},
})
}
// SetReturn 设置 return 指令(用于禁用网站)
func (p *Parser) SetReturn(code, url string) error {
_ = p.Clear("server.return") // 忽略不存在的错误
directives := []*config.Directive{
{
Name: "return",
Parameters: []config.Parameter{{Value: code}, {Value: url}},
},
}
// 在 server 块的最开始插入 return 指令
// 获取 server 块
serverDirs := p.cfg.Block.FindDirectives("server")
if len(serverDirs) == 0 {
return fmt.Errorf("server block not found")
}
serverBlock, ok := serverDirs[0].GetBlock().(*config.Block)
if !ok {
return fmt.Errorf("server block is not *config.Block")
}
// 设置父节点
for _, d := range directives {
d.SetParent(serverDirs[0])
}
// 在开头插入
newDirectives := make([]config.IDirective, 0, len(directives)+len(serverBlock.Directives))
for _, d := range directives {
newDirectives = append(newDirectives, d)
}
newDirectives = append(newDirectives, serverBlock.Directives...)
serverBlock.Directives = newDirectives
return nil
}
// SetLimitRate 设置限速配置
func (p *Parser) SetLimitRate(limitRate string) error {
_ = p.Clear("server.limit_rate") // 忽略不存在的错误
if limitRate == "" {
return nil // 清除限速配置
}
return p.Set("server", []*config.Directive{
{
Name: "limit_rate",
Parameters: []config.Parameter{{Value: limitRate}},
},
})
}
// SetLimitConn 设置并发连接数限制
func (p *Parser) SetLimitConn(limitConn [][]string) error {
if err := p.Clear("server.limit_conn"); err != nil {
// 忽略不存在的错误
}
if len(limitConn) == 0 {
return nil // 清除限流配置
}
var directives []*config.Directive
for _, limit := range limitConn {
if len(limit) >= 2 {
directives = append(directives, &config.Directive{
Name: "limit_conn",
Parameters: p.slices2Parameters(limit),
})
}
}
return p.Set("server", directives)
}
// SetBasicAuth 设置基本认证
func (p *Parser) SetBasicAuth(realm, userFile string) error {
// 清除现有配置
if err := p.Clear("server.auth_basic"); err != nil {
// 忽略不存在的错误
}
if err := p.Clear("server.auth_basic_user_file"); err != nil {
// 忽略不存在的错误
}
// 如果 realm 为空,表示禁用基本认证
if realm == "" || userFile == "" {
return nil
}
return p.Set("server", []*config.Directive{
{
Name: "auth_basic",
Parameters: []config.Parameter{{Value: realm}},
},
{
Name: "auth_basic_user_file",
Parameters: []config.Parameter{{Value: userFile}},
},
})
}