mirror of
https://github.com/tnb-labs/panel.git
synced 2026-10-16 07:21:35 +08:00
docs: 清掉复述代码的注释
删的是只把标识符名翻译一遍的注释和 ===== 分隔线, 带条件、原因、格式示例的都留着。顺带把 Apache 的全局监听文件命名为 listen.conf。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -22,7 +22,6 @@ func Supported() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// kernelVersion 返回形如 6.12.0 的内核版本
|
||||
func kernelVersion() string {
|
||||
var uts unix.Utsname
|
||||
if err := unix.Uname(&uts); err != nil {
|
||||
@@ -31,7 +30,6 @@ func kernelVersion() string {
|
||||
return string(uts.Release[:bytes.IndexByte(uts.Release[:], 0)])
|
||||
}
|
||||
|
||||
// kernelAtLeast 判断内核是否 >= major.minor
|
||||
func kernelAtLeast(major, minor int) bool {
|
||||
v := kernelVersion()
|
||||
parts := strings.SplitN(v, ".", 3)
|
||||
@@ -57,7 +55,6 @@ func kernelAtLeast(major, minor int) bool {
|
||||
return minNum >= minor
|
||||
}
|
||||
|
||||
// activeLSM 读取当前激活的 LSM 列表
|
||||
func activeLSM() string {
|
||||
data, err := os.ReadFile("/sys/kernel/security/lsm")
|
||||
if err != nil {
|
||||
@@ -66,7 +63,6 @@ func activeLSM() string {
|
||||
return strings.TrimSpace(string(data))
|
||||
}
|
||||
|
||||
// DetectEBPF 检测 eBPF-LSM 模式可用性
|
||||
func DetectEBPF() EBPFStatus {
|
||||
st := EBPFStatus{
|
||||
KernelVersion: kernelVersion(),
|
||||
@@ -95,7 +91,6 @@ func DetectEBPF() EBPFStatus {
|
||||
return st
|
||||
}
|
||||
|
||||
// grubCmdlineRe 匹配 grub 的内核命令行配置项
|
||||
var grubCmdlineRe = regexp.MustCompile(`(?m)^(GRUB_CMDLINE_LINUX(?:_DEFAULT)?=)"([^"]*)"`)
|
||||
|
||||
// injectLSMBpf 在 grub 内核命令行中注入 bpf LSM
|
||||
|
||||
@@ -40,7 +40,6 @@ func waitEvent(ch <-chan Event, want func(Event) bool) *Event {
|
||||
}
|
||||
}
|
||||
|
||||
// requireEBPF 跳过无法跑 eBPF 全功能测试的环境
|
||||
func requireEBPF(t *testing.T) {
|
||||
t.Helper()
|
||||
if os.Geteuid() != 0 {
|
||||
|
||||
@@ -131,7 +131,6 @@ func cachedMountDevs() []mountDev {
|
||||
return m
|
||||
}
|
||||
|
||||
// refreshMountDevs 强制刷新缓存
|
||||
func refreshMountDevs() {
|
||||
mountsMu.Lock()
|
||||
mounts = loadMountDevs()
|
||||
|
||||
@@ -39,7 +39,6 @@ func ExcludeMatches(ex, path string) bool {
|
||||
return slices.Contains(strings.Split(path, string(os.PathSeparator)), ex)
|
||||
}
|
||||
|
||||
// isExcluded 判断路径是否落在排除项内
|
||||
func isExcluded(path string, excludes []string) bool {
|
||||
for _, ex := range excludes {
|
||||
if ExcludeMatches(ex, path) {
|
||||
|
||||
@@ -33,7 +33,6 @@ func tryWrite(path string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// chattrSupported 检测当前文件系统是否支持 immutable 属性
|
||||
func chattrSupported(dir string) bool {
|
||||
p := filepath.Join(dir, ".chattr_probe")
|
||||
if err := os.WriteFile(p, []byte("x"), 0644); err != nil {
|
||||
|
||||
@@ -23,7 +23,6 @@ func EnableBPFLSMGrub(_ context.Context) error {
|
||||
return errors.New("only supported on Linux")
|
||||
}
|
||||
|
||||
// Manager 非 Linux 占位
|
||||
type Manager struct{}
|
||||
|
||||
// NewManager 非 Linux 平台不支持
|
||||
|
||||
@@ -1,22 +1,17 @@
|
||||
package apache
|
||||
|
||||
// ServerRoot 安装目录
|
||||
const ServerRoot = "/opt/ace/server/apache"
|
||||
|
||||
// HTMLDir 默认页目录
|
||||
const HTMLDir = ServerRoot + "/htdocs"
|
||||
|
||||
// DisablePage 禁用页面路径
|
||||
const DisablePage = HTMLDir + "/stop.html"
|
||||
|
||||
// SitesPath 网站目录
|
||||
const SitesPath = "/opt/ace/sites"
|
||||
|
||||
// ConfigName 站点配置文件名
|
||||
const ConfigName = "apache.conf"
|
||||
|
||||
// ListenConf 面板维护的全局监听配置,放在 Apache 的 conf/extra 下
|
||||
const ListenConf = "ace-listen.conf"
|
||||
// ListenConf 面板维护的全局监听配置,装的是 Listen 指令
|
||||
const ListenConf = "listen.conf"
|
||||
|
||||
// HSTSValue 是 HSTS 响应头的默认 max-age(1 年)
|
||||
const HSTSValue = "max-age=31536000"
|
||||
@@ -32,7 +27,6 @@ const (
|
||||
ProxyEndNum = 299
|
||||
)
|
||||
|
||||
// DefaultVhostConf 默认配置模板
|
||||
const DefaultVhostConf = `# Auto-generated by AcePanel. DO NOT EDIT MANUALLY!
|
||||
IncludeOptional /opt/ace/sites/default/config/shared/*.conf
|
||||
<VirtualHost *:80>
|
||||
@@ -49,7 +43,6 @@ IncludeOptional /opt/ace/sites/default/config/shared/*.conf
|
||||
</VirtualHost>
|
||||
`
|
||||
|
||||
// order 定义 Apache 指令的排序优先级
|
||||
var order = map[string]int{
|
||||
"Listen": 0,
|
||||
"ServerName": 1,
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
"github.com/acepanel/panel/v3/pkg/webserver/types"
|
||||
)
|
||||
|
||||
// panelTokenDir 面板证书验证的 token 目录
|
||||
const panelTokenDir = "/tmp/acme-challenge"
|
||||
|
||||
const phpCacheConf = `# browser cache
|
||||
@@ -50,7 +49,6 @@ const spaConf = `# single-page application route fallback, remove if not needed
|
||||
FallbackResource /index.html
|
||||
`
|
||||
|
||||
// Dialect Apache 方言
|
||||
type Dialect struct{}
|
||||
|
||||
func (Dialect) Service() string {
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/acepanel/panel/v3/pkg/webserver/conf"
|
||||
)
|
||||
|
||||
// ParseOptions 控制解析行为
|
||||
type ParseOptions struct {
|
||||
// Tolerant 容错模式:遇到结构错误(孤立闭合标签、未闭合块)记录后尽力继续,不致命
|
||||
Tolerant bool
|
||||
@@ -33,7 +32,6 @@ func ParseFragment(content string) (*conf.Config, error) {
|
||||
return parse(content, ParseOptions{Tolerant: true})
|
||||
}
|
||||
|
||||
// parse 将配置文本解析为 AST
|
||||
func parse(content string, opts ParseOptions) (*conf.Config, error) {
|
||||
p := &parser{lines: scanLogicalLines(content), opts: opts}
|
||||
nodes, err := p.parseNodes("")
|
||||
|
||||
@@ -257,7 +257,6 @@ func TestAddDirectiveAutoQuote(t *testing.T) {
|
||||
check.NotContains(t, out, `"`)
|
||||
}
|
||||
|
||||
// collectComments 递归收集节点树中的所有注释
|
||||
func collectComments(nodes []conf.Node) []*conf.Comment {
|
||||
var out []*conf.Comment
|
||||
for _, n := range nodes {
|
||||
|
||||
@@ -46,10 +46,8 @@ func parseDurationToSeconds(duration string) int {
|
||||
// proxyFilePattern 匹配代理配置文件名 (200-299)
|
||||
var proxyFilePattern = regexp.MustCompile(`^(\d{3})-proxy\.conf$`)
|
||||
|
||||
// balancerFilePattern 匹配负载均衡配置文件名
|
||||
var balancerFilePattern = regexp.MustCompile(`^(\d{3})-balancer-(.+)\.conf$`)
|
||||
|
||||
// parseProxyFiles 从 site 目录解析所有代理配置
|
||||
func parseProxyFiles(siteDir string) ([]types.Proxy, error) {
|
||||
entries, err := os.ReadDir(siteDir)
|
||||
if err != nil {
|
||||
@@ -87,7 +85,6 @@ func parseProxyFiles(siteDir string) ([]types.Proxy, error) {
|
||||
return proxies, nil
|
||||
}
|
||||
|
||||
// parseProxyFile 解析单个代理配置文件为结构体(基于 AST 遍历)
|
||||
func parseProxyFile(filePath string) (*types.Proxy, error) {
|
||||
content, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
@@ -178,7 +175,6 @@ func parseProxyFile(filePath string) (*types.Proxy, error) {
|
||||
return proxy, nil
|
||||
}
|
||||
|
||||
// parseCacheBlock 从 mod_cache 块提取缓存配置
|
||||
func parseCacheBlock(blk *conf.Directive) *types.CacheConfig {
|
||||
cache := &types.CacheConfig{
|
||||
Valid: make(map[string]string),
|
||||
@@ -211,7 +207,6 @@ func parseSubstitute(rule string) (from, to string, ok bool) {
|
||||
return "", "", false
|
||||
}
|
||||
|
||||
// writeProxyFiles 将代理配置写入文件
|
||||
func writeProxyFiles(siteDir string, proxies []types.Proxy, upstreams []string) error {
|
||||
if err := clearProxyFiles(siteDir); err != nil {
|
||||
return err
|
||||
@@ -232,7 +227,6 @@ func writeProxyFiles(siteDir string, proxies []types.Proxy, upstreams []string)
|
||||
return nil
|
||||
}
|
||||
|
||||
// clearProxyFiles 清除所有代理配置文件
|
||||
func clearProxyFiles(siteDir string) error {
|
||||
entries, err := os.ReadDir(siteDir)
|
||||
if err != nil {
|
||||
@@ -443,7 +437,6 @@ func parseResponseHeaders(blk *conf.Directive) *types.ResponseHeaderConfig {
|
||||
return headers
|
||||
}
|
||||
|
||||
// generateProxyConfig 构建代理配置 AST 并序列化
|
||||
func generateProxyConfig(proxy types.Proxy, upstreams []string) string {
|
||||
loc := parseLocation(proxy.Location)
|
||||
pass := balancerPass(proxy.Pass, upstreams)
|
||||
@@ -611,7 +604,6 @@ func parseBalancerFiles(sharedDir string) ([]types.Upstream, error) {
|
||||
return upstreams, nil
|
||||
}
|
||||
|
||||
// parseBalancerFile 解析单个负载均衡配置文件为结构体(基于 AST 遍历)
|
||||
func parseBalancerFile(filePath string, name string) (*types.Upstream, error) {
|
||||
content, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
@@ -760,7 +752,6 @@ func balancerNames(sharedDir string) []string {
|
||||
return names
|
||||
}
|
||||
|
||||
// writeBalancerFiles 将负载均衡配置写入文件
|
||||
func writeBalancerFiles(sharedDir string, upstreams []types.Upstream) error {
|
||||
if err := clearBalancerFiles(sharedDir); err != nil {
|
||||
return err
|
||||
@@ -777,7 +768,6 @@ func writeBalancerFiles(sharedDir string, upstreams []types.Upstream) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// clearBalancerFiles 清除所有负载均衡配置文件
|
||||
func clearBalancerFiles(sharedDir string) error {
|
||||
entries, err := os.ReadDir(sharedDir)
|
||||
if err != nil {
|
||||
@@ -802,7 +792,6 @@ func clearBalancerFiles(sharedDir string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// generateBalancerConfig 构建负载均衡配置 AST 并序列化
|
||||
func generateBalancerConfig(upstream types.Upstream) string {
|
||||
proxy := conf.Blk("Proxy", "balancer://"+upstream.Name)
|
||||
for _, addr := range slices.Sorted(maps.Keys(upstream.Servers)) {
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
// redirectFilePattern 匹配重定向配置文件名 (100-199)
|
||||
var redirectFilePattern = regexp.MustCompile(`^(\d{3})-redirect\.conf$`)
|
||||
|
||||
// parseRedirectFiles 从 site 目录解析所有重定向配置
|
||||
func parseRedirectFiles(siteDir string) ([]types.Redirect, error) {
|
||||
entries, err := os.ReadDir(siteDir)
|
||||
if err != nil {
|
||||
@@ -53,7 +52,6 @@ func parseRedirectFiles(siteDir string) ([]types.Redirect, error) {
|
||||
return redirects, nil
|
||||
}
|
||||
|
||||
// parseRedirectFile 解析单个重定向配置文件为结构体(基于 AST 遍历)
|
||||
func parseRedirectFile(filePath string) (*types.Redirect, error) {
|
||||
content, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
@@ -155,7 +153,6 @@ func parseRewriteStatus(flag string) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// writeRedirectFiles 将重定向配置写入文件
|
||||
func writeRedirectFiles(siteDir string, redirects []types.Redirect) error {
|
||||
if err := clearRedirectFiles(siteDir); err != nil {
|
||||
return err
|
||||
@@ -176,7 +173,6 @@ func writeRedirectFiles(siteDir string, redirects []types.Redirect) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// clearRedirectFiles 清除所有重定向配置文件
|
||||
func clearRedirectFiles(siteDir string) error {
|
||||
entries, err := os.ReadDir(siteDir)
|
||||
if err != nil {
|
||||
@@ -207,7 +203,6 @@ func clearRedirectFiles(siteDir string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// generateRedirectConfig 构建重定向配置 AST 并序列化
|
||||
func generateRedirectConfig(redirect types.Redirect) string {
|
||||
statusCode := redirect.StatusCode
|
||||
if statusCode == 0 {
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"github.com/libtnb/assert/must"
|
||||
)
|
||||
|
||||
// realWorldConfig 汇集真实 apache 配置里最难解析的语法
|
||||
const realWorldConfig = `# main config
|
||||
ServerRoot "/etc/httpd"
|
||||
Listen 80
|
||||
|
||||
@@ -15,22 +15,18 @@ import (
|
||||
"github.com/acepanel/panel/v3/pkg/webserver/types"
|
||||
)
|
||||
|
||||
// StaticVhost 纯静态虚拟主机
|
||||
type StaticVhost struct {
|
||||
*baseVhost
|
||||
}
|
||||
|
||||
// PHPVhost PHP 虚拟主机
|
||||
type PHPVhost struct {
|
||||
*baseVhost
|
||||
}
|
||||
|
||||
// ProxyVhost 反向代理虚拟主机
|
||||
type ProxyVhost struct {
|
||||
*baseVhost
|
||||
}
|
||||
|
||||
// baseVhost Apache 虚拟主机基础实现
|
||||
type baseVhost struct {
|
||||
config *conf.Config
|
||||
vhost *conf.Directive // 主 VirtualHost 块,写盘时按端口拆成明文与 TLS 两个块
|
||||
@@ -39,7 +35,6 @@ type baseVhost struct {
|
||||
siteName string
|
||||
}
|
||||
|
||||
// newBaseVhost 创建基础虚拟主机实例
|
||||
func newBaseVhost(configDir string) (*baseVhost, error) {
|
||||
if configDir == "" {
|
||||
return nil, errors.New("config directory is required")
|
||||
@@ -107,12 +102,10 @@ func (v *baseVhost) loadVhosts() {
|
||||
v.vhost = main
|
||||
}
|
||||
|
||||
// defaultConf 返回替换好站点名的默认配置模板
|
||||
func (v *baseVhost) defaultConf() string {
|
||||
return strings.ReplaceAll(DefaultVhostConf, "/opt/ace/sites/default", "/opt/ace/sites/"+v.siteName)
|
||||
}
|
||||
|
||||
// NewStaticVhost 创建纯静态虚拟主机实例
|
||||
func NewStaticVhost(configDir string) (*StaticVhost, error) {
|
||||
base, err := newBaseVhost(configDir)
|
||||
if err != nil {
|
||||
@@ -121,7 +114,6 @@ func NewStaticVhost(configDir string) (*StaticVhost, error) {
|
||||
return &StaticVhost{baseVhost: base}, nil
|
||||
}
|
||||
|
||||
// NewPHPVhost 创建 PHP 虚拟主机实例
|
||||
func NewPHPVhost(configDir string) (*PHPVhost, error) {
|
||||
base, err := newBaseVhost(configDir)
|
||||
if err != nil {
|
||||
@@ -130,7 +122,6 @@ func NewPHPVhost(configDir string) (*PHPVhost, error) {
|
||||
return &PHPVhost{baseVhost: base}, nil
|
||||
}
|
||||
|
||||
// NewProxyVhost 创建反向代理虚拟主机实例
|
||||
func NewProxyVhost(configDir string) (*ProxyVhost, error) {
|
||||
base, err := newBaseVhost(configDir)
|
||||
if err != nil {
|
||||
@@ -526,7 +517,6 @@ func (v *baseVhost) ClearSSL() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// hasPort 判断 VirtualHost 是否监听指定端口
|
||||
func (v *baseVhost) hasPort(port string) bool {
|
||||
return slices.ContainsFunc(v.vhost.Values(), func(addr string) bool {
|
||||
return portOf(addr) == port
|
||||
@@ -673,8 +663,6 @@ func (v *baseVhost) SetRedirects(redirects []types.Redirect) error {
|
||||
return writeRedirectFiles(filepath.Join(v.configDir, "site"), redirects)
|
||||
}
|
||||
|
||||
// ========== PHPVhost ==========
|
||||
|
||||
func (v *PHPVhost) PHP() uint {
|
||||
cfg, err := ParseFragment(v.Config("010-php.conf", types.ScopeSite))
|
||||
if err != nil {
|
||||
@@ -700,7 +688,6 @@ func (v *PHPVhost) SetPHP(version uint) error {
|
||||
return v.SetConfig("010-php.conf", "site", Export(cfg)+"\n")
|
||||
}
|
||||
|
||||
// phpVersionFromHandler 从 SetHandler 值提取 PHP 版本号
|
||||
func phpVersionFromHandler(handler string) uint {
|
||||
idx := strings.Index(handler, "php-cgi-")
|
||||
if idx == -1 {
|
||||
@@ -713,8 +700,6 @@ func phpVersionFromHandler(handler string) uint {
|
||||
return version
|
||||
}
|
||||
|
||||
// ========== ProxyVhost ==========
|
||||
|
||||
func (v *ProxyVhost) Proxies() []types.Proxy {
|
||||
proxies, _ := parseProxyFiles(filepath.Join(v.configDir, "site"))
|
||||
return proxies
|
||||
@@ -746,12 +731,10 @@ func (v *ProxyVhost) ClearUpstreams() error {
|
||||
return clearBalancerFiles(filepath.Join(v.configDir, "shared"))
|
||||
}
|
||||
|
||||
// isHSTSHeader 判断是否为 HSTS 响应头指令
|
||||
func isHSTSHeader(d *conf.Directive) bool {
|
||||
return argsContain(d.Args, "Strict-Transport-Security")
|
||||
}
|
||||
|
||||
// argsContain 判断参数值中是否有任一含子串
|
||||
func argsContain(args []conf.Arg, sub string) bool {
|
||||
for _, a := range args {
|
||||
if strings.Contains(a.Value, sub) {
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
package caddy
|
||||
|
||||
// ServerRoot 安装根目录
|
||||
const ServerRoot = "/opt/ace/server/caddy"
|
||||
|
||||
// MainConf 主配置文件
|
||||
const MainConf = ServerRoot + "/Caddyfile"
|
||||
|
||||
// HTMLDir 默认页目录
|
||||
const HTMLDir = ServerRoot + "/html"
|
||||
|
||||
// ACMEDir HTTP-01 验证目录,站点与兜底站点以它为根提供 token
|
||||
@@ -18,10 +15,8 @@ const ErrorLogPath = ServerRoot + "/logs/error.log"
|
||||
// panelACMEConf 面板验证写入的 token 文件名,供清理
|
||||
const panelACMEConf = ServerRoot + "/conf/acme-tokens"
|
||||
|
||||
// ConfName 站点配置文件名
|
||||
const ConfName = "caddy.conf"
|
||||
|
||||
// acmeURI HTTP-01 验证路径
|
||||
const acmeURI = "/.well-known/acme-challenge/"
|
||||
|
||||
const phpCacheConf = `# browser cache
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/acepanel/panel/v3/pkg/webserver/types"
|
||||
)
|
||||
|
||||
// Dialect Caddy 方言
|
||||
type Dialect struct{}
|
||||
|
||||
func (Dialect) Service() string {
|
||||
|
||||
@@ -23,7 +23,6 @@ type token struct {
|
||||
|
||||
var heredocMarker = regexp.MustCompile(`^[A-Za-z0-9_-]+$`)
|
||||
|
||||
// Parse 解析配置文本
|
||||
func Parse(content string) (*conf.Config, error) {
|
||||
tokens, err := lex(content)
|
||||
if err != nil {
|
||||
@@ -99,7 +98,6 @@ func Parse(content string) (*conf.Config, error) {
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// ParseFile 解析配置文件
|
||||
func ParseFile(path string) (*conf.Config, error) {
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
@@ -229,8 +227,6 @@ func splitAddresses(tokens []token) []string {
|
||||
return out
|
||||
}
|
||||
|
||||
// ========== 渲染 ==========
|
||||
|
||||
// Export 渲染为配置文本,顶层块之间空一行
|
||||
func Export(c *conf.Config) string {
|
||||
var b strings.Builder
|
||||
@@ -300,8 +296,6 @@ func quote(t, indent string) string {
|
||||
return t
|
||||
}
|
||||
|
||||
// ========== 站点块 ==========
|
||||
|
||||
// isSite 带块且不是片段或全局选项的顶层指令,Name 与 Args 为地址列表
|
||||
func isSite(d *conf.Directive) bool {
|
||||
return d.Block != nil && d.Name != "" && !strings.HasPrefix(d.Name, "(")
|
||||
|
||||
@@ -388,7 +388,6 @@ const (
|
||||
realIPValue = "{remote_host}"
|
||||
)
|
||||
|
||||
// denyAll nginx `deny all` 的等价写法
|
||||
var denyAll = []string{"0.0.0.0/0", "::/0"}
|
||||
|
||||
// accessLists nginx 习惯的 all:允许列表里等于不限制,有允许列表时 deny all 已隐含,否则展开为全部网段
|
||||
|
||||
@@ -16,17 +16,14 @@ import (
|
||||
"github.com/acepanel/panel/v3/pkg/webserver/types"
|
||||
)
|
||||
|
||||
// StaticVhost 纯静态虚拟主机
|
||||
type StaticVhost struct {
|
||||
*baseVhost
|
||||
}
|
||||
|
||||
// PHPVhost PHP 虚拟主机
|
||||
type PHPVhost struct {
|
||||
*baseVhost
|
||||
}
|
||||
|
||||
// ProxyVhost 反向代理虚拟主机
|
||||
type ProxyVhost struct {
|
||||
*baseVhost
|
||||
}
|
||||
@@ -53,7 +50,6 @@ type baseVhost struct {
|
||||
redirects []types.Redirect
|
||||
}
|
||||
|
||||
// newBaseVhost 创建基础虚拟主机实例
|
||||
func newBaseVhost(configDir string) (*baseVhost, error) {
|
||||
if configDir == "" {
|
||||
return nil, errors.New("config directory is required")
|
||||
@@ -85,7 +81,6 @@ func newBaseVhost(configDir string) (*baseVhost, error) {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// NewStaticVhost 创建纯静态虚拟主机实例
|
||||
func NewStaticVhost(configDir string) (*StaticVhost, error) {
|
||||
base, err := newBaseVhost(configDir)
|
||||
if err != nil {
|
||||
@@ -94,7 +89,6 @@ func NewStaticVhost(configDir string) (*StaticVhost, error) {
|
||||
return &StaticVhost{baseVhost: base}, nil
|
||||
}
|
||||
|
||||
// NewPHPVhost 创建 PHP 虚拟主机实例
|
||||
func NewPHPVhost(configDir string) (*PHPVhost, error) {
|
||||
base, err := newBaseVhost(configDir)
|
||||
if err != nil {
|
||||
@@ -103,7 +97,6 @@ func NewPHPVhost(configDir string) (*PHPVhost, error) {
|
||||
return &PHPVhost{baseVhost: base}, nil
|
||||
}
|
||||
|
||||
// NewProxyVhost 创建反向代理虚拟主机实例
|
||||
func NewProxyVhost(configDir string) (*ProxyVhost, error) {
|
||||
base, err := newBaseVhost(configDir)
|
||||
if err != nil {
|
||||
@@ -112,8 +105,6 @@ func NewProxyVhost(configDir string) (*ProxyVhost, error) {
|
||||
return &ProxyVhost{baseVhost: base}, nil
|
||||
}
|
||||
|
||||
// ========== 加载 ==========
|
||||
|
||||
var phpSocketPattern = regexp.MustCompile(`php-cgi-(\d+)\.sock$`)
|
||||
|
||||
func (v *baseVhost) load(cfg *conf.Config) {
|
||||
@@ -278,8 +269,6 @@ func (v *baseVhost) loadAuths(body *conf.Block) {
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 核心方法 ==========
|
||||
|
||||
func (v *baseVhost) Enable() bool {
|
||||
_, err := os.Stat(filepath.Join(v.configDir, "site", "00-disable.conf"))
|
||||
return os.IsNotExist(err)
|
||||
@@ -481,8 +470,6 @@ func (v *baseVhost) RemoveConfig(name string, scope types.ConfigScope) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ========== SSL ==========
|
||||
|
||||
func (v *baseVhost) SSL() bool {
|
||||
return v.ssl != nil
|
||||
}
|
||||
@@ -512,8 +499,6 @@ func (v *baseVhost) ClearSSL() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ========== 高级功能 ==========
|
||||
|
||||
// RateLimit Caddy 核心没有并发与带宽限制,站点级不支持
|
||||
func (v *baseVhost) RateLimit() *types.RateLimit {
|
||||
return nil
|
||||
@@ -563,8 +548,6 @@ func (v *baseVhost) SetRedirects(redirects []types.Redirect) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ========== PHPVhost ==========
|
||||
|
||||
func (v *PHPVhost) PHP() uint {
|
||||
return v.php
|
||||
}
|
||||
@@ -574,8 +557,6 @@ func (v *PHPVhost) SetPHP(version uint) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ========== ProxyVhost ==========
|
||||
|
||||
func (v *ProxyVhost) Proxies() []types.Proxy {
|
||||
return v.proxies
|
||||
}
|
||||
@@ -604,8 +585,6 @@ func (v *ProxyVhost) ClearUpstreams() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ========== 生成 ==========
|
||||
|
||||
const (
|
||||
hstsHeader = "Strict-Transport-Security"
|
||||
httpMatcher = "@ace_http"
|
||||
@@ -775,8 +754,6 @@ func (v *baseVhost) buildAuths(body *conf.Block, users map[string]bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 辅助 ==========
|
||||
|
||||
// accessLogFormat nginx combined 格式,由 transform-encoder 插件渲染,空字段输出 -
|
||||
const accessLogFormat = `{request>remote_ip} - {user_id} [{ts}] "{request>method} {request>uri} {request>proto}" {status} {size} "{request>headers>Referer>[0]}" "{request>headers>User-Agent>[0]}"`
|
||||
|
||||
|
||||
@@ -49,7 +49,6 @@ type Block struct {
|
||||
Nodes []Node
|
||||
}
|
||||
|
||||
// Config 配置文件根
|
||||
type Config struct {
|
||||
Block
|
||||
}
|
||||
@@ -58,12 +57,10 @@ func (*Comment) node() {}
|
||||
func (*Blank) node() {}
|
||||
func (*Directive) node() {}
|
||||
|
||||
// Dir 构造一条指令
|
||||
func Dir(name string, args ...string) *Directive {
|
||||
return &Directive{Name: name, Args: Args(args...)}
|
||||
}
|
||||
|
||||
// Blk 构造一条带子块的指令
|
||||
func Blk(name string, args ...string) *Directive {
|
||||
return &Directive{Name: name, Args: Args(args...), Block: &Block{}}
|
||||
}
|
||||
@@ -73,7 +70,6 @@ func Cmt(text string) *Comment {
|
||||
return &Comment{Text: " " + text}
|
||||
}
|
||||
|
||||
// Args 由纯值构造参数
|
||||
func Args(values ...string) []Arg {
|
||||
if len(values) == 0 {
|
||||
return nil
|
||||
@@ -85,7 +81,6 @@ func Args(values ...string) []Arg {
|
||||
return out
|
||||
}
|
||||
|
||||
// Values 取参数的纯值
|
||||
func Values(args []Arg) []string {
|
||||
if len(args) == 0 {
|
||||
return nil
|
||||
@@ -105,7 +100,6 @@ func (d *Directive) Arg(i int) string {
|
||||
return d.Args[i].Value
|
||||
}
|
||||
|
||||
// Values 全部参数的值
|
||||
func (d *Directive) Values() []string {
|
||||
if d == nil {
|
||||
return nil
|
||||
@@ -121,12 +115,10 @@ func (d *Directive) ArgsFrom(i int) []string {
|
||||
return Values(d.Args[i:])
|
||||
}
|
||||
|
||||
// SetArgs 替换参数
|
||||
func (d *Directive) SetArgs(values ...string) {
|
||||
d.Args = Args(values...)
|
||||
}
|
||||
|
||||
// AppendArg 追加参数
|
||||
func (d *Directive) AppendArg(value string) {
|
||||
d.Args = append(d.Args, Arg{Value: value})
|
||||
}
|
||||
@@ -152,7 +144,6 @@ func (b *Block) Clone() *Block {
|
||||
return out
|
||||
}
|
||||
|
||||
// Clone 深拷贝指令及其子块
|
||||
func (d *Directive) Clone() *Directive {
|
||||
if d == nil {
|
||||
return nil
|
||||
|
||||
@@ -4,12 +4,10 @@ import "strings"
|
||||
|
||||
// 名称比较一律大小写不敏感:apache 与 OLS 本身不区分,nginx 与 Caddy 的指令名全小写
|
||||
|
||||
// Append 追加节点
|
||||
func (b *Block) Append(nodes ...Node) {
|
||||
b.Nodes = append(b.Nodes, nodes...)
|
||||
}
|
||||
|
||||
// Len 节点数
|
||||
func (b *Block) Len() int {
|
||||
if b == nil {
|
||||
return 0
|
||||
@@ -17,7 +15,6 @@ func (b *Block) Len() int {
|
||||
return len(b.Nodes)
|
||||
}
|
||||
|
||||
// All 全部指令
|
||||
func (b *Block) All() []*Directive {
|
||||
if b == nil {
|
||||
return nil
|
||||
@@ -31,7 +28,6 @@ func (b *Block) All() []*Directive {
|
||||
return out
|
||||
}
|
||||
|
||||
// Get 首个同名指令
|
||||
func (b *Block) Get(name string) *Directive {
|
||||
if b == nil {
|
||||
return nil
|
||||
@@ -44,7 +40,6 @@ func (b *Block) Get(name string) *Directive {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAll 全部同名指令
|
||||
func (b *Block) GetAll(name string) []*Directive {
|
||||
if b == nil {
|
||||
return nil
|
||||
@@ -58,24 +53,20 @@ func (b *Block) GetAll(name string) []*Directive {
|
||||
return out
|
||||
}
|
||||
|
||||
// Has 是否存在同名指令
|
||||
func (b *Block) Has(name string) bool {
|
||||
return b.Get(name) != nil
|
||||
}
|
||||
|
||||
// Value 首个同名指令的首个参数
|
||||
func (b *Block) Value(name string) string {
|
||||
return b.Get(name).Arg(0)
|
||||
}
|
||||
|
||||
// Add 追加一条指令
|
||||
func (b *Block) Add(name string, args ...string) *Directive {
|
||||
d := Dir(name, args...)
|
||||
b.Nodes = append(b.Nodes, d)
|
||||
return d
|
||||
}
|
||||
|
||||
// AddBlock 追加一条带子块的指令
|
||||
func (b *Block) AddBlock(name string, args ...string) *Directive {
|
||||
d := Blk(name, args...)
|
||||
b.Nodes = append(b.Nodes, d)
|
||||
@@ -114,7 +105,6 @@ func (b *Block) RemoveFunc(name string, pred func(*Directive) bool) int {
|
||||
return count
|
||||
}
|
||||
|
||||
// Filter 只保留满足条件的节点
|
||||
func (b *Block) Filter(keep func(Node) bool) {
|
||||
if b == nil {
|
||||
return
|
||||
@@ -138,7 +128,6 @@ func (b *Block) GetBlock(name string, args ...string) *Directive {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Blocks 全部带子块的同名指令
|
||||
func (b *Block) Blocks(name string) []*Directive {
|
||||
var out []*Directive
|
||||
for _, d := range b.GetAll(name) {
|
||||
@@ -172,7 +161,6 @@ func (b *Block) Find(path string) []*Directive {
|
||||
return out
|
||||
}
|
||||
|
||||
// FindOne 点路径命中的首个指令
|
||||
func (b *Block) FindOne(path string) *Directive {
|
||||
if ds := b.Find(path); len(ds) > 0 {
|
||||
return ds[0]
|
||||
@@ -180,7 +168,6 @@ func (b *Block) FindOne(path string) *Directive {
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindBlocks 点路径命中的带子块指令
|
||||
func (b *Block) FindBlocks(path string) []*Directive {
|
||||
var out []*Directive
|
||||
for _, d := range b.Find(path) {
|
||||
@@ -215,7 +202,6 @@ func (b *Block) Meta(key string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// AddMeta 写入元数据注释
|
||||
func (b *Block) AddMeta(key, value string) {
|
||||
b.Nodes = append(b.Nodes, &Comment{Text: " ace:" + key + " " + value})
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/acepanel/panel/v3/pkg/webserver/types"
|
||||
)
|
||||
|
||||
// WithIPv6Listens 为每个监听补充同端口的 IPv6 监听
|
||||
func WithIPv6Listens(listens []types.Listen) []types.Listen {
|
||||
ipv6 := lo.FilterMap(listens, func(listen types.Listen, _ int) (types.Listen, bool) {
|
||||
port := listen.Address
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"github.com/acepanel/panel/v3/pkg/webserver/types"
|
||||
)
|
||||
|
||||
// AuthConfName 基本认证 map 片段文件名
|
||||
const AuthConfName = "011-auth.conf"
|
||||
|
||||
// 基本认证 map 变量名前缀
|
||||
@@ -46,7 +45,6 @@ func authPathPattern(path string) string {
|
||||
return "~^" + regexp.QuoteMeta(path) + "(/.*)?$"
|
||||
}
|
||||
|
||||
// authPatternPath 将 map 正则还原为路径
|
||||
func authPatternPath(pattern string) string {
|
||||
path := strings.TrimPrefix(pattern, "~^")
|
||||
path = strings.TrimSuffix(path, "(/.*)?$")
|
||||
@@ -83,7 +81,6 @@ func generateAuthMaps(siteName string, auths []types.BasicAuth) string {
|
||||
return Export(cfg)
|
||||
}
|
||||
|
||||
// parseAuthMaps 从 file map 还原认证规则
|
||||
func parseAuthMaps(content string) []types.BasicAuth {
|
||||
cfg, err := Parse(content)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
package nginx
|
||||
|
||||
// HTMLDir 默认页目录
|
||||
const HTMLDir = "/opt/ace/server/nginx/html"
|
||||
|
||||
// DisablePage 禁用页面路径
|
||||
const DisablePage = HTMLDir + "/stop.html"
|
||||
|
||||
// SitesPath 网站目录
|
||||
const SitesPath = "/opt/ace/sites"
|
||||
|
||||
// DefaultSiteConf 内置默认站点配置
|
||||
const DefaultSiteConf = "/opt/ace/server/nginx/conf/default.conf"
|
||||
|
||||
// 配置文件序号范围
|
||||
@@ -33,7 +29,6 @@ server {
|
||||
}
|
||||
`
|
||||
|
||||
// order 定义 Nginx 指令的排序优先级
|
||||
var order = map[string]int{
|
||||
"listen": 0,
|
||||
"server_name": 1,
|
||||
|
||||
@@ -34,7 +34,6 @@ location / {
|
||||
}
|
||||
`
|
||||
|
||||
// Dialect Nginx 方言
|
||||
type Dialect struct{}
|
||||
|
||||
func (Dialect) Service() string {
|
||||
|
||||
@@ -37,7 +37,6 @@ func listFiles(dir string, pattern *regexp.Regexp, from, to int) []string {
|
||||
return files
|
||||
}
|
||||
|
||||
// clearFiles 删除区间内的片段文件
|
||||
func clearFiles(dir string, pattern *regexp.Regexp, from, to int) error {
|
||||
for _, file := range listFiles(dir, pattern, from, to) {
|
||||
if err := os.Remove(file); err != nil && !os.IsNotExist(err) {
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
|
||||
// nginx 配置:分号结尾的指令、花括号块、单双引号(反斜杠转义)、# 注释,*_by_lua_block 的块体按 Lua 词法原样保留
|
||||
|
||||
// Parse 解析配置文本
|
||||
func Parse(content string) (*conf.Config, error) {
|
||||
p := &parser{s: strings.ReplaceAll(content, "\r\n", "\n"), line: 1}
|
||||
nodes, err := p.parseNodes(true)
|
||||
@@ -20,7 +19,6 @@ func Parse(content string) (*conf.Config, error) {
|
||||
return &conf.Config{Block: conf.Block{Nodes: nodes}}, nil
|
||||
}
|
||||
|
||||
// ParseFile 解析配置文件
|
||||
func ParseFile(path string) (*conf.Config, error) {
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
@@ -217,7 +215,6 @@ func (p *parser) readQuoted(quote byte) (string, error) {
|
||||
return "", p.errorf("unterminated quoted string")
|
||||
}
|
||||
|
||||
// trailingComment 取同一行紧随其后的注释
|
||||
func (p *parser) trailingComment() string {
|
||||
j := p.i
|
||||
for j < len(p.s) && (p.s[j] == ' ' || p.s[j] == '\t') {
|
||||
@@ -307,7 +304,6 @@ func (p *parser) skipLongBracket(level int) {
|
||||
p.i += end + len(closing)
|
||||
}
|
||||
|
||||
// skipLuaString 跳过 Lua 短字符串
|
||||
func (p *parser) skipLuaString(quote byte) {
|
||||
p.i++
|
||||
for p.i < len(p.s) {
|
||||
|
||||
@@ -66,7 +66,6 @@ func parseSize(s string) int64 {
|
||||
return value * unit
|
||||
}
|
||||
|
||||
// formatSize 用最大整除单位表示大小
|
||||
func formatSize(bytes int64) string {
|
||||
for _, u := range []struct {
|
||||
size int64
|
||||
|
||||
@@ -13,22 +13,18 @@ import (
|
||||
"github.com/acepanel/panel/v3/pkg/webserver/types"
|
||||
)
|
||||
|
||||
// StaticVhost 纯静态虚拟主机
|
||||
type StaticVhost struct {
|
||||
*baseVhost
|
||||
}
|
||||
|
||||
// PHPVhost PHP 虚拟主机
|
||||
type PHPVhost struct {
|
||||
*baseVhost
|
||||
}
|
||||
|
||||
// ProxyVhost 反向代理虚拟主机
|
||||
type ProxyVhost struct {
|
||||
*baseVhost
|
||||
}
|
||||
|
||||
// baseVhost Nginx 虚拟主机基础实现
|
||||
// 主文件解析成语法树后就地修改,用户手写的指令得以保留;保存时按 order 表排序输出
|
||||
type baseVhost struct {
|
||||
cfg *conf.Config
|
||||
@@ -37,7 +33,6 @@ type baseVhost struct {
|
||||
siteName string
|
||||
}
|
||||
|
||||
// newBaseVhost 创建基础虚拟主机实例
|
||||
func newBaseVhost(configDir string) (*baseVhost, error) {
|
||||
if configDir == "" {
|
||||
return nil, errors.New("config directory is required")
|
||||
@@ -64,7 +59,6 @@ func newBaseVhost(configDir string) (*baseVhost, error) {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// NewStaticVhost 创建纯静态虚拟主机实例
|
||||
func NewStaticVhost(configDir string) (*StaticVhost, error) {
|
||||
base, err := newBaseVhost(configDir)
|
||||
if err != nil {
|
||||
@@ -74,7 +68,6 @@ func NewStaticVhost(configDir string) (*StaticVhost, error) {
|
||||
return &StaticVhost{baseVhost: base}, nil
|
||||
}
|
||||
|
||||
// NewPHPVhost 创建 PHP 虚拟主机实例
|
||||
func NewPHPVhost(configDir string) (*PHPVhost, error) {
|
||||
base, err := newBaseVhost(configDir)
|
||||
if err != nil {
|
||||
@@ -84,7 +77,6 @@ func NewPHPVhost(configDir string) (*PHPVhost, error) {
|
||||
return &PHPVhost{baseVhost: base}, nil
|
||||
}
|
||||
|
||||
// NewProxyVhost 创建反向代理虚拟主机实例
|
||||
func NewProxyVhost(configDir string) (*ProxyVhost, error) {
|
||||
base, err := newBaseVhost(configDir)
|
||||
if err != nil {
|
||||
@@ -294,7 +286,6 @@ func (v *baseVhost) SetErrorLog(errorLog string) error {
|
||||
return v.SetConfig("020-error-log.conf", types.ScopeSite, "error_log "+errorLog+";\n")
|
||||
}
|
||||
|
||||
// fragmentValue 取站点级片段中某条指令的首个参数
|
||||
func (v *baseVhost) fragmentValue(name, directive string) string {
|
||||
cfg, err := Parse(v.Config(name, types.ScopeSite))
|
||||
if err != nil {
|
||||
@@ -349,8 +340,6 @@ func (v *baseVhost) RemoveConfig(name string, scope types.ConfigScope) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ========== SSL ==========
|
||||
|
||||
const (
|
||||
hstsHeader = "Strict-Transport-Security"
|
||||
httpsRedirect = "https://$host$request_uri"
|
||||
@@ -459,15 +448,12 @@ func (v *baseVhost) setHTTPSRedirect(enable bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// hasReturnTo 块内是否有跳转到指定目标的 return
|
||||
func hasReturnTo(d *conf.Directive, target string) bool {
|
||||
return slices.ContainsFunc(d.GetAll("return"), func(r *conf.Directive) bool {
|
||||
return slices.Contains(r.Values(), target)
|
||||
})
|
||||
}
|
||||
|
||||
// ========== 高级功能 ==========
|
||||
|
||||
func (v *baseVhost) RateLimit() *types.RateLimit {
|
||||
limit := &types.RateLimit{}
|
||||
if rate := v.server.Value("limit_rate"); rate != "" {
|
||||
@@ -600,8 +586,6 @@ func (v *baseVhost) SetRedirects(redirects []types.Redirect) error {
|
||||
return writeRedirectFiles(filepath.Join(v.configDir, "site"), redirects)
|
||||
}
|
||||
|
||||
// ========== PHPVhost ==========
|
||||
|
||||
func (v *PHPVhost) PHP() uint {
|
||||
content := v.Config("010-php.conf", types.ScopeSite)
|
||||
idx := strings.Index(content, "php-cgi-")
|
||||
@@ -634,8 +618,6 @@ func (v *PHPVhost) SetPHP(version uint) error {
|
||||
return v.SetConfig("010-php.conf", types.ScopeSite, content)
|
||||
}
|
||||
|
||||
// ========== ProxyVhost ==========
|
||||
|
||||
func (v *ProxyVhost) Proxies() []types.Proxy {
|
||||
return parseProxyFiles(filepath.Join(v.configDir, "site"))
|
||||
}
|
||||
|
||||
@@ -1,27 +1,21 @@
|
||||
package openlitespeed
|
||||
|
||||
// ServerRoot 安装根目录
|
||||
const ServerRoot = "/opt/ace/server/openlitespeed"
|
||||
|
||||
// HTMLDir 默认页目录
|
||||
const HTMLDir = ServerRoot + "/html"
|
||||
|
||||
// DisablePage 禁用页面路径
|
||||
const DisablePage = HTMLDir + "/stop.html"
|
||||
|
||||
// PanelConfDir 面板托管的主配置片段目录,由主配置 include
|
||||
const PanelConfDir = ServerRoot + "/conf/panel"
|
||||
|
||||
// ListenersConf 面板生成的监听器配置
|
||||
const ListenersConf = PanelConfDir + "/listeners.conf"
|
||||
|
||||
// VhostsConf 面板生成的站点注册配置
|
||||
const VhostsConf = PanelConfDir + "/vhosts.conf"
|
||||
|
||||
// vhostStubDir configFile 桩目录,让 OLS 的 .txt 转储留在面板目录内
|
||||
const vhostStubDir = PanelConfDir + "/vhosts"
|
||||
|
||||
// SitesPath 网站目录
|
||||
const SitesPath = "/opt/ace/sites"
|
||||
|
||||
// 站点配置目录下的文件名
|
||||
@@ -33,7 +27,6 @@ const (
|
||||
// stopURI 站点停用时请求重写到的路径
|
||||
const stopURI = "/ace-stop/"
|
||||
|
||||
// accessLogFormat Apache 兼容的访问日志格式
|
||||
const accessLogFormat = `"%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""`
|
||||
|
||||
const phpCacheConf = `expires {
|
||||
|
||||
@@ -18,7 +18,6 @@ import (
|
||||
// acmeConf mod_acme 配置,无状态 HTTP-01:按账户指纹直接应答 token.thumbprint
|
||||
const acmeConf = PanelConfDir + "/acme.conf"
|
||||
|
||||
// acmeProbe 探测用 token
|
||||
const acmeProbe = "ace-probe"
|
||||
|
||||
// acmeLeaseTTL 租约过期兜底,验证出错时 CleanUp 不会被调用
|
||||
@@ -32,7 +31,6 @@ var acmeLease struct {
|
||||
expires time.Time
|
||||
}
|
||||
|
||||
// Dialect OpenLiteSpeed 方言
|
||||
type Dialect struct{}
|
||||
|
||||
func (Dialect) Service() string {
|
||||
@@ -105,7 +103,6 @@ func (Dialect) RewritesDir() string {
|
||||
return "apache"
|
||||
}
|
||||
|
||||
// BeforeReload 覆盖站点删除等未经 Save 的变更
|
||||
func (Dialect) BeforeReload() error {
|
||||
return Sync()
|
||||
}
|
||||
|
||||
@@ -166,7 +166,6 @@ func syncListeners() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ensureDefaultCert 生成缺失的默认自签名证书
|
||||
func ensureDefaultCert() error {
|
||||
if _, err := os.Stat(defaultCert); err == nil {
|
||||
if _, err = os.Stat(defaultKey); err == nil {
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
|
||||
const indentUnit = " "
|
||||
|
||||
// Parse 解析配置文本
|
||||
func Parse(content string) (*conf.Config, error) {
|
||||
cfg := &conf.Config{}
|
||||
stack := []*conf.Block{&cfg.Block}
|
||||
@@ -93,7 +92,6 @@ func Parse(content string) (*conf.Config, error) {
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// ParseFile 解析配置文件
|
||||
func ParseFile(path string) (*conf.Config, error) {
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
@@ -102,7 +100,6 @@ func ParseFile(path string) (*conf.Config, error) {
|
||||
return Parse(string(content))
|
||||
}
|
||||
|
||||
// splitKeyValue 按首个空白拆分键与值
|
||||
func splitKeyValue(line string) (string, string) {
|
||||
idx := strings.IndexAny(line, " \t")
|
||||
if idx < 0 {
|
||||
|
||||
@@ -22,17 +22,14 @@ const (
|
||||
|
||||
var phpHandlerPattern = regexp.MustCompile(`/php/(\d+)\.conf$`)
|
||||
|
||||
// phpHandlerFile 站点引用的脚本处理器文件
|
||||
func phpHandlerFile(version uint) string {
|
||||
return filepath.Join(phpHandlerDir, strconv.FormatUint(uint64(version), 10)+".conf")
|
||||
}
|
||||
|
||||
// LSPHPPath 面板 PHP 附带的 lsphp 二进制路径
|
||||
func LSPHPPath(version uint) string {
|
||||
return fmt.Sprintf("/opt/ace/server/php/%d/bin/lsphp", version)
|
||||
}
|
||||
|
||||
// LSAPIEnabled 该 PHP 版本是否以 LSAPI 协议运行
|
||||
func LSAPIEnabled(version uint) bool {
|
||||
_, err := os.Stat(filepath.Join(lsapiDir, strconv.FormatUint(uint64(version), 10)))
|
||||
return err == nil
|
||||
@@ -117,7 +114,6 @@ func syncPHP() error {
|
||||
return os.WriteFile(phpConf, []byte(Export(cfg)), 0600)
|
||||
}
|
||||
|
||||
// installedPHPVersions 扫描面板已安装的 PHP 版本
|
||||
func installedPHPVersions() []uint {
|
||||
var versions []uint
|
||||
matches, _ := filepath.Glob("/opt/ace/server/php/*/bin/php")
|
||||
|
||||
@@ -150,7 +150,6 @@ func (v *baseVhost) buildProxies(cfg *conf.Config) map[int]bool {
|
||||
return consumed
|
||||
}
|
||||
|
||||
// addProxyApp 与后端保持长连接
|
||||
func addProxyApp(ext *conf.Directive, address string, timeout int, buffering bool) {
|
||||
ext.Add("type", "proxy")
|
||||
ext.Add("address", address)
|
||||
@@ -190,7 +189,6 @@ func parseHeaderValue(value string) string {
|
||||
return types.ApacheVars.ToNginx(expr)
|
||||
}
|
||||
|
||||
// upstreamHost 取代理地址里的主机名
|
||||
func upstreamHost(pass string) string {
|
||||
u, err := url.Parse(pass)
|
||||
if err != nil {
|
||||
|
||||
@@ -14,22 +14,18 @@ import (
|
||||
"github.com/acepanel/panel/v3/pkg/webserver/types"
|
||||
)
|
||||
|
||||
// StaticVhost 纯静态虚拟主机
|
||||
type StaticVhost struct {
|
||||
*baseVhost
|
||||
}
|
||||
|
||||
// PHPVhost PHP 虚拟主机
|
||||
type PHPVhost struct {
|
||||
*baseVhost
|
||||
}
|
||||
|
||||
// ProxyVhost 反向代理虚拟主机
|
||||
type ProxyVhost struct {
|
||||
*baseVhost
|
||||
}
|
||||
|
||||
// baseVhost OpenLiteSpeed 虚拟主机基础实现
|
||||
// vhconf 由内存状态整体生成,加载时解析回来;监听与域名属于主配置的 listener,单独记在 listen 文件
|
||||
type baseVhost struct {
|
||||
configDir string
|
||||
@@ -52,7 +48,6 @@ type baseVhost struct {
|
||||
redirects []types.Redirect
|
||||
}
|
||||
|
||||
// newBaseVhost 创建基础虚拟主机实例
|
||||
func newBaseVhost(configDir string) (*baseVhost, error) {
|
||||
if configDir == "" {
|
||||
return nil, errors.New("config directory is required")
|
||||
@@ -91,7 +86,6 @@ func newBaseVhost(configDir string) (*baseVhost, error) {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// NewStaticVhost 创建纯静态虚拟主机实例
|
||||
func NewStaticVhost(configDir string) (*StaticVhost, error) {
|
||||
base, err := newBaseVhost(configDir)
|
||||
if err != nil {
|
||||
@@ -100,7 +94,6 @@ func NewStaticVhost(configDir string) (*StaticVhost, error) {
|
||||
return &StaticVhost{baseVhost: base}, nil
|
||||
}
|
||||
|
||||
// NewPHPVhost 创建 PHP 虚拟主机实例
|
||||
func NewPHPVhost(configDir string) (*PHPVhost, error) {
|
||||
base, err := newBaseVhost(configDir)
|
||||
if err != nil {
|
||||
@@ -109,7 +102,6 @@ func NewPHPVhost(configDir string) (*PHPVhost, error) {
|
||||
return &PHPVhost{baseVhost: base}, nil
|
||||
}
|
||||
|
||||
// NewProxyVhost 创建反向代理虚拟主机实例
|
||||
func NewProxyVhost(configDir string) (*ProxyVhost, error) {
|
||||
base, err := newBaseVhost(configDir)
|
||||
if err != nil {
|
||||
@@ -118,8 +110,6 @@ func NewProxyVhost(configDir string) (*ProxyVhost, error) {
|
||||
return &ProxyVhost{baseVhost: base}, nil
|
||||
}
|
||||
|
||||
// ========== 加载 ==========
|
||||
|
||||
func (v *baseVhost) load(cfg *conf.Config) {
|
||||
if root := cfg.Value("docRoot"); root != "" {
|
||||
v.root = root
|
||||
@@ -222,8 +212,6 @@ func (v *baseVhost) loadAuths(cfg *conf.Config) {
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 核心方法 ==========
|
||||
|
||||
func (v *baseVhost) Enable() bool {
|
||||
_, err := os.Stat(filepath.Join(v.configDir, "site", "00-disable.conf"))
|
||||
return os.IsNotExist(err)
|
||||
@@ -386,8 +374,6 @@ func (v *baseVhost) RemoveConfig(name string, scope types.ConfigScope) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ========== SSL ==========
|
||||
|
||||
func (v *baseVhost) SSL() bool {
|
||||
return v.ssl != nil
|
||||
}
|
||||
@@ -417,8 +403,6 @@ func (v *baseVhost) ClearSSL() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ========== 高级功能 ==========
|
||||
|
||||
// RateLimit OLS 限速只有服务器级,站点级不支持
|
||||
func (v *baseVhost) RateLimit() *types.RateLimit {
|
||||
return nil
|
||||
@@ -468,8 +452,6 @@ func (v *baseVhost) SetRedirects(redirects []types.Redirect) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ========== PHPVhost ==========
|
||||
|
||||
func (v *PHPVhost) PHP() uint {
|
||||
return v.php
|
||||
}
|
||||
@@ -479,8 +461,6 @@ func (v *PHPVhost) SetPHP(version uint) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ========== ProxyVhost ==========
|
||||
|
||||
func (v *ProxyVhost) Proxies() []types.Proxy {
|
||||
return v.proxies
|
||||
}
|
||||
@@ -509,8 +489,6 @@ func (v *ProxyVhost) ClearUpstreams() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ========== 生成 ==========
|
||||
|
||||
// build 由内存状态生成完整 vhconf
|
||||
func (v *baseVhost) build() *conf.Config {
|
||||
cfg := &conf.Config{}
|
||||
@@ -760,8 +738,6 @@ func (v *baseVhost) buildListen() *conf.Config {
|
||||
return cfg
|
||||
}
|
||||
|
||||
// ========== 辅助 ==========
|
||||
|
||||
type fragmentType int
|
||||
|
||||
const (
|
||||
@@ -772,7 +748,6 @@ const (
|
||||
|
||||
var rewriteDirectivePattern = regexp.MustCompile(`(?i)^rewrite(rule|cond|base|engine|options|map)\b`)
|
||||
|
||||
// fragmentKind 按内容判断片段类型
|
||||
func fragmentKind(content string) fragmentType {
|
||||
kind := fragmentEmpty
|
||||
for line := range strings.SplitSeq(content, "\n") {
|
||||
@@ -806,7 +781,6 @@ func parseIfExists(path string) (*conf.Config, error) {
|
||||
return ParseFile(path)
|
||||
}
|
||||
|
||||
// splitList 拆分逗号分隔的值
|
||||
func splitList(value string) []string {
|
||||
out := make([]string, 0)
|
||||
for item := range strings.SplitSeq(value, ",") {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package webserver
|
||||
|
||||
// Type Web 服务器类型
|
||||
type Type string
|
||||
|
||||
const (
|
||||
|
||||
@@ -10,25 +10,16 @@ type Features struct {
|
||||
|
||||
// Dialect 收敛某种 Web 服务器在面板层面的全部差异,新增服务器只需实现此接口并在 webserver 包中注册
|
||||
type Dialect interface {
|
||||
// Service systemd 服务名
|
||||
Service() string
|
||||
// ConfigTest 配置测试命令
|
||||
ConfigTest() string
|
||||
// HTMLDir 默认页目录,存放 index.html、stop.html 与 404.html
|
||||
HTMLDir() string
|
||||
// ConfigFile 站点配置目录中的主配置文件名
|
||||
ConfigFile() string
|
||||
// PanelACMEConf 面板证书 HTTP 验证使用的独立配置文件
|
||||
PanelACMEConf() string
|
||||
// Features 能力集
|
||||
Features() Features
|
||||
// HTTPSListenArgs 443 监听的附加参数
|
||||
HTTPSListenArgs() []string
|
||||
// ErrorPageConf 站点 404 页面片段
|
||||
ErrorPageConf() string
|
||||
// PHPCacheConf PHP 站点浏览器缓存与敏感文件拦截片段
|
||||
PHPCacheConf() string
|
||||
// SPAConf 静态站点单页应用路由回退片段
|
||||
SPAConf() string
|
||||
// LSCacheConf 站点级 LiteSpeed 页面缓存片段,name 为站点名
|
||||
LSCacheConf(name string) string
|
||||
@@ -38,7 +29,6 @@ type Dialect interface {
|
||||
DefaultSiteConf() string
|
||||
// WriteDefaultSite 写入内置默认站点配置,asDefault 为 false 时把默认位让给某个站点
|
||||
WriteDefaultSite(asDefault bool) error
|
||||
// HTPasswdLine 基本认证 htpasswd 单行
|
||||
HTPasswdLine(username, password string) string
|
||||
// RewritesDir 伪静态预置目录名,语法相同的服务器可共用
|
||||
RewritesDir() string
|
||||
@@ -56,6 +46,5 @@ type Dialect interface {
|
||||
RemoveSiteChallenge(conf, path, token string) (bool, error)
|
||||
// WritePanelChallenge 写入面板独立验证站点,用于 80 端口已被 Web 服务器占用时签发面板证书
|
||||
WritePanelChallenge(conf string, names []string, tokens map[string]string) (bool, error)
|
||||
// RemovePanelChallenge 清理面板独立验证站点
|
||||
RemovePanelChallenge(conf string) (bool, error)
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ func ParseLocation(location string) (LocationKind, string) {
|
||||
return LocationPrefix, location
|
||||
}
|
||||
|
||||
// NormalizePath 补上开头的斜杠
|
||||
func NormalizePath(path string) string {
|
||||
path = strings.TrimSpace(path)
|
||||
if !strings.HasPrefix(path, "/") {
|
||||
|
||||
@@ -2,7 +2,6 @@ package types
|
||||
|
||||
import "time"
|
||||
|
||||
// CacheConfig 缓存配置
|
||||
type CacheConfig struct {
|
||||
// 缓存时长,状态码 -> 时长,如: {"200 302": "10m", "404": "1m", "any": "5m"}
|
||||
Valid map[string]string `form:"valid" json:"valid"`
|
||||
@@ -31,14 +30,12 @@ type CacheConfig struct {
|
||||
Key string `form:"key" json:"key"`
|
||||
}
|
||||
|
||||
// TimeoutConfig 超时配置
|
||||
type TimeoutConfig struct {
|
||||
Connect time.Duration `form:"connect" json:"connect"` // proxy_connect_timeout,默认 60s
|
||||
Read time.Duration `form:"read" json:"read"` // proxy_read_timeout,默认 60s
|
||||
Send time.Duration `form:"send" json:"send"` // proxy_send_timeout,默认 60s
|
||||
}
|
||||
|
||||
// RetryConfig 重试配置
|
||||
type RetryConfig struct {
|
||||
// 触发重试的条件 (proxy_next_upstream)
|
||||
// 可选值: "error", "timeout", "invalid_header", "http_500", "http_502", "http_503", "http_504", "http_429", "non_idempotent", "off"
|
||||
@@ -51,14 +48,12 @@ type RetryConfig struct {
|
||||
Timeout time.Duration `form:"timeout" json:"timeout"`
|
||||
}
|
||||
|
||||
// SSLBackendConfig SSL 后端验证配置
|
||||
type SSLBackendConfig struct {
|
||||
Verify bool `form:"verify" json:"verify"` // proxy_ssl_verify on/off
|
||||
TrustedCertificate string `form:"trusted_certificate" json:"trusted_certificate"` // proxy_ssl_trusted_certificate 路径
|
||||
VerifyDepth int `form:"verify_depth" json:"verify_depth"` // proxy_ssl_verify_depth,默认 1
|
||||
}
|
||||
|
||||
// ResponseHeaderConfig 响应头修改配置
|
||||
type ResponseHeaderConfig struct {
|
||||
// 隐藏的响应头 (proxy_hide_header)
|
||||
Hide []string `form:"hide" json:"hide"`
|
||||
@@ -68,7 +63,6 @@ type ResponseHeaderConfig struct {
|
||||
Add map[string]string `form:"add" json:"add"`
|
||||
}
|
||||
|
||||
// AccessControlConfig IP 访问控制配置
|
||||
type AccessControlConfig struct {
|
||||
// 允许的 IP/CIDR 列表 (allow)
|
||||
Allow []string `form:"allow" json:"allow"`
|
||||
@@ -77,7 +71,6 @@ type AccessControlConfig struct {
|
||||
Deny []string `form:"deny" json:"deny"`
|
||||
}
|
||||
|
||||
// Proxy 反向代理配置
|
||||
type Proxy struct {
|
||||
Location string `form:"location" json:"location" validate:"required"` // 匹配路径,如: "/", "/api", "~ ^/api/v[0-9]+/"
|
||||
Pass string `form:"pass" json:"pass" validate:"required"` // 代理地址,如: "http://example.com", "http://backend"
|
||||
@@ -117,7 +110,6 @@ func NormalizeAlgo(algo string) string {
|
||||
}
|
||||
}
|
||||
|
||||
// Upstream 上游服务器配置
|
||||
type Upstream struct {
|
||||
Name string `form:"name" json:"name" validate:"required"` // 上游名称,如: "backend"
|
||||
Servers map[string]string `form:"servers" json:"servers" validate:"required"` // 上游服务器及配置,如: map["server1"] = "weight=5 resolve"
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package types
|
||||
|
||||
// RedirectType 重定向类型
|
||||
type RedirectType string
|
||||
|
||||
const (
|
||||
@@ -9,7 +8,6 @@ const (
|
||||
RedirectTypeURL RedirectType = "url" // URL 重定向
|
||||
)
|
||||
|
||||
// Redirect 重定向配置
|
||||
type Redirect struct {
|
||||
Type RedirectType `json:"type"` // 重定向类型
|
||||
From string `json:"from"` // 源地址,如: "example.com", "http://example.com", "/old"
|
||||
|
||||
@@ -10,7 +10,6 @@ type VarMap struct {
|
||||
toNginx *strings.Replacer
|
||||
}
|
||||
|
||||
// NewVarMap 由 nginx 变量到方言占位符的有序表构造双向映射
|
||||
func NewVarMap(pairs [][2]string) *VarMap {
|
||||
native := make([]string, 0, len(pairs)*2)
|
||||
nginx := make([]string, 0, len(pairs)*2)
|
||||
@@ -26,12 +25,10 @@ func NewVarMap(pairs [][2]string) *VarMap {
|
||||
return &VarMap{toNative: strings.NewReplacer(native...), toNginx: strings.NewReplacer(nginx...)}
|
||||
}
|
||||
|
||||
// ToNative 面板存的 nginx 写法转成方言占位符
|
||||
func (m *VarMap) ToNative(value string) string {
|
||||
return m.toNative.Replace(value)
|
||||
}
|
||||
|
||||
// ToNginx 方言占位符转回 nginx 写法
|
||||
func (m *VarMap) ToNginx(value string) string {
|
||||
return m.toNginx.Replace(value)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package types
|
||||
|
||||
// ConfigScope 配置片段的作用域
|
||||
type ConfigScope string
|
||||
|
||||
const (
|
||||
@@ -8,164 +7,111 @@ const (
|
||||
ScopeShared ConfigScope = "shared" // 共享级片段(shared/ 目录)
|
||||
)
|
||||
|
||||
// Vhost 虚拟主机通用接口
|
||||
type Vhost interface {
|
||||
// ========== 核心方法 ==========
|
||||
|
||||
// Enable 取启用状态
|
||||
Enable() bool
|
||||
// SetEnable 设置启用状态
|
||||
SetEnable(enable bool) error
|
||||
|
||||
// Default 是否为默认站点,承接未匹配任何域名的请求
|
||||
Default() bool
|
||||
// SetDefault 设置默认站点标志
|
||||
SetDefault(enable bool) error
|
||||
|
||||
// Listen 取监听配置
|
||||
Listen() []Listen
|
||||
// SetListen 设置监听配置
|
||||
SetListen(listen []Listen) error
|
||||
|
||||
// ServerName 取服务器名称,如: ["example.com", "www.example.com"]
|
||||
ServerName() []string
|
||||
// SetServerName 设置服务器名称
|
||||
SetServerName(serverName []string) error
|
||||
|
||||
// Index 取默认首页,如: ["index.php", "index.html"]
|
||||
Index() []string
|
||||
// SetIndex 设置默认首页
|
||||
SetIndex(index []string) error
|
||||
|
||||
// Root 取网站根目录,如: "/opt/ace/sites/example/public"
|
||||
Root() string
|
||||
// SetRoot 设置网站根目录
|
||||
SetRoot(root string) error
|
||||
|
||||
// Includes 取包含的文件配置
|
||||
Includes() []IncludeFile
|
||||
// SetIncludes 设置包含的文件配置
|
||||
SetIncludes(includes []IncludeFile) error
|
||||
|
||||
// AccessLog 取访问日志路径,如: "/opt/ace/sites/example/log/access.log"
|
||||
AccessLog() string
|
||||
// SetAccessLog 设置访问日志路径
|
||||
SetAccessLog(accessLog string) error
|
||||
|
||||
// ErrorLog 取错误日志路径,如: "/opt/ace/sites/example/log/error.log"
|
||||
ErrorLog() string
|
||||
// SetErrorLog 设置错误日志路径
|
||||
SetErrorLog(errorLog string) error
|
||||
|
||||
// Save 保存配置到文件
|
||||
Save() error
|
||||
// Reset 重置配置为默认值
|
||||
Reset() error
|
||||
|
||||
// ========== SSL/TLS 方法 ==========
|
||||
|
||||
// SSL 取 SSL 启用状态
|
||||
SSL() bool
|
||||
// SSLConfig 取 SSL 配置
|
||||
SSLConfig() *SSLConfig
|
||||
// SetSSLConfig 设置 SSL 配置(自动启用 HTTPS)
|
||||
SetSSLConfig(cfg *SSLConfig) error
|
||||
// ClearSSL 清除 SSL 配置
|
||||
ClearSSL() error
|
||||
|
||||
// ========== 高级功能方法 ==========
|
||||
|
||||
// RateLimit 取限流限速配置
|
||||
RateLimit() *RateLimit
|
||||
// SetRateLimit 设置限流限速配置
|
||||
SetRateLimit(limit *RateLimit) error
|
||||
// ClearRateLimit 清除限流限速配置
|
||||
ClearRateLimit() error
|
||||
|
||||
// BasicAuth 取基本认证规则
|
||||
BasicAuth() []BasicAuth
|
||||
// SetBasicAuth 设置基本认证规则
|
||||
SetBasicAuth(auths []BasicAuth) error
|
||||
// ClearBasicAuth 清除基本认证
|
||||
ClearBasicAuth() error
|
||||
|
||||
// RealIP 取真实 IP 配置
|
||||
RealIP() *RealIP
|
||||
// SetRealIP 设置真实 IP 配置
|
||||
SetRealIP(realIP *RealIP) error
|
||||
// ClearRealIP 清除真实 IP 配置
|
||||
ClearRealIP() error
|
||||
|
||||
// Config 取指定名称的配置内容
|
||||
Config(name string, scope ConfigScope) string
|
||||
// SetConfig 设置指定名称的配置内容,自动添加生成标记注释
|
||||
SetConfig(name string, scope ConfigScope, content string) error
|
||||
// SetRawConfig 设置配置内容但不添加生成标记注释(用于用户可编辑的片段)
|
||||
SetRawConfig(name string, scope ConfigScope, content string) error
|
||||
// RemoveConfig 清除指定名称的配置内容
|
||||
RemoveConfig(name string, scope ConfigScope) error
|
||||
}
|
||||
|
||||
// StaticVhost 纯静态虚拟主机接口
|
||||
type StaticVhost interface {
|
||||
Vhost
|
||||
VhostRedirect
|
||||
}
|
||||
|
||||
// PHPVhost PHP 虚拟主机接口
|
||||
type PHPVhost interface {
|
||||
Vhost
|
||||
VhostPHP
|
||||
VhostRedirect
|
||||
}
|
||||
|
||||
// ProxyVhost 反向代理虚拟主机接口
|
||||
type ProxyVhost interface {
|
||||
Vhost
|
||||
VhostRedirect
|
||||
VhostProxy
|
||||
}
|
||||
|
||||
// VhostPHP PHP 相关接口
|
||||
type VhostPHP interface {
|
||||
// PHP 取 PHP 版本,如: 84, 81, 80, 0 表示未启用 PHP
|
||||
PHP() uint
|
||||
// SetPHP 设置 PHP 版本
|
||||
SetPHP(version uint) error
|
||||
}
|
||||
|
||||
// VhostRedirect 重定向相关接口
|
||||
type VhostRedirect interface {
|
||||
// Redirects 取所有重定向配置
|
||||
Redirects() []Redirect
|
||||
// SetRedirects 设置重定向
|
||||
SetRedirects(redirects []Redirect) error
|
||||
}
|
||||
|
||||
// VhostProxy 反向代理相关接口
|
||||
type VhostProxy interface {
|
||||
// Proxies 取所有反向代理配置
|
||||
Proxies() []Proxy
|
||||
// SetProxies 设置反向代理配置
|
||||
SetProxies(proxies []Proxy) error
|
||||
// ClearProxies 清除所有反向代理配置
|
||||
ClearProxies() error
|
||||
|
||||
// Upstreams 取上游服务器配置
|
||||
Upstreams() []Upstream
|
||||
// SetUpstreams 设置上游服务器配置
|
||||
SetUpstreams(upstreams []Upstream) error
|
||||
// ClearUpstreams 清除所有上游服务器配置
|
||||
ClearUpstreams() error
|
||||
}
|
||||
|
||||
// Listen 监听配置
|
||||
type Listen struct {
|
||||
Address string `form:"address" json:"address"` // 监听地址,如: "80", "0.0.0.0:80", "[::]:443"
|
||||
Args []string `form:"args" json:"args"` // 其他参数,如: ["default_server", "ssl", "quic"]
|
||||
}
|
||||
|
||||
// SSLConfig SSL/TLS 配置
|
||||
type SSLConfig struct {
|
||||
Cert string `json:"cert"` // 证书路径
|
||||
Key string `json:"key"` // 私钥路径
|
||||
@@ -178,27 +124,23 @@ type SSLConfig struct {
|
||||
AltSvc string `json:"alt_svc"` // Alt-Svc 配置,如: 'h3=":443"; ma=86400'
|
||||
}
|
||||
|
||||
// RateLimit 限流限速配置
|
||||
type RateLimit struct {
|
||||
PerServer int `json:"per_server"` // 站点最大并发数 (limit_conn perserver X)
|
||||
PerIP int `json:"per_ip"` // 单 IP 最大并发数 (limit_conn perip X)
|
||||
Rate int `json:"rate"` // 流量限制,单位 KB (limit_rate Xk)
|
||||
}
|
||||
|
||||
// BasicAuth 基本认证规则
|
||||
type BasicAuth struct {
|
||||
Path string `json:"path"` // 生效路径前缀,"/" 表示整站
|
||||
UserFile string `json:"user_file"` // htpasswd 文件路径
|
||||
}
|
||||
|
||||
// RealIP 真实 IP 配置
|
||||
type RealIP struct {
|
||||
From []string `json:"from"` // 可信 IP 来源列表 (set_real_ip_from)
|
||||
Header string `json:"header"` // 真实 IP 头 (real_ip_header),如: X-Real-IP, X-Forwarded-For
|
||||
Recursive bool `json:"recursive"` // 递归搜索 (real_ip_recursive)
|
||||
}
|
||||
|
||||
// IncludeFile 包含文件配置
|
||||
type IncludeFile struct {
|
||||
Path string `json:"path"` // 文件路径
|
||||
Comment []string `json:"comment"` // 注释说明
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
"github.com/acepanel/panel/v3/pkg/webserver/types"
|
||||
)
|
||||
|
||||
// dialects 已注册的 Web 服务器方言
|
||||
var dialects = map[Type]types.Dialect{
|
||||
TypeNginx: nginx.Dialect{},
|
||||
TypeApache: apache.Dialect{},
|
||||
@@ -22,13 +21,11 @@ var dialects = map[Type]types.Dialect{
|
||||
TypeCaddy: caddy.Dialect{},
|
||||
}
|
||||
|
||||
// Dialect 在具体方言之上补充与服务器无关的通用逻辑
|
||||
type Dialect struct {
|
||||
types.Dialect
|
||||
Type Type
|
||||
}
|
||||
|
||||
// Get 按类型取方言
|
||||
func Get(t Type) (Dialect, error) {
|
||||
d, ok := dialects[t]
|
||||
if !ok {
|
||||
@@ -38,7 +35,6 @@ func Get(t Type) (Dialect, error) {
|
||||
return Dialect{Dialect: d, Type: t}, nil
|
||||
}
|
||||
|
||||
// Types 已注册的 Web 服务器类型
|
||||
func Types() []Type {
|
||||
keys := make([]Type, 0, len(dialects))
|
||||
for t := range dialects {
|
||||
|
||||
Reference in New Issue
Block a user