From 168d34d58d4e955bf3ca37dcacfe7cd47f18b771 Mon Sep 17 00:00:00 2001 From: xfy Date: Wed, 15 Apr 2026 10:34:04 +0800 Subject: [PATCH] =?UTF-8?q?refactor(config,app):=20=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E8=BF=81=E7=A7=BB=E5=88=B0=20servers=20?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DefaultConfig() 使用 Servers[0] 替代 Server - GenerateConfigYAML() 生成 servers 列表格式 - App.Run() 支持多服务器监听地址日志输出 Co-Authored-By: Claude Opus 4.6 --- internal/app/app.go | 15 +- internal/config/defaults.go | 365 ++++++++++++++++++------------------ 2 files changed, 197 insertions(+), 183 deletions(-) diff --git a/internal/app/app.go b/internal/app/app.go index 10657fc..e5117b4 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -166,7 +166,20 @@ func (a *App) Run() int { } a.logger.LogStartup("配置加载成功", map[string]string{"config_path": a.cfgPath}) - a.logger.LogStartup("监听地址", map[string]string{"listen": a.cfg.Server.Listen}) + + // 记录监听地址(支持多服务器模式) + mode := a.cfg.GetMode() + if mode == config.ServerModeMultiServer { + for i, srv := range a.cfg.Servers { + a.logger.LogStartup("监听地址", map[string]string{ + "index": fmt.Sprintf("[%d]", i), + "listen": srv.Listen, + "name": srv.Name, + }) + } + } else { + a.logger.LogStartup("监听地址", map[string]string{"listen": a.cfg.Server.Listen}) + } // 创建 DNS 解析器(如果启用) if a.cfg.Resolver.Enabled { diff --git a/internal/config/defaults.go b/internal/config/defaults.go index 414fbda..9ee7e6b 100644 --- a/internal/config/defaults.go +++ b/internal/config/defaults.go @@ -37,7 +37,7 @@ import ( // - 压缩: gzip,级别 6,最小 1024 字节 func DefaultConfig() *Config { return &Config{ - Server: ServerConfig{ + Servers: []ServerConfig{{ Listen: ":8080", Name: "localhost", ReadTimeout: 30 * time.Second, @@ -142,7 +142,7 @@ func DefaultConfig() *Config { "application/javascript", }, }, - }, + }}, Logging: LoggingConfig{ Format: "text", Access: AccessLogConfig{ @@ -234,221 +234,222 @@ func GenerateConfigYAML(cfg *Config) ([]byte, error) { // buf.WriteString("# 文档: https://github.com/xfy/lolly\n") buf.WriteString("\n") - // server 配置 - buf.WriteString("# 服务器配置(单服务器模式)\n") - buf.WriteString("server:\n") - fmt.Fprintf(&buf, " listen: \"%s\" # 监听地址\n", cfg.Server.Listen) - fmt.Fprintf(&buf, " name: \"%s\" # 服务器名称(虚拟主机匹配)\n", cfg.Server.Name) - fmt.Fprintf(&buf, " read_timeout: %ds # 读取超时(0 表示不限制)\n", int(cfg.Server.ReadTimeout.Seconds())) - fmt.Fprintf(&buf, " write_timeout: %ds # 写入超时(0 表示不限制)\n", int(cfg.Server.WriteTimeout.Seconds())) - fmt.Fprintf(&buf, " idle_timeout: %ds # 空闲超时(0 表示不限制)\n", int(cfg.Server.IdleTimeout.Seconds())) - fmt.Fprintf(&buf, " max_conns_per_ip: %d # 每 IP 最大连接数(0 表示不限制)\n", cfg.Server.MaxConnsPerIP) - fmt.Fprintf(&buf, " max_requests_per_conn: %d # 每连接最大请求数(0 表示不限制)\n", cfg.Server.MaxRequestsPerConn) - fmt.Fprintf(&buf, " client_max_body_size: \"1MB\" # 请求体大小限制(支持单位: b, kb, mb, gb)\n") + // servers 配置 + buf.WriteString("# 服务器配置(多服务器模式)\n") + buf.WriteString("servers:\n") + buf.WriteString(" - # 服务器配置\n") + fmt.Fprintf(&buf, " listen: \"%s\" # 监听地址\n", cfg.Servers[0].Listen) + fmt.Fprintf(&buf, " name: \"%s\" # 服务器名称(虚拟主机匹配)\n", cfg.Servers[0].Name) + fmt.Fprintf(&buf, " read_timeout: %ds # 读取超时(0 表示不限制)\n", int(cfg.Servers[0].ReadTimeout.Seconds())) + fmt.Fprintf(&buf, " write_timeout: %ds # 写入超时(0 表示不限制)\n", int(cfg.Servers[0].WriteTimeout.Seconds())) + fmt.Fprintf(&buf, " idle_timeout: %ds # 空闲超时(0 表示不限制)\n", int(cfg.Servers[0].IdleTimeout.Seconds())) + fmt.Fprintf(&buf, " max_conns_per_ip: %d # 每 IP 最大连接数(0 表示不限制)\n", cfg.Servers[0].MaxConnsPerIP) + fmt.Fprintf(&buf, " max_requests_per_conn: %d # 每连接最大请求数(0 表示不限制)\n", cfg.Servers[0].MaxRequestsPerConn) + fmt.Fprintf(&buf, " client_max_body_size: \"1MB\" # 请求体大小限制(支持单位: b, kb, mb, gb)\n") buf.WriteString("\n") // cache_api 配置 - buf.WriteString(" # 缓存清理 API 配置(用于主动清理代理缓存)\n") - buf.WriteString(" # cache_api:\n") - fmt.Fprintf(&buf, " # enabled: %v # 是否启用缓存清理 API\n", cfg.Server.CacheAPI.Enabled) - fmt.Fprintf(&buf, " # path: \"%s\" # API 端点路径\n", cfg.Server.CacheAPI.Path) - buf.WriteString(" # allow: # 允许访问的 IP\n") - for _, ip := range cfg.Server.CacheAPI.Allow { - fmt.Fprintf(&buf, " # - \"%s\"\n", ip) + buf.WriteString(" # 缓存清理 API 配置(用于主动清理代理缓存)\n") + buf.WriteString(" # cache_api:\n") + fmt.Fprintf(&buf, " # enabled: %v # 是否启用缓存清理 API\n", cfg.Servers[0].CacheAPI.Enabled) + fmt.Fprintf(&buf, " # path: \"%s\" # API 端点路径\n", cfg.Servers[0].CacheAPI.Path) + buf.WriteString(" # allow: # 允许访问的 IP\n") + for _, ip := range cfg.Servers[0].CacheAPI.Allow { + fmt.Fprintf(&buf, " # - \"%s\"\n", ip) } - buf.WriteString(" # auth: # 认证配置\n") - fmt.Fprintf(&buf, " # type: \"%s\" # 认证类型(有效值: none, token)\n", cfg.Server.CacheAPI.Auth.Type) - buf.WriteString(" # token: \"\" # 认证令牌(支持环境变量 ${CACHE_API_TOKEN})\n") + buf.WriteString(" # auth: # 认证配置\n") + fmt.Fprintf(&buf, " # type: \"%s\" # 认证类型(有效值: none, token)\n", cfg.Servers[0].CacheAPI.Auth.Type) + buf.WriteString(" # token: \"\" # 认证令牌(支持环境变量 ${CACHE_API_TOKEN})\n") buf.WriteString("\n") // lua 配置 - buf.WriteString(" # Lua 中间件配置(在请求处理流程中嵌入 Lua 脚本)\n") - buf.WriteString(" # lua:\n") - fmt.Fprintf(&buf, " # enabled: %v # 是否启用 Lua 中间件\n", cfg.Server.Lua.Enabled) - buf.WriteString(" # scripts: # Lua 脚本列表\n") - buf.WriteString(" # - path: \"/scripts/auth.lua\" # 脚本路径\n") - buf.WriteString(" # phase: \"access\" # 执行阶段(有效值: rewrite, access, content, log, header_filter, body_filter)\n") - buf.WriteString(" # timeout: 10s # 执行超时\n") - buf.WriteString(" # enabled: true # 是否启用此脚本\n") - buf.WriteString(" # global_settings: # 全局设置\n") - buf.WriteString(" # max_concurrent_coroutines: 1000 # 最大并发协程数\n") - buf.WriteString(" # coroutine_timeout: 30s # 协程执行超时\n") - buf.WriteString(" # code_cache_size: 1000 # 字节码缓存条目数\n") - buf.WriteString(" # enable_file_watch: true # 启用文件变更检测\n") - buf.WriteString(" # max_execution_time: 30s # 最大执行时间\n") + buf.WriteString(" # Lua 中间件配置(在请求处理流程中嵌入 Lua 脚本)\n") + buf.WriteString(" # lua:\n") + fmt.Fprintf(&buf, " # enabled: %v # 是否启用 Lua 中间件\n", cfg.Servers[0].Lua.Enabled) + buf.WriteString(" # scripts: # Lua 脚本列表\n") + buf.WriteString(" # - path: \"/scripts/auth.lua\" # 脚本路径\n") + buf.WriteString(" # phase: \"access\" # 执行阶段(有效值: rewrite, access, content, log, header_filter, body_filter)\n") + buf.WriteString(" # timeout: 10s # 执行超时\n") + buf.WriteString(" # enabled: true # 是否启用此脚本\n") + buf.WriteString(" # global_settings: # 全局设置\n") + buf.WriteString(" # max_concurrent_coroutines: 1000 # 最大并发协程数\n") + buf.WriteString(" # coroutine_timeout: 30s # 协程执行超时\n") + buf.WriteString(" # code_cache_size: 1000 # 字节码缓存条目数\n") + buf.WriteString(" # enable_file_watch: true # 启用文件变更检测\n") + buf.WriteString(" # max_execution_time: 30s # 最大执行时间\n") buf.WriteString("\n") // static 配置 - buf.WriteString(" # 静态文件服务配置(支持多个目录)\n") - buf.WriteString(" static:\n") - for _, st := range cfg.Server.Static { - buf.WriteString(" - path: \"/\" # 匹配路径前缀\n") - fmt.Fprintf(&buf, " root: \"%s\" # 静态文件根目录\n", st.Root) - buf.WriteString(" index: # 索引文件\n") + buf.WriteString(" # 静态文件服务配置(支持多个目录)\n") + buf.WriteString(" static:\n") + for _, st := range cfg.Servers[0].Static { + buf.WriteString(" - path: \"/\" # 匹配路径前缀\n") + fmt.Fprintf(&buf, " root: \"%s\" # 静态文件根目录\n", st.Root) + buf.WriteString(" index: # 索引文件\n") for _, idx := range st.Index { - fmt.Fprintf(&buf, " - \"%s\"\n", idx) + fmt.Fprintf(&buf, " - \"%s\"\n", idx) } - buf.WriteString(" try_files: [] # SPA 部署示例: [\"$uri\", \"$uri/\", \"/index.html\"]\n") - buf.WriteString(" try_files_pass: false # 内部重定向是否触发中间件\n") + buf.WriteString(" try_files: [] # SPA 部署示例: [\"$uri\", \"$uri/\", \"/index.html\"]\n") + buf.WriteString(" try_files_pass: false # 内部重定向是否触发中间件\n") } - buf.WriteString(" # 示例:额外的静态目录\n") - buf.WriteString(" # - path: \"/assets/\"\n") - buf.WriteString(" # root: \"/var/www/assets\"\n") - buf.WriteString(" # index: [\"index.html\"]\n") + buf.WriteString(" # 示例:额外的静态目录\n") + buf.WriteString(" # - path: \"/assets/\"\n") + buf.WriteString(" # root: \"/var/www/assets\"\n") + buf.WriteString(" # index: [\"index.html\"]\n") buf.WriteString("\n") // proxy 配置示例 - buf.WriteString(" # 反向代理配置\n") - buf.WriteString(" # proxy:\n") - buf.WriteString(" # - path: /api # 匹配路径前缀\n") - buf.WriteString(" # targets: # 后端目标列表\n") - buf.WriteString(" # - url: http://backend1:8080\n") - buf.WriteString(" # weight: 3 # 权重(加权轮询时有效)\n") - buf.WriteString(" # - url: http://backend2:8080\n") - buf.WriteString(" # weight: 1\n") - buf.WriteString(" # load_balance: round_robin # 负载均衡算法(有效值: round_robin, weighted_round_robin, least_conn, ip_hash, consistent_hash)\n") - buf.WriteString(" # hash_key: ip # 一致性哈希键(仅 load_balance=consistent_hash 时有效,有效值: ip, uri, header:X-Name)\n") - buf.WriteString(" # virtual_nodes: 150 # 一致性哈希虚拟节点数(仅 load_balance=consistent_hash 时有效)\n") - buf.WriteString(" # health_check: # 健康检查\n") - buf.WriteString(" # interval: 10s\n") - buf.WriteString(" # path: /health\n") - buf.WriteString(" # timeout: 5s\n") - buf.WriteString(" # timeout: # 超时配置\n") - buf.WriteString(" # connect: 5s # 连接超时\n") - buf.WriteString(" # read: 30s # 读取超时\n") - buf.WriteString(" # write: 30s # 写入超时\n") - buf.WriteString(" # headers: # 头部修改\n") - buf.WriteString(" # set_request: {X-Custom: value}\n") - buf.WriteString(" # set_response: {X-Server: lolly}\n") - buf.WriteString(" # remove: [X-Powered-By]\n") - buf.WriteString(" # cache: # 代理缓存\n") - buf.WriteString(" # enabled: false\n") - buf.WriteString(" # max_age: 60s\n") - buf.WriteString(" # cache_lock: true # 防止缓存击穿\n") - buf.WriteString(" # stale_while_revalidate: 30s\n") - buf.WriteString(" # client_max_body_size: \"50MB\" # 此代理路径的请求体限制\n") - buf.WriteString(" # next_upstream: # 故障转移配置\n") - buf.WriteString(" # tries: 1 # 最大尝试次数(1 表示禁用故障转移)\n") - buf.WriteString(" # http_codes: [502, 503, 504] # 触发重试的 HTTP 状态码\n") + buf.WriteString(" # 反向代理配置\n") + buf.WriteString(" # proxy:\n") + buf.WriteString(" # - path: /api # 匹配路径前缀\n") + buf.WriteString(" # targets: # 后端目标列表\n") + buf.WriteString(" # - url: http://backend1:8080\n") + buf.WriteString(" # weight: 3 # 权重(加权轮询时有效)\n") + buf.WriteString(" # - url: http://backend2:8080\n") + buf.WriteString(" # weight: 1\n") + buf.WriteString(" # load_balance: round_robin # 负载均衡算法(有效值: round_robin, weighted_round_robin, least_conn, ip_hash, consistent_hash)\n") + buf.WriteString(" # hash_key: ip # 一致性哈希键(仅 load_balance=consistent_hash 时有效,有效值: ip, uri, header:X-Name)\n") + buf.WriteString(" # virtual_nodes: 150 # 一致性哈希虚拟节点数(仅 load_balance=consistent_hash 时有效)\n") + buf.WriteString(" # health_check: # 健康检查\n") + buf.WriteString(" # interval: 10s\n") + buf.WriteString(" # path: /health\n") + buf.WriteString(" # timeout: 5s\n") + buf.WriteString(" # timeout: # 超时配置\n") + buf.WriteString(" # connect: 5s # 连接超时\n") + buf.WriteString(" # read: 30s # 读取超时\n") + buf.WriteString(" # write: 30s # 写入超时\n") + buf.WriteString(" # headers: # 头部修改\n") + buf.WriteString(" # set_request: {X-Custom: value}\n") + buf.WriteString(" # set_response: {X-Server: lolly}\n") + buf.WriteString(" # remove: [X-Powered-By]\n") + buf.WriteString(" # cache: # 代理缓存\n") + buf.WriteString(" # enabled: false\n") + buf.WriteString(" # max_age: 60s\n") + buf.WriteString(" # cache_lock: true # 防止缓存击穿\n") + buf.WriteString(" # stale_while_revalidate: 30s\n") + buf.WriteString(" # client_max_body_size: \"50MB\" # 此代理路径的请求体限制\n") + buf.WriteString(" # next_upstream: # 故障转移配置\n") + buf.WriteString(" # tries: 1 # 最大尝试次数(1 表示禁用故障转移)\n") + buf.WriteString(" # http_codes: [502, 503, 504] # 触发重试的 HTTP 状态码\n") buf.WriteString("\n") // SSL 配置 - buf.WriteString(" # SSL/TLS 配置\n") - buf.WriteString(" # ssl:\n") - buf.WriteString(" # cert: /path/to/cert.pem # 证书文件\n") - buf.WriteString(" # key: /path/to/key.pem # 私钥文件\n") - buf.WriteString(" # cert_chain: /path/to/chain.pem # 证书链文件\n") - buf.WriteString(" # protocols: # TLS 版本(有效值: TLSv1.2, TLSv1.3)\n") - for _, proto := range cfg.Server.SSL.Protocols { - fmt.Fprintf(&buf, " # - \"%s\"\n", proto) + buf.WriteString(" # SSL/TLS 配置\n") + buf.WriteString(" # ssl:\n") + buf.WriteString(" # cert: /path/to/cert.pem # 证书文件\n") + buf.WriteString(" # key: /path/to/key.pem # 私钥文件\n") + buf.WriteString(" # cert_chain: /path/to/chain.pem # 证书链文件\n") + buf.WriteString(" # protocols: # TLS 版本(有效值: TLSv1.2, TLSv1.3)\n") + for _, proto := range cfg.Servers[0].SSL.Protocols { + fmt.Fprintf(&buf, " # - \"%s\"\n", proto) } - buf.WriteString(" # ciphers: # 加密套件(仅 TLS 1.2 有效,TLS 1.3 使用内置套件)\n") - buf.WriteString(" # - ECDHE-ECDSA-AES256-GCM-SHA384\n") - buf.WriteString(" # - ECDHE-RSA-AES256-GCM-SHA384\n") - buf.WriteString(" # - ECDHE-ECDSA-CHACHA20-POLY1305\n") - buf.WriteString(" # - ECDHE-RSA-CHACHA20-POLY1305\n") - buf.WriteString(" # # 拒绝不安全套件:含 RC4、DES、3DES、CBC 的配置将报错\n") - fmt.Fprintf(&buf, " # ocsp_stapling: %v # OCSP Stapling\n", cfg.Server.SSL.OCSPStapling) - buf.WriteString(" # hsts: # HTTP Strict Transport Security\n") - fmt.Fprintf(&buf, " # max_age: %d # 过期时间(秒)\n", cfg.Server.SSL.HSTS.MaxAge) - fmt.Fprintf(&buf, " # include_sub_domains: %v # 包含子域名\n", cfg.Server.SSL.HSTS.IncludeSubDomains) - fmt.Fprintf(&buf, " # preload: %v # 加入 HSTS 预加载列表\n", cfg.Server.SSL.HSTS.Preload) - buf.WriteString(" # session_tickets: # TLS Session Tickets 配置(TLS 1.3 会话恢复)\n") - fmt.Fprintf(&buf, " # enabled: %v # 是否启用 Session Tickets\n", cfg.Server.SSL.SessionTickets.Enabled) - buf.WriteString(" # key_file: \"\" # 密钥存储文件路径(用于持久化密钥)\n") - fmt.Fprintf(&buf, " # rotate_interval: %d # 密钥轮换间隔(秒),建议 1-24 小时\n", int(cfg.Server.SSL.SessionTickets.RotateInterval.Seconds())) - fmt.Fprintf(&buf, " # retain_keys: %d # 保留的历史密钥数量,建议 3-5 个\n", cfg.Server.SSL.SessionTickets.RetainKeys) - buf.WriteString(" # client_verify: # mTLS 客户端证书验证配置\n") - buf.WriteString(" # enabled: false # 是否启用客户端证书验证\n") - buf.WriteString(" # mode: \"none\" # 验证模式(有效值: none, request, require, optional_no_ca)\n") - buf.WriteString(" # client_ca: \"\" # 客户端 CA 证书文件路径\n") - buf.WriteString(" # verify_depth: 1 # 证书链验证深度\n") - buf.WriteString(" # crl: \"\" # 证书撤销列表文件路径(可选)\n") - buf.WriteString(" # http2: # HTTP/2 配置(需 SSL 证书)\n") - fmt.Fprintf(&buf, " # enabled: %v # 是否启用 HTTP/2\n", cfg.Server.SSL.HTTP2.Enabled) - fmt.Fprintf(&buf, " # max_concurrent_streams: %d # 最大并发流数\n", cfg.Server.SSL.HTTP2.MaxConcurrentStreams) - fmt.Fprintf(&buf, " # max_header_list_size: %d # 最大头部列表大小(字节)\n", cfg.Server.SSL.HTTP2.MaxHeaderListSize) - fmt.Fprintf(&buf, " # idle_timeout: %ds # 空闲超时\n", int(cfg.Server.SSL.HTTP2.IdleTimeout.Seconds())) - fmt.Fprintf(&buf, " # push_enabled: %v # 是否启用 Server Push\n", cfg.Server.SSL.HTTP2.PushEnabled) - fmt.Fprintf(&buf, " # h2c_enabled: %v # 是否启用 H2C(明文 HTTP/2)\n", cfg.Server.SSL.HTTP2.H2CEnabled) - fmt.Fprintf(&buf, " # graceful_shutdown_timeout: %ds # HTTP/2 优雅关闭超时\n", int(cfg.Server.SSL.HTTP2.GracefulShutdownTimeout.Seconds())) + buf.WriteString(" # ciphers: # 加密套件(仅 TLS 1.2 有效,TLS 1.3 使用内置套件)\n") + buf.WriteString(" # - ECDHE-ECDSA-AES256-GCM-SHA384\n") + buf.WriteString(" # - ECDHE-RSA-AES256-GCM-SHA384\n") + buf.WriteString(" # - ECDHE-ECDSA-CHACHA20-POLY1305\n") + buf.WriteString(" # - ECDHE-RSA-CHACHA20-POLY1305\n") + buf.WriteString(" # # 拒绝不安全套件:含 RC4、DES、3DES、CBC 的配置将报错\n") + fmt.Fprintf(&buf, " # ocsp_stapling: %v # OCSP Stapling\n", cfg.Servers[0].SSL.OCSPStapling) + buf.WriteString(" # hsts: # HTTP Strict Transport Security\n") + fmt.Fprintf(&buf, " # max_age: %d # 过期时间(秒)\n", cfg.Servers[0].SSL.HSTS.MaxAge) + fmt.Fprintf(&buf, " # include_sub_domains: %v # 包含子域名\n", cfg.Servers[0].SSL.HSTS.IncludeSubDomains) + fmt.Fprintf(&buf, " # preload: %v # 加入 HSTS 预加载列表\n", cfg.Servers[0].SSL.HSTS.Preload) + buf.WriteString(" # session_tickets: # TLS Session Tickets 配置(TLS 1.3 会话恢复)\n") + fmt.Fprintf(&buf, " # enabled: %v # 是否启用 Session Tickets\n", cfg.Servers[0].SSL.SessionTickets.Enabled) + buf.WriteString(" # key_file: \"\" # 密钥存储文件路径(用于持久化密钥)\n") + fmt.Fprintf(&buf, " # rotate_interval: %d # 密钥轮换间隔(秒),建议 1-24 小时\n", int(cfg.Servers[0].SSL.SessionTickets.RotateInterval.Seconds())) + fmt.Fprintf(&buf, " # retain_keys: %d # 保留的历史密钥数量,建议 3-5 个\n", cfg.Servers[0].SSL.SessionTickets.RetainKeys) + buf.WriteString(" # client_verify: # mTLS 客户端证书验证配置\n") + buf.WriteString(" # enabled: false # 是否启用客户端证书验证\n") + buf.WriteString(" # mode: \"none\" # 验证模式(有效值: none, request, require, optional_no_ca)\n") + buf.WriteString(" # client_ca: \"\" # 客户端 CA 证书文件路径\n") + buf.WriteString(" # verify_depth: 1 # 证书链验证深度\n") + buf.WriteString(" # crl: \"\" # 证书撤销列表文件路径(可选)\n") + buf.WriteString(" # http2: # HTTP/2 配置(需 SSL 证书)\n") + fmt.Fprintf(&buf, " # enabled: %v # 是否启用 HTTP/2\n", cfg.Servers[0].SSL.HTTP2.Enabled) + fmt.Fprintf(&buf, " # max_concurrent_streams: %d # 最大并发流数\n", cfg.Servers[0].SSL.HTTP2.MaxConcurrentStreams) + fmt.Fprintf(&buf, " # max_header_list_size: %d # 最大头部列表大小(字节)\n", cfg.Servers[0].SSL.HTTP2.MaxHeaderListSize) + fmt.Fprintf(&buf, " # idle_timeout: %ds # 空闲超时\n", int(cfg.Servers[0].SSL.HTTP2.IdleTimeout.Seconds())) + fmt.Fprintf(&buf, " # push_enabled: %v # 是否启用 Server Push\n", cfg.Servers[0].SSL.HTTP2.PushEnabled) + fmt.Fprintf(&buf, " # h2c_enabled: %v # 是否启用 H2C(明文 HTTP/2)\n", cfg.Servers[0].SSL.HTTP2.H2CEnabled) + fmt.Fprintf(&buf, " # graceful_shutdown_timeout: %ds # HTTP/2 优雅关闭超时\n", int(cfg.Servers[0].SSL.HTTP2.GracefulShutdownTimeout.Seconds())) buf.WriteString("\n") // security 配置 - buf.WriteString(" # 安全配置\n") - buf.WriteString(" security:\n") - buf.WriteString(" # IP 访问控制\n") - buf.WriteString(" access:\n") - buf.WriteString(" allow: [] # 允许的 IP/CIDR 列表\n") - buf.WriteString(" deny: [] # 拒绝的 IP/CIDR 列表\n") - fmt.Fprintf(&buf, " default: \"%s\" # 默认动作(有效值: allow, deny)\n", cfg.Server.Security.Access.Default) - buf.WriteString(" trusted_proxies: [] # 可信代理 CIDR 列表,用于 X-Forwarded-For 解析\n") + buf.WriteString(" # 安全配置\n") + buf.WriteString(" security:\n") + buf.WriteString(" # IP 访问控制\n") + buf.WriteString(" access:\n") + buf.WriteString(" allow: [] # 允许的 IP/CIDR 列表\n") + buf.WriteString(" deny: [] # 拒绝的 IP/CIDR 列表\n") + fmt.Fprintf(&buf, " default: \"%s\" # 默认动作(有效值: allow, deny)\n", cfg.Servers[0].Security.Access.Default) + buf.WriteString(" trusted_proxies: [] # 可信代理 CIDR 列表,用于 X-Forwarded-For 解析\n") buf.WriteString("\n") - buf.WriteString(" # 速率限制\n") - buf.WriteString(" rate_limit:\n") - fmt.Fprintf(&buf, " request_rate: %d # 每秒请求数(0 表示不限制)\n", cfg.Server.Security.RateLimit.RequestRate) - fmt.Fprintf(&buf, " burst: %d # 突发上限\n", cfg.Server.Security.RateLimit.Burst) - fmt.Fprintf(&buf, " conn_limit: %d # 连接数限制\n", cfg.Server.Security.RateLimit.ConnLimit) - fmt.Fprintf(&buf, " key: \"%s\" # 限流 key 来源(有效值: ip, header)\n", cfg.Server.Security.RateLimit.Key) - fmt.Fprintf(&buf, " algorithm: \"%s\" # 限流算法(有效值: token_bucket, sliding_window)\n", cfg.Server.Security.RateLimit.Algorithm) - fmt.Fprintf(&buf, " sliding_window_mode: \"%s\" # 滑动窗口模式(有效值: approximate, precise,仅 algorithm=sliding_window 时有效)\n", cfg.Server.Security.RateLimit.SlidingWindowMode) - fmt.Fprintf(&buf, " sliding_window: %d # 滑动窗口大小(秒,仅 algorithm=sliding_window 时有效)\n", cfg.Server.Security.RateLimit.SlidingWindow) + buf.WriteString(" # 速率限制\n") + buf.WriteString(" rate_limit:\n") + fmt.Fprintf(&buf, " request_rate: %d # 每秒请求数(0 表示不限制)\n", cfg.Servers[0].Security.RateLimit.RequestRate) + fmt.Fprintf(&buf, " burst: %d # 突发上限\n", cfg.Servers[0].Security.RateLimit.Burst) + fmt.Fprintf(&buf, " conn_limit: %d # 连接数限制\n", cfg.Servers[0].Security.RateLimit.ConnLimit) + fmt.Fprintf(&buf, " key: \"%s\" # 限流 key 来源(有效值: ip, header)\n", cfg.Servers[0].Security.RateLimit.Key) + fmt.Fprintf(&buf, " algorithm: \"%s\" # 限流算法(有效值: token_bucket, sliding_window)\n", cfg.Servers[0].Security.RateLimit.Algorithm) + fmt.Fprintf(&buf, " sliding_window_mode: \"%s\" # 滑动窗口模式(有效值: approximate, precise,仅 algorithm=sliding_window 时有效)\n", cfg.Servers[0].Security.RateLimit.SlidingWindowMode) + fmt.Fprintf(&buf, " sliding_window: %d # 滑动窗口大小(秒,仅 algorithm=sliding_window 时有效)\n", cfg.Servers[0].Security.RateLimit.SlidingWindow) buf.WriteString("\n") - buf.WriteString(" # 认证配置(type 为空时禁用)\n") - buf.WriteString(" auth:\n") - buf.WriteString(" type: \"\" # 认证类型(有效值: basic,空表示禁用)\n") - fmt.Fprintf(&buf, " require_tls: %v # 启用时强制 HTTPS\n", cfg.Server.Security.Auth.RequireTLS) - fmt.Fprintf(&buf, " algorithm: \"%s\" # 密码哈希算法(有效值: bcrypt, argon2id)\n", cfg.Server.Security.Auth.Algorithm) - buf.WriteString(" users: [] # 用户列表\n") - fmt.Fprintf(&buf, " realm: \"%s\" # 认证域\n", cfg.Server.Security.Auth.Realm) - fmt.Fprintf(&buf, " min_password_length: %d # 密码最小长度\n", cfg.Server.Security.Auth.MinPasswordLength) + buf.WriteString(" # 认证配置(type 为空时禁用)\n") + buf.WriteString(" auth:\n") + buf.WriteString(" type: \"\" # 认证类型(有效值: basic,空表示禁用)\n") + fmt.Fprintf(&buf, " require_tls: %v # 启用时强制 HTTPS\n", cfg.Servers[0].Security.Auth.RequireTLS) + fmt.Fprintf(&buf, " algorithm: \"%s\" # 密码哈希算法(有效值: bcrypt, argon2id)\n", cfg.Servers[0].Security.Auth.Algorithm) + buf.WriteString(" users: [] # 用户列表\n") + fmt.Fprintf(&buf, " realm: \"%s\" # 认证域\n", cfg.Servers[0].Security.Auth.Realm) + fmt.Fprintf(&buf, " min_password_length: %d # 密码最小长度\n", cfg.Servers[0].Security.Auth.MinPasswordLength) buf.WriteString("\n") - buf.WriteString(" # 安全头部\n") - buf.WriteString(" headers:\n") - fmt.Fprintf(&buf, " x_frame_options: \"%s\" # 防止点击劫持(有效值: DENY, SAMEORIGIN, 空表示禁用)\n", cfg.Server.Security.Headers.XFrameOptions) - fmt.Fprintf(&buf, " x_content_type_options: \"%s\" # 防止 MIME 嗅探(有效值:nosniff,空表示禁用)\n", cfg.Server.Security.Headers.XContentTypeOptions) - fmt.Fprintf(&buf, " referrer_policy: \"%s\" # 引用策略(有效值: no-referrer, no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url)\n", cfg.Server.Security.Headers.ReferrerPolicy) - buf.WriteString(" content_security_policy: \"\" # 内容安全策略 CSP(空表示禁用)\n") - buf.WriteString(" permissions_policy: \"\" # 权限策略(空表示禁用)\n") + buf.WriteString(" # 安全头部\n") + buf.WriteString(" headers:\n") + fmt.Fprintf(&buf, " x_frame_options: \"%s\" # 防止点击劫持(有效值: DENY, SAMEORIGIN, 空表示禁用)\n", cfg.Servers[0].Security.Headers.XFrameOptions) + fmt.Fprintf(&buf, " x_content_type_options: \"%s\" # 防止 MIME 嗅探(有效值:nosniff,空表示禁用)\n", cfg.Servers[0].Security.Headers.XContentTypeOptions) + fmt.Fprintf(&buf, " referrer_policy: \"%s\" # 引用策略(有效值: no-referrer, no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url)\n", cfg.Servers[0].Security.Headers.ReferrerPolicy) + buf.WriteString(" content_security_policy: \"\" # 内容安全策略 CSP(空表示禁用)\n") + buf.WriteString(" permissions_policy: \"\" # 权限策略(空表示禁用)\n") buf.WriteString("\n") - buf.WriteString(" # 自定义错误页面\n") - buf.WriteString(" error_page:\n") - buf.WriteString(" pages: {} # 状态码到页面映射,如 {404: \"/errors/404.html\"}\n") - buf.WriteString(" default: \"\" # 默认错误页面\n") - buf.WriteString(" response_code: 0 # 响应状态码覆盖(0 表示使用原始状态码)\n") + buf.WriteString(" # 自定义错误页面\n") + buf.WriteString(" error_page:\n") + buf.WriteString(" pages: {} # 状态码到页面映射,如 {404: \"/errors/404.html\"}\n") + buf.WriteString(" default: \"\" # 默认错误页面\n") + buf.WriteString(" response_code: 0 # 响应状态码覆盖(0 表示使用原始状态码)\n") buf.WriteString("\n") - buf.WriteString(" # 外部认证子请求配置(将认证委托给外部服务)\n") - buf.WriteString(" auth_request:\n") - buf.WriteString(" enabled: false # 是否启用外部认证\n") - buf.WriteString(" uri: \"\" # 认证服务地址(支持相对路径或完整 URL)\n") - buf.WriteString(" method: \"GET\" # 认证请求方法(有效值: GET, POST, HEAD)\n") - buf.WriteString(" auth_timeout: 5s # 认证请求超时时间\n") - buf.WriteString(" headers: {} # 自定义认证请求头,如 {X-Original-Uri: \"$request_uri\"}\n") - buf.WriteString(" forward_headers: [] # 需要转发的原请求头,默认包含 Cookie, Authorization, X-Forwarded-For\n") + buf.WriteString(" # 外部认证子请求配置(将认证委托给外部服务)\n") + buf.WriteString(" auth_request:\n") + buf.WriteString(" enabled: false # 是否启用外部认证\n") + buf.WriteString(" uri: \"\" # 认证服务地址(支持相对路径或完整 URL)\n") + buf.WriteString(" method: \"GET\" # 认证请求方法(有效值: GET, POST, HEAD)\n") + buf.WriteString(" auth_timeout: 5s # 认证请求超时时间\n") + buf.WriteString(" headers: {} # 自定义认证请求头,如 {X-Original-Uri: \"$request_uri\"}\n") + buf.WriteString(" forward_headers: [] # 需要转发的原请求头,默认包含 Cookie, Authorization, X-Forwarded-For\n") buf.WriteString("\n") // rewrite 配置示例 - buf.WriteString(" # URL 重写规则\n") - buf.WriteString(" # rewrite:\n") - buf.WriteString(" # - pattern: \"^/old/(.*)$\" # 匹配模式(正则表达式)\n") - buf.WriteString(" # replacement: /new/$1 # 替换目标\n") - buf.WriteString(" # flag: last # 标志(有效值: last, redirect, permanent, break)\n") + buf.WriteString(" # URL 重写规则\n") + buf.WriteString(" # rewrite:\n") + buf.WriteString(" # - pattern: \"^/old/(.*)$\" # 匹配模式(正则表达式)\n") + buf.WriteString(" # replacement: /new/$1 # 替换目标\n") + buf.WriteString(" # flag: last # 标志(有效值: last, redirect, permanent, break)\n") buf.WriteString("\n") // compression 配置 - buf.WriteString(" # 响应压缩配置\n") - buf.WriteString(" compression:\n") - fmt.Fprintf(&buf, " type: \"%s\" # 压缩类型(有效值: gzip, brotli, both,空表示禁用)\n", cfg.Server.Compression.Type) - fmt.Fprintf(&buf, " level: %d # 压缩级别(范围 0-9,0=不压缩,1=最快,9=最高压缩率)\n", cfg.Server.Compression.Level) - fmt.Fprintf(&buf, " min_size: %d # 最小压缩大小(字节,小于此值不压缩)\n", cfg.Server.Compression.MinSize) - fmt.Fprintf(&buf, " gzip_static: %v # 启用预压缩文件支持(自动查找 .gz/.br 文件)\n", cfg.Server.Compression.GzipStatic) - buf.WriteString(" gzip_static_extensions: # 预压缩文件扩展名\n") - for _, ext := range cfg.Server.Compression.GzipStaticExtensions { - fmt.Fprintf(&buf, " - \"%s\"\n", ext) + buf.WriteString(" # 响应压缩配置\n") + buf.WriteString(" compression:\n") + fmt.Fprintf(&buf, " type: \"%s\" # 压缩类型(有效值: gzip, brotli, both,空表示禁用)\n", cfg.Servers[0].Compression.Type) + fmt.Fprintf(&buf, " level: %d # 压缩级别(范围 0-9,0=不压缩,1=最快,9=最高压缩率)\n", cfg.Servers[0].Compression.Level) + fmt.Fprintf(&buf, " min_size: %d # 最小压缩大小(字节,小于此值不压缩)\n", cfg.Servers[0].Compression.MinSize) + fmt.Fprintf(&buf, " gzip_static: %v # 启用预压缩文件支持(自动查找 .gz/.br 文件)\n", cfg.Servers[0].Compression.GzipStatic) + buf.WriteString(" gzip_static_extensions: # 预压缩文件扩展名\n") + for _, ext := range cfg.Servers[0].Compression.GzipStaticExtensions { + fmt.Fprintf(&buf, " - \"%s\"\n", ext) } - buf.WriteString(" types: # 可压缩的 MIME 类型\n") - for _, t := range cfg.Server.Compression.Types { - fmt.Fprintf(&buf, " - \"%s\"\n", t) + buf.WriteString(" types: # 可压缩的 MIME 类型\n") + for _, t := range cfg.Servers[0].Compression.Types { + fmt.Fprintf(&buf, " - \"%s\"\n", t) } buf.WriteString("\n")