lolly/internal/config/config.go
xfy a026277385 feat(config): 添加 redirect_rewrite 配置定义和验证
- 新增 RedirectRewriteConfig 配置结构体,支持三种模式:
  - default: 自动从 target URL 生成改写规则(运行时)
  - off: 禁用 Location/Refresh 头改写
  - custom: 使用预定义规则列表(预编译)
- 新增 RedirectRewriteRule 规则结构体,支持正则(~ 前缀)和前缀匹配
- 添加 validateRedirectRewrite 验证函数:
  - Mode 有效性检查
  - custom 模式必须有规则
  - 正则表达式预编译检查
- 更新 GenerateConfigYAML 添加配置示例文档

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 17:01:07 +08:00

1950 lines
58 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 config 提供 YAML 配置文件的解析、验证和默认配置生成功能。
//
// 该文件包含配置结构体定义和加载/保存功能,包括:
// - 根配置和服务器配置结构体
// - SSL、安全、代理、压缩等子配置结构体
// - 配置文件的加载、保存和验证方法
//
// 主要用途:
//
// 用于定义和管理服务器的完整配置,支持单服务器和多虚拟主机两种模式。
//
// 注意事项:
// - 配置文件使用 YAML 格式
// - 所有配置项都有合理的默认值
// - 配置加载后会自动验证
//
// 作者xfy
package config
import (
"errors"
"fmt"
"net"
"os"
"time"
"gopkg.in/yaml.v3"
)
// 默认配置常量。
const (
// DefaultPprofPath pprof 端点的默认路径。
DefaultPprofPath = "/debug/pprof"
)
// ServerMode 服务器运行模式类型。
//
// 定义服务器的工作模式,支持显式配置或自动推断。
type ServerMode string
// ServerMode 枚举值。
const (
// ServerModeSingle 单服务器模式 - 只运行一个服务器实例。
ServerModeSingle ServerMode = "single"
// ServerModeVHost 虚拟主机模式 - 多个服务器共享相同的监听地址。
ServerModeVHost ServerMode = "vhost"
// ServerModeMultiServer 多服务器模式 - 多个服务器监听不同的地址。
ServerModeMultiServer ServerMode = "multi_server"
// ServerModeAuto 自动模式 - 根据配置自动推断运行模式。
ServerModeAuto ServerMode = "auto"
)
// Config 根配置结构,支持单服务器和多虚拟主机两种模式。
//
// 包含服务器配置、日志配置、性能配置和监控配置等模块。
// 是配置文件的顶级结构体,所有其他配置都作为其子结构。
//
// 注意事项:
// - 必须配置 servers 列表中的至少一个
// - 加载后会自动进行配置验证
// - Stream 配置为可选,用于 TCP/UDP 层代理
// - HTTP/3 配置为可选,需 SSL 配置配合才能生效
//
// 使用示例:
//
// cfg, err := config.Load("config.yaml")
// if err != nil {
// log.Fatal(err)
// }
// // 使用多虚拟主机模式
// for _, s := range cfg.Servers {
// // 处理每个服务器配置
// }
type Config struct {
Mode ServerMode `yaml:"mode"`
Variables VariablesConfig `yaml:"variables"`
Logging LoggingConfig `yaml:"logging"`
Servers []ServerConfig `yaml:"servers"`
Stream []StreamConfig `yaml:"stream"`
Monitoring MonitoringConfig `yaml:"monitoring"`
HTTP3 HTTP3Config `yaml:"http3"`
Resolver ResolverConfig `yaml:"resolver"`
Performance PerformanceConfig `yaml:"performance"`
Shutdown ShutdownConfig `yaml:"shutdown"`
}
// VariablesConfig 自定义变量配置。
//
// 用于定义全局自定义变量,可在日志格式和请求头中引用。
// 变量作用于所有虚拟主机。
//
// 注意事项:
// - 变量名只允许字母、数字、下划线
// - 变量名不能与内置变量冲突
// - 变量名不能以 arg_、http_、cookie_ 开头(动态变量前缀)
//
// 使用示例:
//
// variables:
// set:
// app_name: "lolly"
// version: "1.0.0"
type VariablesConfig struct {
// Set 自定义变量集合
// 键值对形式,可在日志格式和请求头模板中使用 $var_name 引用
Set map[string]string `yaml:"set"`
}
// HTTP2Config HTTP/2 配置。
//
// HTTP/2 提供多路复用、头部压缩和服务器推送等功能,
// 需要服务器配置 SSL/TLS 证书才能正常工作。
//
// 注意事项:
// - 必须配置有效的 SSL 证书TLS 1.2 或更高版本)
// - http2.enabled 仅在配置了 SSL/TLS 时生效
// - 客户端可以通过 ALPN 协商使用 HTTP/2 或 HTTP/1.1
//
// 使用示例:
//
// server:
// ssl:
// cert: "/etc/ssl/server.crt"
// key: "/etc/ssl/server.key"
// http2:
// enabled: true
// max_concurrent_streams: 128
// max_header_list_size: "16KB"
type HTTP2Config struct {
MaxConcurrentStreams int `yaml:"max_concurrent_streams"`
MaxHeaderListSize int `yaml:"max_header_list_size"`
IdleTimeout time.Duration `yaml:"idle_timeout"`
Enabled bool `yaml:"enabled"`
PushEnabled bool `yaml:"push_enabled"`
H2CEnabled bool `yaml:"h2c_enabled"`
GracefulShutdownTimeout time.Duration `yaml:"graceful_shutdown_timeout"`
}
// HTTP3Config HTTP/3 (QUIC) 配置。
//
// HTTP/3 基于 QUIC 协议,提供更快的连接建立和更低的延迟。
// 需要服务器配置 SSL/TLS 证书才能正常工作。
//
// 注意事项:
// - 必须配置有效的 SSL 证书
// - UDP 监听地址不能与 HTTP/1.1 或 HTTP/2 冲突
// - 0-RTT 特性可能带来重放攻击风险,需评估安全性
// - 部分网络环境可能限制 UDP 流量
//
// 使用示例:
//
// http3:
// enabled: true
// listen: ":443"
// max_streams: 1000
// idle_timeout: 30s
// enable_0rtt: true
type HTTP3Config struct {
Listen string `yaml:"listen"`
MaxStreams int `yaml:"max_streams"`
IdleTimeout time.Duration `yaml:"idle_timeout"`
Enabled bool `yaml:"enabled"`
Enable0RTT bool `yaml:"enable_0rtt"`
}
// ServerConfig 服务器配置包含监听地址、静态文件、代理、SSL 等设置。
//
// 用于定义单个服务器的完整行为,包括网络监听、请求处理、
// 安全防护和性能控制等方面。
//
// 注意事项:
// - Listen 字段为必填项,格式为 "host:port" 或 ":port"
// - Name 字段用于虚拟主机匹配,多服务器模式下建议配置
// - SSL 配置为可选,但生产环境强烈建议启用
// - 超时设置需根据实际业务场景调整
//
// 使用示例:
//
// server:
// listen: ":8080"
// name: "api.example.com"
// read_timeout: 30s
// write_timeout: 30s
type ServerConfig struct {
CacheAPI *CacheAPIConfig `yaml:"cache_api"`
Lua *LuaMiddlewareConfig `yaml:"lua"`
ClientMaxBodySize string `yaml:"client_max_body_size"`
Name string `yaml:"name"`
Default bool `yaml:"default,omitempty"` // VHost 默认主机标记
Listen string `yaml:"listen"`
Security SecurityConfig `yaml:"security"`
Static []StaticConfig `yaml:"static"`
Proxy []ProxyConfig `yaml:"proxy"`
Rewrite []RewriteRule `yaml:"rewrite"`
Compression CompressionConfig `yaml:"compression"`
SSL SSLConfig `yaml:"ssl"`
ReadTimeout time.Duration `yaml:"read_timeout"`
MaxRequestsPerConn int `yaml:"max_requests_per_conn"`
MaxConnsPerIP int `yaml:"max_conns_per_ip"`
IdleTimeout time.Duration `yaml:"idle_timeout"`
WriteTimeout time.Duration `yaml:"write_timeout"`
}
// StaticConfig 静态文件服务配置。
//
// 用于配置静态文件服务器的行为,包括路径匹配、根目录和索引文件。
//
// 注意事项:
// - Path 为路径前缀,匹配的请求将被该静态处理器处理
// - Root 路径可以是相对路径或绝对路径
// - 索引文件按顺序查找,第一个存在的文件将被使用
// - 目录路径需要确保有读取权限
//
// 使用示例:
//
// static:
// - path: "/"
// root: "/var/www/html"
// index: ["index.html", "index.htm"]
// - path: "/assets/"
// root: "/var/www/assets"
type StaticConfig struct {
// Path 匹配路径前缀
// 以此前缀开头的请求将被该静态处理器处理
// 默认为 "/",匹配所有路径
Path string `yaml:"path"`
// Root 静态文件根目录
// 所有静态文件请求都将以此目录为基础解析
Root string `yaml:"root"`
// Index 索引文件列表
// 访问目录时依次查找这些文件作为默认页面
// 默认为 ["index.html", "index.htm"]
Index []string `yaml:"index"`
// TryFiles 按顺序尝试查找的文件列表
// 支持以下模式:
// - $uri: 请求路径
// - $uri/: 请求路径加斜杠(目录)
// - $uri.<ext>: 请求路径加扩展名(如 $uri.html, $uri.json
// - /path: 绝对路径回退(如 /index.html
// - filename: 相对路径回退(如 fallback.html
//
// nginx 兼容性:
// - $uri 变量语义与 nginx try_files 指令一致
// - 配置语法可从 nginx 直接迁移
//
// 安全限制(附加于 nginx 基础):
// - 扩展名仅允许字母、数字、点、下划线、连字符
// - 禁止危险后缀(.php, .exe, .bat 等)
// - 禁止 null byte 和路径分隔符
//
// 根路径边界情况:
// - 当 relPath="/" 且模式为 "$uri.<ext>" 时,返回空字符串
// - 此设计避免生成 "/.html" 这样的隐藏文件名
// - 建议使用绝对路径回退(如 /index.html处理根路径
//
// 示例:
// try_files: ["$uri", "$uri.html", "/index.html"]
// try_files: ["$uri", "$uri/", "/app.html"]
TryFiles []string `yaml:"try_files"`
// TryFilesPass 内部重定向是否触发中间件
// 默认为 false内部重定向不触发中间件
// 设置为 true 时try_files 回退会重新进入中间件链
TryFilesPass bool `yaml:"try_files_pass"`
// SymlinkCheck 是否启用符号链接安全检查
// 默认为 false启用后会验证符号链接指向的文件是否在允许的路径范围内
// 防止通过符号链接访问敏感文件(如 /etc/passwd
SymlinkCheck bool `yaml:"symlink_check"`
}
// ProxyConfig 反向代理配置,支持负载均衡和健康检查。
//
// 用于将请求转发到后端服务器,支持多种负载均衡算法
// 和健康检查机制。
//
// 注意事项:
// - Path 使用前缀匹配,较长路径优先匹配
// - 至少配置一个 Target 才能正常工作
// - 负载均衡算法支持round_robin、weighted_round_robin、least_conn、ip_hash、consistent_hash
// - 一致性哈希需要配置 HashKey
//
// 使用示例:
//
// proxy:
// - path: "/api/"
// targets:
// - url: "http://backend1:8080"
// weight: 3
// - url: "http://backend2:8080"
// weight: 1
// load_balance: "weighted_round_robin"
// health_check:
// interval: 10s
// path: "/health"
type ProxyConfig struct {
Path string `yaml:"path"`
LoadBalance string `yaml:"load_balance"`
HashKey string `yaml:"hash_key"`
ClientMaxBodySize string `yaml:"client_max_body_size"`
Headers ProxyHeaders `yaml:"headers"`
Targets []ProxyTarget `yaml:"targets"`
BalancerByLua BalancerByLuaConfig `yaml:"balancer_by_lua"`
HealthCheck HealthCheckConfig `yaml:"health_check"`
NextUpstream NextUpstreamConfig `yaml:"next_upstream"`
Cache ProxyCacheConfig `yaml:"cache"`
Timeout ProxyTimeout `yaml:"timeout"`
VirtualNodes int `yaml:"virtual_nodes"`
RedirectRewrite *RedirectRewriteConfig `yaml:"redirect_rewrite"`
}
// BalancerByLuaConfig Lua 负载均衡配置
//
// 使用 Lua 脚本动态选择后端目标,支持自定义负载均衡逻辑。
//
// 注意事项:
// - Script 为 Lua 脚本文件路径
// - Timeout 控制脚本执行超时
// - Fallback 指定 Lua 失败时的备用算法
//
// 使用示例:
//
// balancer_by_lua:
// enabled: true
// script: "/etc/lolly/scripts/balancer.lua"
// timeout: 100ms
// fallback: "round_robin"
type BalancerByLuaConfig struct {
// Script Lua 脚本路径
Script string `yaml:"script"`
// Fallback 失败时使用的默认负载均衡算法
// 默认值: "round_robin"
Fallback string `yaml:"fallback"`
// Timeout 执行超时
// 默认值: 100ms
Timeout time.Duration `yaml:"timeout"`
// Enabled 是否启用
Enabled bool `yaml:"enabled"`
}
// ProxyTarget 后端目标配置。
//
// 定义单个后端服务器的地址和权重。
//
// 注意事项:
// - URL 必须包含协议http:// 或 https://
// - Weight 仅在 weighted_round_robin 算法下生效
//
// 使用示例:
//
// targets:
// - url: "http://backend1:8080"
// weight: 3
// - url: "http://backend2:8080"
// weight: 1
type ProxyTarget struct {
// URL 后端地址
// 格式:"http://host:port" 或 "https://host:port"
URL string `yaml:"url"`
// Weight 权重
// 用于加权轮询算法,值越大分配的请求越多
Weight int `yaml:"weight"`
}
// HealthCheckConfig 健康检查配置。
//
// 定期检查后端服务器的健康状态,自动剔除不健康的节点。
//
// 注意事项:
// - Interval 不宜设置过小,避免增加后端负担
// - Path 应该是轻量级的健康检查端点
// - 超时时间应小于检查间隔
//
// 使用示例:
//
// health_check:
// interval: 10s
// path: "/health"
// timeout: 5s
type HealthCheckConfig struct {
Path string `yaml:"path"`
Interval time.Duration `yaml:"interval"`
Timeout time.Duration `yaml:"timeout"`
}
// ProxyTimeout 代理超时配置。
//
// 控制代理请求的各个阶段超时。
//
// 注意事项:
// - Connect 超时包括 DNS 解析和 TCP 连接建立
// - Read 和 Write 超时分别控制响应读取和请求发送
// - 超时时间需要根据后端服务响应时间调整
//
// 使用示例:
//
// timeout:
// connect: 5s
// read: 30s
// write: 30s
type ProxyTimeout struct {
// Connect 连接超时
// 建立到后端服务器的连接超时
Connect time.Duration `yaml:"connect"`
// Read 读取超时
// 从后端读取响应的超时
Read time.Duration `yaml:"read"`
// Write 写入超时
// 向后端发送请求的超时
Write time.Duration `yaml:"write"`
}
// ProxyHeaders 代理请求/响应头配置。
//
// 在代理转发过程中修改 HTTP 头部。
//
// 注意事项:
// - SetRequest 添加/修改发送到后端的请求头
// - SetResponse 添加/修改返回给客户端的响应头
// - Remove 会删除指定的请求头(在发送到后端之前)
//
// 使用示例:
//
// headers:
// set_request:
// X-Forwarded-For: "$remote_addr"
// X-Real-IP: "$remote_addr"
// set_response:
// X-Proxy-By: "lolly"
// remove:
// - "X-Internal-Header"
type ProxyHeaders struct {
// SetRequest 设置请求头
// 发送到后端的请求中添加或覆盖的头部
SetRequest map[string]string `yaml:"set_request"`
// SetResponse 设置响应头
// 返回给客户端的响应中添加或覆盖的头部
SetResponse map[string]string `yaml:"set_response"`
// Remove 移除的头部
// 从发送到后端的请求中移除的头部列表
Remove []string `yaml:"remove"`
}
// ProxyCacheConfig 代理缓存配置。
//
// 缓存后端响应,减少重复请求,提高响应速度。
//
// 注意事项:
// - 仅缓存 GET 和 HEAD 请求
// - 后端响应中 Cache-Control 头会覆盖 MaxAge 设置
// - CacheLock 可防止缓存击穿,但会增加首次请求延迟
// - 谨慎缓存动态内容,避免返回过期数据
//
// 使用示例:
//
// cache:
// enabled: true
// max_age: 5m
// cache_lock: true
// stale_while_revalidate: 1m
type ProxyCacheConfig struct {
MaxAge time.Duration `yaml:"max_age"`
StaleWhileRevalidate time.Duration `yaml:"stale_while_revalidate"`
Enabled bool `yaml:"enabled"`
CacheLock bool `yaml:"cache_lock"`
}
// RedirectRewriteConfig Location/Refresh 头改写配置
//
// 用于配置代理响应中 Location 和 Refresh 头的改写行为。
//
// 注意事项:
// - Mode 支持 "default"、"off"、"custom" 三种模式
// - 未配置或空字符串时默认为 "default" 模式
// - "custom" 模式必须配置至少一条规则
//
// 使用示例:
//
// redirect_rewrite:
// mode: "default" # 或 "off" 或 "custom"
// rules:
// - pattern: "http://backend:8000/"
// replacement: "$scheme://$host:$server_port/"
type RedirectRewriteConfig struct {
// Mode 运行模式: "default" | "off" | "custom"
// default: 自动从选中的 target URL 生成规则(运行时)
// off: 禁用改写
// custom: 使用 Rules 列表(预编译)
// 未配置或空字符串时默认为 "default"
Mode string `yaml:"mode"`
// Rules 改写规则列表,仅在 Mode="custom" 时使用
Rules []RedirectRewriteRule `yaml:"rules"`
}
// RedirectRewriteRule 单条改写规则
//
// 定义 Location/Refresh 头改写的匹配模式和替换目标。
//
// 注意事项:
// - Pattern 以 ~ 开头表示正则,~* 表示大小写不敏感
// - 无 ~ 前缀时使用前缀匹配语义
// - Replacement 支持变量展开($host, $scheme, $server_port 等)
//
// 使用示例:
//
// rules:
// - pattern: "http://backend:8000/"
// replacement: "$scheme://$host:$server_port/"
// - pattern: "~^http://[^/]+:8000/(.*)$"
// replacement: "$scheme://$host/$1"
type RedirectRewriteRule struct {
// Pattern 匹配模式,支持正则(以 ~ 开头)或精确匹配
// 示例: "http://localhost:8000/" 或 "~^http://[^/]+:8000/"
Pattern string `yaml:"pattern"`
// Replacement 替换目标,支持变量展开
// 示例: "$scheme://$host:$server_port/" 或 "/"
Replacement string `yaml:"replacement"`
}
// NextUpstreamConfig 故障转移配置,定义后端失败时的自动重试行为。
//
// 当后端返回特定错误状态码或连接失败时,自动尝试下一个可用后端。
//
// 注意事项:
// - Tries 为 1 时禁用故障转移
// - 空 NextUpstream 使用默认值Tries=1禁用故障转移
// - 建议根据后端数量合理设置 Tries 值
//
// 使用示例:
//
// next_upstream:
// tries: 3
// http_codes: [502, 503, 504]
type NextUpstreamConfig struct {
HTTPCodes []int `yaml:"http_codes"`
Tries int `yaml:"tries"`
}
// SSLConfig SSL/TLS 配置。
//
// 用于配置 HTTPS 服务所需的证书和加密参数。
// 支持 TLS 1.2 和 TLS 1.3 协议,可自定义加密套件。
//
// 注意事项:
// - Cert 和 Key 为必需字段,分别指向证书和私钥文件
// - CertChain 可选,用于配置完整的证书链
// - Protocols 建议使用默认值,避免使用不安全的 TLS 1.0/1.1
// - Ciphers 仅对 TLS 1.2 有效TLS 1.3 有固定加密套件
// - 启用 OCSPStapling 可提升握手性能
//
// 使用示例:
//
// ssl:
// cert: "/etc/ssl/certs/server.crt"
// key: "/etc/ssl/private/server.key"
// cert_chain: "/etc/ssl/certs/chain.crt"
// protocols: ["TLSv1.2", "TLSv1.3"]
// ocsp_stapling: true
// hsts:
// max_age: 31536000
// include_sub_domains: true
type SSLConfig struct {
ClientVerify ClientVerifyConfig `yaml:"client_verify"`
Cert string `yaml:"cert"`
Key string `yaml:"key"`
CertChain string `yaml:"cert_chain"`
Protocols []string `yaml:"protocols"`
Ciphers []string `yaml:"ciphers"`
SessionTickets SessionTicketsConfig `yaml:"session_tickets"`
HTTP2 HTTP2Config `yaml:"http2"`
HSTS HSTSConfig `yaml:"hsts"`
OCSPStapling bool `yaml:"ocsp_stapling"`
}
// HSTSConfig HTTP Strict Transport Security 配置。
//
// 强制浏览器使用 HTTPS 访问,防止中间人攻击和协议降级攻击。
//
// 注意事项:
// - MaxAge 单位为秒,建议至少设置为 1 年31536000
// - IncludeSubDomains 为 true 时策略应用于所有子域名
// - Preload 为 true 表示申请加入浏览器预加载列表
// - 启用前确保所有站点资源都支持 HTTPS
//
// 使用示例:
//
// hsts:
// max_age: 31536000
// include_sub_domains: true
// preload: false
type HSTSConfig struct {
// MaxAge 过期时间(秒)
// 默认 315360001年建议至少 6 个月
MaxAge int `yaml:"max_age"`
// IncludeSubDomains 包含子域名
// 为 true 时策略应用于当前域名及其所有子域名
IncludeSubDomains bool `yaml:"include_sub_domains"`
// Preload 加入 HSTS 预加载列表
// 申请加入浏览器内置的 HSTS 列表
Preload bool `yaml:"preload"`
}
// SessionTicketsConfig TLS Session Ticket 配置。
//
// Session Tickets 允许 TLS 1.3 会话恢复,避免完整握手,显著提升性能。
// 密钥定期轮换增强安全性,同时保留旧密钥确保已发放的票据仍可解密。
//
// 注意事项:
// - KeyFile 为密钥存储文件路径,用于持久化密钥
// - RotateInterval 为密钥轮换间隔,建议 1-24 小时
// - RetainKeys 为保留的历史密钥数量,至少保留 2 个
// - 密钥文件权限应为 0600仅所有者可读写
//
// 使用示例:
//
// ssl:
// session_tickets:
// enabled: true
// key_file: "/var/lib/lolly/session_tickets.key"
// rotate_interval: 1h
// retain_keys: 3
type SessionTicketsConfig struct {
KeyFile string `yaml:"key_file"`
RotateInterval time.Duration `yaml:"rotate_interval"`
RetainKeys int `yaml:"retain_keys"`
Enabled bool `yaml:"enabled"`
}
// ClientVerifyConfig mTLS 客户端证书验证配置。
//
// 配置双向 TLS 认证,要求客户端提供有效证书才能建立连接。
// 适用于需要强身份验证的场景,如 API 服务、内部系统通信。
//
// 注意事项:
// - Mode 可选值none、request、require、optional_no_ca
// - ClientCA 为客户端 CA 证书文件路径(必需)
// - VerifyDepth 为证书链验证深度,默认 1
// - CRL 为证书撤销列表文件路径(可选)
//
// 使用示例:
//
// ssl:
// client_verify:
// enabled: true
// mode: "require"
// client_ca: "/etc/ssl/ca/client-ca.crt"
// verify_depth: 2
// crl: "/etc/ssl/ca/client-ca.crl"
type ClientVerifyConfig struct {
Mode string `yaml:"mode"`
ClientCA string `yaml:"client_ca"`
CRL string `yaml:"crl"`
VerifyDepth int `yaml:"verify_depth"`
Enabled bool `yaml:"enabled"`
}
// SecurityConfig 安全配置,包含访问控制、限流、认证和安全头部。
//
// 用于保护服务器免受各种网络攻击和滥用。
//
// 注意事项:
// - Access 配置 IP 黑白名单控制访问来源
// - RateLimit 配置请求频率限制防止 DDoS 攻击
// - Auth 配置 HTTP Basic 认证保护敏感资源
// - Headers 配置安全响应头部增强浏览器安全
// - 各项配置可以组合使用,增强安全性
//
// 使用示例:
//
// security:
// access:
// allow: ["192.168.1.0/24"]
// deny: ["10.0.0.0/8"]
// rate_limit:
// request_rate: 100
// burst: 150
// auth:
// type: "basic"
// users:
// - name: "admin"
// password: "$2y$10$..."
// headers:
// x_frame_options: "DENY"
type SecurityConfig struct {
Headers SecurityHeaders `yaml:"headers"`
Access AccessConfig `yaml:"access"`
ErrorPage ErrorPageConfig `yaml:"error_page"`
Auth AuthConfig `yaml:"auth"`
AuthRequest AuthRequestConfig `yaml:"auth_request"`
RateLimit RateLimitConfig `yaml:"rate_limit"`
}
// AccessConfig IP 访问控制配置。
//
// 通过 IP 地址或 CIDR 范围控制访问权限,支持基于 GeoIP 的国家代码访问控制。
//
// 注意事项:
// - Allow 和 Deny 列表按配置顺序匹配
// - Default 指定未匹配时的默认动作
// - TrustedProxies 用于正确获取客户端真实 IP
// - GeoIP 配置启用后,会基于国家代码进行二次检查
// - 支持 IPv4 和 IPv6 地址格式
//
// 使用示例:
//
// access:
// allow: ["192.168.1.0/24", "10.0.0.0/8"]
// deny: ["192.168.1.100"]
// default: "deny"
// trusted_proxies: ["172.16.0.0/16"]
// geoip:
// enabled: true
// database: "/var/lib/geoip/GeoIP2-Country.mmdb"
// allow_countries: ["US", "JP", "GB"]
// deny_countries: ["CN", "RU"]
// default: "deny"
// cache_size: 10000
// cache_ttl: 1h
// private_ip_behavior: "allow"
type AccessConfig struct {
// Allow 允许的 IP/CIDR 列表
// 配置允许访问的 IP 地址或网段
Allow []string `yaml:"allow"`
// Deny 拒绝的 IP/CIDR 列表
// 配置拒绝访问的 IP 地址或网段
Deny []string `yaml:"deny"`
// TrustedProxies 可信代理 CIDR 列表
// 用于正确解析 X-Forwarded-For 头部获取真实客户端 IP
TrustedProxies []string `yaml:"trusted_proxies"`
// Default 默认动作
// 未匹配任何规则时的处理方式allow 或 deny
Default string `yaml:"default"`
// GeoIP GeoIP 国家代码访问控制配置
GeoIP GeoIPConfig `yaml:"geoip"`
}
// GeoIPConfig GeoIP 访问控制配置。
//
// 通过 MaxMind GeoIP2 数据库查询 IP 所属国家,实现基于国家代码的访问控制。
//
// 注意事项:
// - Database 为 GeoIP2 数据库文件路径(.mmdb 格式)
// - AllowCountries 和 DenyCountries 使用 ISO 3166-1 alpha-2 国家代码
// - CacheSize 设置 LRU 缓存最大条目数0 表示使用默认值 10000
// - CacheTTL 设置缓存有效期0 表示使用默认值 1 小时
// - PrivateIPBehavior 控制私有 IP 的处理策略
//
// 使用示例:
//
// geoip:
// enabled: true
// database: "/var/lib/geoip/GeoIP2-Country.mmdb"
// allow_countries: ["US", "JP", "GB"]
// deny_countries: ["CN", "RU"]
// default: "deny"
// cache_size: 10000
// cache_ttl: 1h
// private_ip_behavior: "allow"
type GeoIPConfig struct {
Database string `yaml:"database"`
Default string `yaml:"default"`
PrivateIPBehavior string `yaml:"private_ip_behavior"`
AllowCountries []string `yaml:"allow_countries"`
DenyCountries []string `yaml:"deny_countries"`
CacheSize int `yaml:"cache_size"`
CacheTTL time.Duration `yaml:"cache_ttl"`
Enabled bool `yaml:"enabled"`
}
// RateLimitConfig 速率限制配置。
//
// 限制请求频率防止 DDoS 攻击和资源滥用。
//
// 注意事项:
// - RequestRate 为每秒允许的最大请求数
// - Burst 为突发流量允许的最大请求数
// - ConnLimit 为单个 IP 的最大并发连接数
// - Algorithm 支持 token_bucket 和 sliding_window 两种算法
// - SlidingWindow 仅在 sliding_window 算法下生效
//
// 使用示例:
//
// rate_limit:
// request_rate: 100
// burst: 150
// conn_limit: 50
// algorithm: "token_bucket"
// key: "ip"
type RateLimitConfig struct {
Key string `yaml:"key"`
Algorithm string `yaml:"algorithm"`
SlidingWindowMode string `yaml:"sliding_window_mode"`
RequestRate int `yaml:"request_rate"`
Burst int `yaml:"burst"`
ConnLimit int `yaml:"conn_limit"`
SlidingWindow int `yaml:"sliding_window"`
}
// AuthConfig 认证配置。
//
// 配置 HTTP Basic 认证保护敏感资源。
//
// 注意事项:
// - Type 目前仅支持 basic
// - RequireTLS 默认为 true强制 HTTPS 传输
// - Algorithm 支持 bcrypt 和 argon2id
// - Users 中 Password 字段存储的是密码哈希而非明文
// - MinPasswordLength 控制密码最小长度要求
//
// 使用示例:
//
// auth:
// type: "basic"
// require_tls: true
// algorithm: "bcrypt"
// realm: "Secure Area"
// min_password_length: 8
// users:
// - name: "admin"
// password: "$2y$10$..."
type AuthConfig struct {
Type string `yaml:"type"`
Algorithm string `yaml:"algorithm"`
Realm string `yaml:"realm"`
Users []User `yaml:"users"`
MinPasswordLength int `yaml:"min_password_length"`
RequireTLS bool `yaml:"require_tls"`
}
// User 认证用户配置。
//
// 定义单个认证用户的凭据。
//
// 注意事项:
// - Name 为用户标识,区分大小写
// - Password 存储的是哈希值而非明文密码
// - 支持的哈希格式取决于 Algorithm 设置
//
// 使用示例:
//
// users:
// - name: "admin"
// password: "$2y$10$N9qo8uLOickgx2ZMRZoMy..."
type User struct {
// Name 用户名
// 认证时使用的用户标识
Name string `yaml:"name"`
// Password 密码哈希
// bcrypt 或 argon2id 哈希值,非明文密码
Password string `yaml:"password"`
}
// SecurityHeaders 安全头部配置。
//
// 配置 HTTP 安全响应头部增强浏览器安全。
//
// 注意事项:
// - XFrameOptions 防止点击劫持攻击
// - XContentTypeOptions 防止 MIME 类型嗅探
// - ContentSecurityPolicy 控制资源加载策略
// - ReferrerPolicy 控制 Referer 头发送策略
// - PermissionsPolicy 控制浏览器功能权限
//
// 使用示例:
//
// headers:
// x_frame_options: "DENY"
// x_content_type_options: "nosniff"
// content_security_policy: "default-src 'self'"
// referrer_policy: "strict-origin-when-cross-origin"
type SecurityHeaders struct {
// XFrameOptions X-Frame-Options 头部
// 可选值DENY、SAMEORIGIN防止页面被嵌入 iframe
XFrameOptions string `yaml:"x_frame_options"`
// XContentTypeOptions X-Content-Type-Options 头部
// 建议值nosniff防止浏览器 MIME 类型嗅探
XContentTypeOptions string `yaml:"x_content_type_options"`
// ContentSecurityPolicy Content-Security-Policy 头部
// 控制页面可以加载的资源来源
ContentSecurityPolicy string `yaml:"content_security_policy"`
// ReferrerPolicy Referrer-Policy 头部
// 控制 Referer 头的发送策略
ReferrerPolicy string `yaml:"referrer_policy"`
// PermissionsPolicy Permissions-Policy 头部
// 控制浏览器功能权限(原 Feature-Policy
PermissionsPolicy string `yaml:"permissions_policy"`
}
// ErrorPageConfig 自定义错误页面配置。
//
// 允许为特定 HTTP 状态码配置自定义错误页面。
// 错误页面文件在启动时预加载到内存中,运行时不进行文件 I/O。
//
// 注意事项:
// - 错误页面文件路径可以是相对路径或绝对路径
// - 所有错误页面加载失败时会阻止服务器启动
// - 部分错误页面加载失败会记录警告但允许启动
// - 支持可选的响应状态码覆盖
//
// 使用示例:
//
// error_page:
// pages:
// 404: "/var/www/errors/404.html"
// 500: "/var/www/errors/500.html"
// 503: "/var/www/errors/503.html"
// default: "/var/www/errors/error.html"
// response_code: 200 # 可选:覆盖响应状态码
type ErrorPageConfig struct {
// Pages 状态码到错误页面文件的映射
// key 为 HTTP 状态码(如 404, 500value 为文件路径
Pages map[int]string `yaml:"pages"`
// Default 默认错误页面
// 当特定状态码没有配置时使用
Default string `yaml:"default"`
// ResponseCode 响应状态码覆盖
// 如果不为 0所有错误页面响应将使用此状态码
// 例如设置为 200 时,即使发生错误也返回 200 OK
ResponseCode int `yaml:"response_code"`
}
// AuthRequestConfig 外部认证子请求配置。
//
// 将认证委托给外部服务,根据子请求的响应状态码决定是否允许原请求继续。
// 适用于需要复杂认证逻辑或与现有认证系统集成的场景。
//
// 行为规则:
// - 2xx 响应:认证通过,原请求继续处理
// - 401/403 响应:认证失败,返回相应状态码
// - 其他响应或超时:返回 500 内部服务器错误
// - 认证服务不可用时:返回 500 内部服务器错误
//
// 注意事项:
// - 认证请求使用独立的连接池,避免影响主服务
// - 支持变量展开(如 $host, $uri, $request_uri
// - 建议配置合理的超时时间,避免长时间阻塞
// - 认证请求会携带原请求的头信息(如 Cookie, Authorization
//
// 使用示例:
//
// security:
// auth_request:
// uri: /auth
// method: GET
// auth_timeout: 5s
// headers:
// X-Original-Uri: $request_uri
// X-Original-Host: $host
type AuthRequestConfig struct {
Headers map[string]string `yaml:"headers"`
URI string `yaml:"uri"`
Method string `yaml:"method"`
ForwardHeaders []string `yaml:"forward_headers"`
Timeout time.Duration `yaml:"auth_timeout"`
Enabled bool `yaml:"enabled"`
}
// RewriteRule URL 重写规则。
//
// 用于在代理或静态文件服务前修改请求 URL。
//
// 注意事项:
// - Pattern 为正则表达式,用于匹配原始 URL
// - Replacement 为替换后的目标 URL支持捕获组
// - Flag 控制重写行为last、redirect、permanent、break
// - 规则按顺序执行,匹配后根据 Flag 决定是否继续
//
// 使用示例:
//
// rewrite:
// - pattern: "^/old/(.*)$"
// replacement: "/new/$1"
// flag: "permanent"
// - pattern: "^/api/(.*)$"
// replacement: "/v1/$1"
// flag: "last"
type RewriteRule struct {
// Pattern 匹配模式
// 正则表达式,用于匹配请求 URL
Pattern string `yaml:"pattern"`
// Replacement 替换目标
// 替换后的 URL 路径,支持 $1、$2 等捕获组引用
Replacement string `yaml:"replacement"`
// Flag 标志
// 可选值:
// - last停止后续规则匹配
// - redirect返回 302 临时重定向
// - permanent返回 301 永久重定向
// - break停止规则匹配但继续处理
Flag string `yaml:"flag"`
}
// CompressionConfig 响应压缩配置。
//
// 配置响应内容压缩,减少传输数据量。
//
// 注意事项:
// - Type 支持 gzip、brotli 或 both同时使用两种
// - Level 压缩级别 1-9越高压缩率越好但 CPU 消耗越大
// - MinSize 低于此大小的响应不压缩
// - Types 指定哪些 MIME 类型进行压缩
// - GzipStatic 启用后优先使用预压缩文件
//
// 使用示例:
//
// compression:
// type: "gzip"
// level: 6
// min_size: 1024
// types: ["text/html", "text/css", "application/json"]
// gzip_static: true
// gzip_static_extensions: [".gz"]
type CompressionConfig struct {
Type string `yaml:"type"`
Types []string `yaml:"types"`
GzipStaticExtensions []string `yaml:"gzip_static_extensions"`
Level int `yaml:"level"`
MinSize int `yaml:"min_size"`
GzipStatic bool `yaml:"gzip_static"`
}
// LoggingConfig 日志配置。
//
// 配置访问日志和错误日志的输出行为。
//
// 注意事项:
// - Format 控制日志格式text 或 json
// - Access 配置访问日志(记录每个请求)
// - Error 配置错误日志(记录错误信息)
// - Path 为空时日志输出到标准输出/标准错误
//
// 使用示例:
//
// logging:
// format: "json"
// access:
// path: "/var/log/lolly/access.log"
// format: "combined"
// error:
// path: "/var/log/lolly/error.log"
// level: "warn"
type LoggingConfig struct {
// Format 全局格式
// 可选值text默认、json
Format string `yaml:"format"`
// Access 访问日志配置
Access AccessLogConfig `yaml:"access"`
// Error 错误日志配置
Error ErrorLogConfig `yaml:"error"`
}
// ShutdownConfig 服务器关闭配置。
//
// 用于配置服务器在接收到不同信号时的关闭超时行为。
// 优雅停止会等待正在处理的请求完成,快速停止会立即中断连接。
//
// 注意事项:
// - graceful_timeout = 0 表示使用默认值30s
// - fast_timeout = 0 表示使用默认值5s
// - graceful_timeout 应显著大于 fast_timeout
// - 两个值都必须 >= 0负数在验证时会报错
//
// 使用示例:
//
// shutdown:
// graceful_timeout: 30s # SIGQUIT 优雅停止超时
// fast_timeout: 5s # SIGINT/SIGTERM 快速停止超时
type ShutdownConfig struct {
// GracefulTimeout 优雅停止超时SIGQUIT
// 接收到 SIGQUIT 信号后,等待活跃请求完成的最大时间
// 默认: 30s当值为 0 时使用默认值)
GracefulTimeout time.Duration `yaml:"graceful_timeout"`
// FastTimeout 快速停止超时SIGINT/SIGTERM
// 接收到 SIGINT 或 SIGTERM 信号后,等待服务器关闭的最大时间
// 默认: 5s当值为 0 时使用默认值)
FastTimeout time.Duration `yaml:"fast_timeout"`
}
// AccessLogConfig 访问日志配置。
//
// 配置访问日志的输出位置和格式。
//
// 注意事项:
// - Path 为日志文件路径,为空则输出到 stdout
// - Format 支持预设格式或自定义格式
// - 常用预设格式common、combined
//
// 使用示例:
//
// access:
// path: "/var/log/lolly/access.log"
// format: "combined"
type AccessLogConfig struct {
// Path 日志文件路径
// 访问日志的输出文件,为空则输出到标准输出
Path string `yaml:"path"`
// Format 日志格式
// 预设格式或自定义日志格式字符串
Format string `yaml:"format"`
}
// ErrorLogConfig 错误日志配置。
//
// 配置错误日志的输出位置和级别。
//
// 注意事项:
// - Path 为日志文件路径,为空则输出到 stderr
// - Level 控制记录的日志级别阈值
// - 可选级别debug、info、warn、error
//
// 使用示例:
//
// error:
// path: "/var/log/lolly/error.log"
// level: "error"
type ErrorLogConfig struct {
// Path 日志文件路径
// 错误日志的输出文件,为空则输出到标准错误
Path string `yaml:"path"`
// Level 日志级别
// 可选值debug、info、warn、error
Level string `yaml:"level"`
}
// PerformanceConfig 性能配置。
//
// 配置服务器性能优化相关参数。
//
// 注意事项:
// - GoroutinePool 复用 goroutine 减少创建开销
// - FileCache 缓存静态文件内容提升响应速度
// - Transport 配置代理连接的连接池参数
//
// 使用示例:
//
// performance:
// goroutine_pool:
// enabled: true
// max_workers: 1000
// file_cache:
// max_entries: 10000
// max_size: 1073741824
// transport:
// max_idle_conns: 100
type PerformanceConfig struct {
// GoroutinePool Goroutine 池配置
// 控制 worker goroutine 的复用行为
GoroutinePool GoroutinePoolConfig `yaml:"goroutine_pool"`
// FileCache 文件缓存配置
// 缓存静态文件内容避免重复磁盘 IO
FileCache FileCacheConfig `yaml:"file_cache"`
// Transport HTTP Transport 配置
// 代理连接池的参数设置
Transport TransportConfig `yaml:"transport"`
}
// GoroutinePoolConfig Goroutine 池配置。
//
// 复用 goroutine 减少创建和销毁开销。
//
// 注意事项:
// - Enabled 为 true 时启用 goroutine 池
// - MaxWorkers 限制最大并发 worker 数
// - MinWorkers 预热 worker 数量
// - IdleTimeout 空闲 worker 回收时间
//
// 使用示例:
//
// goroutine_pool:
// enabled: true
// max_workers: 1000
// min_workers: 100
// idle_timeout: 60s
type GoroutinePoolConfig struct {
// Enabled 是否启用
Enabled bool `yaml:"enabled"`
// MaxWorkers 最大 worker 数
// 限制同时运行的最大 goroutine 数量
MaxWorkers int `yaml:"max_workers"`
// MinWorkers 最小 worker 数(预热)
// 启动时预创建的 goroutine 数量
MinWorkers int `yaml:"min_workers"`
// IdleTimeout 空闲超时
// 空闲 worker 超过此时间将被回收
IdleTimeout time.Duration `yaml:"idle_timeout"`
}
// FileCacheConfig 文件缓存配置。
//
// 缓存静态文件内容减少磁盘 IO。
//
// 注意事项:
// - MaxEntries 限制最大缓存文件数量
// - MaxSize 限制缓存总内存使用量(字节)
// - Inactive 超过此时间未访问的文件将被淘汰
//
// 使用示例:
//
// file_cache:
// max_entries: 10000
// max_size: 1073741824
// inactive: 60s
type FileCacheConfig struct {
// MaxEntries 最大缓存条目数
// 缓存文件的最大数量限制
MaxEntries int64 `yaml:"max_entries"`
// MaxSize 内存上限(字节)
// 缓存占用的最大内存限制
MaxSize int64 `yaml:"max_size"`
// Inactive 未访问淘汰时间
// 超过此时间未被访问的缓存将被清除
Inactive time.Duration `yaml:"inactive"`
}
// TransportConfig HTTP Transport 配置。
//
// 配置代理后端连接的连接池参数。
//
// 注意事项:
// - MaxIdleConnsPerHost 控制每个后端主机的空闲连接
// - IdleConnTimeout 控制空闲连接的保持时间
// - MaxConnsPerHost 限制每个后端主机的总连接数
//
// 使用示例:
//
// transport:
// max_idle_conns_per_host: 10
// idle_conn_timeout: 90s
// max_conns_per_host: 100
type TransportConfig struct {
// MaxIdleConnsPerHost 每主机最大空闲连接
// 单个后端主机的最大空闲连接数
MaxIdleConnsPerHost int `yaml:"max_idle_conns_per_host"`
// IdleConnTimeout 空闲连接超时
// 空闲连接的最大存活时间
IdleConnTimeout time.Duration `yaml:"idle_conn_timeout"`
// MaxConnsPerHost 每主机最大连接数
// 单个后端主机的总连接数上限
MaxConnsPerHost int `yaml:"max_conns_per_host"`
}
// MonitoringConfig 监控配置。
//
// 配置服务状态监控和健康检查端点。
//
// 注意事项:
// - Status 配置状态检查端点
// - 监控端点建议限制访问 IP 防止信息泄露
//
// 使用示例:
//
// monitoring:
// status:
// path: "/status"
// allow: ["127.0.0.1", "10.0.0.0/8"]
type MonitoringConfig struct {
// Status 状态端点配置
// 服务健康状态检查端点
Status StatusConfig `yaml:"status"`
// Pprof pprof 性能分析端点配置
// 用于收集 CPU、内存等性能数据支持 PGO 优化
Pprof PprofConfig `yaml:"pprof"`
}
// PprofConfig pprof 性能分析端点配置。
//
// 配置 pprof 端点用于收集运行时性能数据。
// 收集的 profile 可用于 PGO (Profile-Guided Optimization) 构建。
//
// 注意事项:
// - 生产环境仅在收集 profile 时启用,完成后关闭
// - 建议严格限制访问 IP防止性能数据泄露
// - CPU profile 收集需要代表性 workload
//
// 使用示例:
//
// pprof:
// enabled: true
// path: "/debug/pprof"
// allow: ["127.0.0.1"]
type PprofConfig struct {
Path string `yaml:"path"`
Allow []string `yaml:"allow"`
Enabled bool `yaml:"enabled"`
}
// StatusConfig 状态监控端点配置。
//
// 配置服务状态检查端点的路径和访问控制。
//
// 注意事项:
// - Path 为状态端点的 URL 路径
// - Allow 限制可访问的 IP 地址列表
// - 生产环境建议严格限制访问来源
//
// 使用示例:
//
// status:
// path: "/status"
// allow: ["127.0.0.1", "192.168.0.0/16"]
type StatusConfig struct {
Path string `yaml:"path"`
Format string `yaml:"format"`
Allow []string `yaml:"allow"`
}
// CacheAPIConfig 缓存 API 配置。
//
// 配置缓存清理 API 端点,支持主动清理代理缓存。
//
// 注意事项:
// - Enabled 默认为 false需显式启用
// - Allow 限制可访问的 IP 地址列表
// - Auth 配置认证方式,推荐使用 token 认证
//
// 使用示例:
//
// cache_api:
// enabled: true
// path: "/_cache/purge"
// allow: ["127.0.0.1", "10.0.0.0/8"]
// auth:
// type: "token"
// token: "${CACHE_API_TOKEN}"
type CacheAPIConfig struct {
Auth CacheAPIAuthConfig `yaml:"auth"`
Path string `yaml:"path"`
Allow []string `yaml:"allow"`
Enabled bool `yaml:"enabled"`
}
// CacheAPIAuthConfig 缓存 API 认证配置。
type CacheAPIAuthConfig struct {
// Type 认证类型
// 支持 "none" 和 "token" 两种类型
// 默认为 "none"
Type string `yaml:"type"`
// Token 认证令牌
// 当 Type 为 "token" 时使用
// 支持环境变量替换,如 "${CACHE_API_TOKEN}"
Token string `yaml:"token"`
}
// LuaMiddlewareConfig Lua 中间件配置(配置文件格式)
//
// 用于配置 Lua 中间件的行为,包括脚本路径、执行阶段和全局设置。
//
// 注意事项:
// - Enabled 为 true 时启用 Lua 中间件
// - Scripts 配置要执行的脚本列表
// - GlobalSettings 控制 Lua 引擎的全局行为
//
// 使用示例:
//
// lua:
// enabled: true
// scripts:
// - path: "/scripts/auth.lua"
// phase: "access"
// timeout: 10s
// global_settings:
// max_concurrent_coroutines: 1000
// coroutine_timeout: 30s
type LuaMiddlewareConfig struct {
Scripts []LuaScriptConfig `yaml:"scripts"`
GlobalSettings LuaGlobalSettings `yaml:"global_settings"`
Enabled bool `yaml:"enabled"`
}
// LuaScriptConfig 单个脚本配置
//
// 定义单个 Lua 脚本的执行参数。
//
// 注意事项:
// - Path 为脚本文件路径,必需字段
// - Phase 为执行阶段,必需字段
// - Timeout 控制脚本执行超时
//
// 使用示例:
//
// scripts:
// - path: "/scripts/auth.lua"
// phase: "access"
// timeout: 10s
// enabled: true
type LuaScriptConfig struct {
// Path 脚本路径
Path string `yaml:"path"`
// Phase 执行阶段
// 可选值rewrite、access、content、log、header_filter、body_filter
Phase string `yaml:"phase"`
// Timeout 执行超时
Timeout time.Duration `yaml:"timeout"`
// Enabled 是否启用此脚本(默认 true
Enabled bool `yaml:"enabled"`
}
// LuaGlobalSettings 全局 Lua 设置
//
// 控制 Lua 引擎的全局行为。
//
// 注意事项:
// - MaxConcurrentCoroutines 控制最大并发协程数
// - CoroutineTimeout 控制协程执行超时
// - CodeCacheSize 控制字节码缓存大小
// - CoroutineStackSize 控制协程栈大小默认64
// - MinimizeStackMemory 启用栈内存自动收缩
// - CoroutinePoolWarmup 协程池预热数量
//
// 使用示例:
//
// global_settings:
// max_concurrent_coroutines: 1000
// coroutine_timeout: 30s
// code_cache_size: 1000
// enable_file_watch: true
// max_execution_time: 30s
// coroutine_stack_size: 64
// minimize_stack_memory: true
// coroutine_pool_warmup: 4
type LuaGlobalSettings struct {
// MaxConcurrentCoroutines 最大并发协程数
MaxConcurrentCoroutines int `yaml:"max_concurrent_coroutines"`
// CoroutineTimeout 协程执行超时
CoroutineTimeout time.Duration `yaml:"coroutine_timeout"`
// CodeCacheSize 字节码缓存条目数
CodeCacheSize int `yaml:"code_cache_size"`
// MaxExecutionTime 单脚本最大执行时间
MaxExecutionTime time.Duration `yaml:"max_execution_time"`
// CoroutineStackSize 协程栈大小默认64最大256
// 较小的栈减少内存分配,适用于简单脚本
CoroutineStackSize int `yaml:"coroutine_stack_size"`
// CoroutinePoolWarmup 协程池预热数量,启动时预创建
CoroutinePoolWarmup int `yaml:"coroutine_pool_warmup"`
// EnableFileWatch 启用文件变更检测
EnableFileWatch bool `yaml:"enable_file_watch"`
// MinimizeStackMemory 启用栈内存自动收缩以减少内存占用
MinimizeStackMemory bool `yaml:"minimize_stack_memory"`
}
// StreamConfig TCP/UDP Stream 代理配置。
//
// 用于四层网络代理如数据库、Redis 等 TCP/UDP 服务。
//
// 注意事项:
// - Listen 配置监听地址
// - Protocol 支持 tcp 或 udp
// - Upstream 配置后端目标列表
// - Stream 代理工作在传输层,不解析应用层协议
//
// 使用示例:
//
// stream:
// - listen: ":3306"
// protocol: "tcp"
// upstream:
// targets:
// - addr: "mysql1:3306"
// weight: 3
// - addr: "mysql2:3306"
// weight: 1
// load_balance: "round_robin"
type StreamConfig struct {
Listen string `yaml:"listen"`
Protocol string `yaml:"protocol"`
Upstream StreamUpstream `yaml:"upstream"`
ProxySSL StreamProxySSLConfig `yaml:"proxy_ssl"`
SSL StreamSSLConfig `yaml:"ssl"`
}
// StreamUpstream Stream 上游配置。
//
// 配置 Stream 代理的后端服务器列表。
//
// 注意事项:
// - Targets 配置后端服务器地址
// - LoadBalance 配置负载均衡算法
//
// 使用示例:
//
// upstream:
// targets:
// - addr: "backend1:3306"
// weight: 3
// load_balance: "round_robin"
type StreamUpstream struct {
LoadBalance string `yaml:"load_balance"`
Targets []StreamTarget `yaml:"targets"`
}
// StreamTarget Stream 目标配置。
//
// 定义单个 Stream 后端服务器。
//
// 注意事项:
// - Addr 为后端服务器地址
// - Weight 在加权轮询算法下生效
//
// 使用示例:
//
// targets:
// - addr: "mysql1:3306"
// weight: 3
// - addr: "mysql2:3306"
// weight: 1
type StreamTarget struct {
// Addr 目标地址
// 后端服务器地址,如 "host:port"
Addr string `yaml:"addr"`
// Weight 权重
// 用于加权轮询负载均衡
Weight int `yaml:"weight"`
}
// StreamSSLConfig Stream SSL 服务端配置。
//
// 配置 Stream 模块的 TLS 终端功能,用于加密 TCP 流量。
//
// 注意事项:
// - 仅对 TCP 协议有效UDP 不支持 TLS
// - 证书文件需要 PEM 格式
// - 支持配置客户端证书验证mTLS
//
// 使用示例:
//
// stream:
// - listen: ":3306"
// protocol: "tcp"
// ssl:
// enabled: true
// cert: "/etc/ssl/server.crt"
// key: "/etc/ssl/server.key"
// upstream:
// targets:
// - addr: "mysql:3306"
type StreamSSLConfig struct {
Cert string `yaml:"cert"`
Key string `yaml:"key"`
ClientCA string `yaml:"client_ca"`
Protocols []string `yaml:"protocols"`
Ciphers []string `yaml:"ciphers"`
VerifyDepth int `yaml:"verify_depth"`
Enabled bool `yaml:"enabled"`
}
// StreamProxySSLConfig Stream 上游 SSL 配置。
//
// 配置到上游服务器的 TLS 连接,用于加密代理到后端的流量。
//
// 注意事项:
// - 启用后,代理将使用 TLS 连接到上游
// - 支持客户端证书mTLS和服务器证书验证
// - ServerName 用于 SNI 和证书验证
//
// 使用示例:
//
// stream:
// - listen: ":3306"
// protocol: "tcp"
// proxy_ssl:
// enabled: true
// verify: true
// trusted_ca: "/etc/ssl/ca.crt"
// server_name: "mysql.internal"
// upstream:
// targets:
// - addr: "mysql:3306"
type StreamProxySSLConfig struct {
TrustedCA string `yaml:"trusted_ca"`
ServerName string `yaml:"server_name"`
Cert string `yaml:"cert"`
Key string `yaml:"key"`
Protocols []string `yaml:"protocols"`
Enabled bool `yaml:"enabled"`
Verify bool `yaml:"verify"`
SessionReuse bool `yaml:"session_reuse"`
}
// Load 从文件加载配置。
//
// 读取指定路径的 YAML 配置文件,解析并验证配置内容。
//
// 参数:
// - path: 配置文件路径
//
// 返回值:
// - *Config: 解析后的配置对象
// - error: 读取、解析或验证失败时的错误信息
//
// 注意事项:
// - 加载后会自动调用 Validate 进行配置验证
// - 文件不存在或格式错误都会返回错误
func Load(path string) (*Config, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("读取配置文件失败: %w", err)
}
var cfg Config
if err := yaml.Unmarshal(data, &cfg); err != nil {
return nil, fmt.Errorf("解析配置文件失败: %w", err)
}
if err := Validate(&cfg); err != nil {
return nil, fmt.Errorf("配置验证失败: %w", err)
}
return &cfg, nil
}
// LoadFromString 从 YAML 字符串加载配置。
//
// 解析 YAML 格式的配置字符串,适用于从环境变量或命令行参数加载配置。
//
// 参数:
// - yamlStr: YAML 格式的配置字符串
//
// 返回值:
// - *Config: 解析后的配置对象
// - error: 解析或验证失败时的错误信息
//
// 注意事项:
// - 加载后会自动调用 Validate 进行配置验证
func LoadFromString(yamlStr string) (*Config, error) {
var cfg Config
if err := yaml.Unmarshal([]byte(yamlStr), &cfg); err != nil {
return nil, fmt.Errorf("解析配置失败: %w", err)
}
if err := Validate(&cfg); err != nil {
return nil, fmt.Errorf("配置验证失败: %w", err)
}
return &cfg, nil
}
// Save 保存配置到文件。
//
// 将配置对象序列化为 YAML 格式并写入指定文件。
//
// 参数:
// - cfg: 配置对象
// - path: 目标文件路径
//
// 返回值:
// - error: 序列化或写入失败时的错误信息
//
// 注意事项:
// - 文件权限设为 0644
func Save(cfg *Config, path string) error {
data, err := yaml.Marshal(cfg)
if err != nil {
return fmt.Errorf("序列化配置失败: %w", err)
}
if err := os.WriteFile(path, data, 0o644); err != nil {
return fmt.Errorf("写入配置文件失败: %w", err)
}
return nil
}
// HasServers 检查是否为多虚拟主机模式。
//
// 返回值:
// - bool: 如果配置了 servers 列表且非空,返回 true
func (c *Config) HasServers() bool {
return len(c.Servers) > 0
}
// GetDefaultServerFromList 从 servers 列表中获取默认服务器配置。
//
// 遍历 servers 列表,返回第一个 Default 标记为 true 的服务器。
// 用于在虚拟主机模式下获取默认服务器的配置作为 fallback。
//
// 返回值:
// - *ServerConfig: 默认服务器配置,如无则返回 nil
func (c *Config) GetDefaultServerFromList() *ServerConfig {
for i := range c.Servers {
if c.Servers[i].Default {
return &c.Servers[i]
}
}
return nil
}
// GetMode 获取服务器运行模式。
//
// 如果 Mode 显式设置(非 auto返回设置的值。
// 如果 Mode 是 auto 或未设置,根据配置自动推断:
// - servers 数量 == 1 → single
// - servers 数量 > 1 且所有 listen 地址相同 → vhost
// - servers 数量 > 1 且 listen 地址不同 → multi_server
//
// 返回值:
// - ServerMode: 推断后的服务器运行模式
func (c *Config) GetMode() ServerMode {
// 如果显式设置了非 auto 模式,直接返回
if c.Mode != "" && c.Mode != ServerModeAuto {
return c.Mode
}
// 自动推断模式
serverCount := len(c.Servers)
// servers 为空 → auto配置验证会确保至少有一个服务器
if serverCount == 0 {
return ServerModeAuto
}
// servers 数量 == 1 → single
if serverCount == 1 {
return ServerModeSingle
}
// servers 数量 > 1检查 listen 地址
firstListen := c.Servers[0].Listen
allSameListen := true
for i := 1; i < serverCount; i++ {
if c.Servers[i].Listen != firstListen {
allSameListen = false
break
}
}
// 所有 listen 地址相同 → vhost否则 → multi_server
if allSameListen {
return ServerModeVHost
}
return ServerModeMultiServer
}
// Validate 配置验证入口。
//
// 验证配置的完整性和有效性,检查是否至少配置了一个服务器,
// 并递归验证所有服务器配置。
//
// 参数:
// - cfg: 配置对象
//
// 返回值:
// - error: 验证失败时的错误信息,包含具体字段路径
//
// 验证规则:
// - 必须配置 servers 数组且至少包含一个服务器
// - 所有服务器配置必须通过 validateServer 验证
func Validate(cfg *Config) error {
// 必须配置 servers 且至少包含一个服务器
if !cfg.HasServers() {
return errors.New("必须配置 servers 且至少包含一个服务器")
}
// 验证模式
if err := validateMode(cfg.Mode); err != nil {
return err
}
// 验证监听地址冲突multi_server 模式)
if err := validateListenConflicts(cfg.Servers, cfg.GetMode()); err != nil {
return err
}
// 验证 default 服务器唯一性
if err := validateDefaultServer(cfg.Servers); err != nil {
return err
}
// 验证所有服务器
for i := range cfg.Servers {
if err := validateServer(&cfg.Servers[i], false); err != nil {
return fmt.Errorf("servers[%d]: %w", i, err)
}
}
// 验证 Stream 配置
for i := range cfg.Stream {
if err := validateStream(&cfg.Stream[i]); err != nil {
return fmt.Errorf("stream[%d]: %w", i, err)
}
}
// 验证日志配置
if err := validateLogging(&cfg.Logging); err != nil {
return err
}
// 验证性能配置
if err := validatePerformance(&cfg.Performance); err != nil {
return fmt.Errorf("performance: %w", err)
}
// 验证 Resolver 配置
if err := cfg.Resolver.Validate(); err != nil {
return fmt.Errorf("resolver: %w", err)
}
// 验证变量配置
if err := validateVariables(&cfg.Variables); err != nil {
return fmt.Errorf("variables: %w", err)
}
// 验证关闭配置
if err := validateShutdown(&cfg.Shutdown); err != nil {
return err
}
return nil
}
// validateShutdown 验证关闭配置。
func validateShutdown(cfg *ShutdownConfig) error {
if cfg.GracefulTimeout < 0 {
return errors.New("shutdown.graceful_timeout 不能为负数")
}
if cfg.FastTimeout < 0 {
return errors.New("shutdown.fast_timeout 不能为负数")
}
// 0 值表示使用默认值,在应用层处理
return nil
}
// ResolverConfig DNS 解析器配置。
//
// 配置 DNS 解析器的行为,包括服务器地址、缓存 TTL、超时等。
// 启用后可实现动态 DNS 解析和缓存,支持后端域名的动态解析。
//
// 注意事项:
// - Enabled 为 true 时启用 DNS 解析器
// - Addresses 配置 DNS 服务器地址,如 "8.8.8.8:53"
// - Valid 为缓存有效期TTL建议 30s-300s
// - Timeout 为单次查询超时时间
//
// 使用示例:
//
// resolver:
// enabled: true
// addresses:
// - "8.8.8.8:53"
// - "8.8.4.4:53"
// valid: 30s
// timeout: 5s
// ipv4: true
// ipv6: false
// cache_size: 1024
type ResolverConfig struct {
Addresses []string `yaml:"addresses"`
Valid time.Duration `yaml:"valid"`
Timeout time.Duration `yaml:"timeout"`
CacheSize int `yaml:"cache_size"`
Enabled bool `yaml:"enabled"`
IPv4 bool `yaml:"ipv4"`
IPv6 bool `yaml:"ipv6"`
}
// TTL 返回缓存有效期Valid 的别名,便于代码理解)。
func (c *ResolverConfig) TTL() time.Duration {
return c.Valid
}
// Validate 验证 Resolver 配置。
//
// 检查 DNS 服务器地址格式、TTL 和超时设置的有效性。
//
// 返回值:
// - error: 验证失败时的错误信息
func (c *ResolverConfig) Validate() error {
if !c.Enabled {
return nil
}
if len(c.Addresses) == 0 {
return errors.New("resolver.addresses is required when enabled")
}
for _, addr := range c.Addresses {
if _, err := net.ResolveUDPAddr("udp", addr); err != nil {
return fmt.Errorf("invalid DNS address %s: %w", addr, err)
}
}
if c.Valid > 0 && c.Valid < time.Second {
return errors.New("resolver.valid must be at least 1s")
}
if c.Timeout > 0 && c.Timeout < time.Second {
return errors.New("resolver.timeout must be at least 1s")
}
if !c.IPv4 && !c.IPv6 {
return errors.New("at least one of ipv4 or ipv6 must be enabled")
}
return nil
}