diff --git a/docs/llms.txt b/docs/llms.txt new file mode 100644 index 0000000..39c426c --- /dev/null +++ b/docs/llms.txt @@ -0,0 +1,1012 @@ +# Lolly - AI Agent 使用指南 + +> 本文档专为 AI Agent 设计,提供 Lolly HTTP 服务器的完整使用参考。 + +## 项目概述 + +Lolly 是一个高性能 HTTP 服务器与反向代理,使用 Go 语言编写,基于 fasthttp 构建。提供类似 nginx 的功能,但使用 YAML 配置格式,单二进制部署。 + +**核心特性**: +- 静态文件服务(零拷贝传输、sendfile) +- 反向代理(7 种负载均衡算法、健康检查、故障转移) +- HTTP/2 和 HTTP/3 (QUIC) 支持 +- WebSocket 代理 +- Lua 脚本扩展(nginx-lua 兼容 API) +- SSL/TLS(OCSP Stapling、Session Tickets) +- 安全特性(访问控制、速率限制、GeoIP 过滤) +- 热升级和配置热重载 + +## 快速开始 + +### 构建与运行 + +```bash +# 构建 +make build # 生产构建(静态链接) +make build-pgo # PGO 优化构建 + +# 运行 +./bin/lolly # 使用默认配置 lolly.yaml +./bin/lolly -c /path/to/config.yaml # 指定配置文件 +./bin/lolly -g -o config.yaml # 生成默认配置 +./bin/lolly -i nginx.conf -o lolly.yaml # 导入 nginx 配置 +./bin/lolly -v # 显示版本 +``` + +### 最小配置示例 + +```yaml +servers: + - listen: ":8080" + static: + - path: "/" + root: "/var/www/html" +``` + +## 配置结构 + +### 根配置 (Config) + +```yaml +mode: auto # 运行模式: single/vhost/multi_server/auto +variables: {} # 自定义变量 +logging: {} # 日志配置 +servers: [] # 服务器列表(必填) +stream: [] # TCP/UDP Stream 代理 +monitoring: {} # 监控配置 +http3: {} # HTTP/3 配置 +resolver: {} # DNS 解析配置 +performance: {} # 性能配置 +shutdown: {} # 关闭配置 +include: [] # 配置引入 +cache_path: {} # 缓存路径配置 +``` + +### 运行模式 + +| 模式 | 说明 | 自动推断条件 | +|------|------|--------------| +| `single` | 单服务器 | servers 数量 = 1 | +| `vhost` | 虚拟主机 | servers 数量 > 1 且所有 listen 相同 | +| `multi_server` | 多服务器 | servers 数量 > 1 且 listen 不同 | +| `auto` | 自动推断 | 默认值 | + +### 服务器配置 (ServerConfig) + +```yaml +servers: + - listen: ":8080" # 监听地址(必填) + name: "api.example.com" # 服务器名称(虚拟主机匹配) + server_names: [] # 多域名支持(支持通配符) + default: false # 虚拟主机默认服务器 + + # 超时配置 + read_timeout: 60s + write_timeout: 60s + idle_timeout: 120s + + # 连接限制 + max_conns_per_ip: 0 # 单 IP 最大连接数(0=不限制) + max_requests_per_conn: 0 # 单连接最大请求数 + concurrency: 262144 # 最大并发连接数 + client_max_body_size: "100MB" + + # 缓冲区 + read_buffer_size: 16384 # 16KB + write_buffer_size: 16384 + + # 功能模块 + static: [] # 静态文件服务 + proxy: [] # 反向代理 + rewrite: [] # URL 重写 + ssl: {} # SSL/TLS 配置 + security: {} # 安全配置 + compression: {} # 压缩配置 + lua: {} # Lua 脚本配置 +``` + +## 静态文件服务 + +### 基本配置 + +```yaml +static: + - path: "/" # 路径前缀 + root: "/var/www/html" # 根目录 + index: ["index.html", "index.htm"] + + - path: "/assets/" + alias: "/var/www/files/" # 别名(与 root 互斥) +``` + +### 高级配置 + +```yaml +static: + - path: "/" + root: "/var/www/html" + + # try_files 回退 + try_files: ["$uri", "$uri.html", "/index.html"] + try_files_pass: false # 回退是否触发中间件 + + # 缓存 + expires: "30d" # max/epoch/off 或时间 + + # 目录列表 + auto_index: false # 启用目录列表 + auto_index_format: "html" # html/json/xml + auto_index_exact_size: false + auto_index_localtime: false + + # 安全 + symlink_check: false # 符号链接检查 + + # Location 匹配类型 + location_type: "prefix" # exact/prefix/regex/regex_caseless/prefix_priority/named + internal: false # 仅允许内部访问 +``` + +### try_files 变量 + +| 变量 | 说明 | +|------|------| +| `$uri` | 请求路径 | +| `$uri/` | 请求路径加斜杠 | +| `$uri.` | 请求路径加扩展名(如 `$uri.html`) | + +## 反向代理 + +### 基本配置 + +```yaml +proxy: + - path: "/api/" + targets: + - url: "http://backend1:8080" + weight: 3 + - url: "http://backend2:8080" + weight: 1 + load_balance: "weighted_round_robin" +``` + +### 负载均衡算法 + +| 算法 | 说明 | 配置 | +|------|------|------| +| `round_robin` | 轮询 | 默认 | +| `weighted_round_robin` | 加权轮询 | 使用 weight 字段 | +| `least_conn` | 最少连接 | 选择活跃连接最少的目标 | +| `ip_hash` | IP 哈希 | 同一客户端路由到同一目标 | +| `consistent_hash` | 一致性哈希 | 配置 hash_key 和 virtual_nodes | +| `random` | 随机选择 | Power of Two Choices | + +### 目标配置 (ProxyTarget) + +```yaml +targets: + - url: "http://backend:8080" + weight: 3 # 权重 + max_conns: 1000 # 最大并发连接 + max_fails: 3 # 最大失败次数 + fail_timeout: 30s # 失败超时 + backup: false # 备份服务器 + down: false # 标记为不可用 + proxy_uri: "/api" # 替换请求路径 +``` + +### 健康检查 + +```yaml +health_check: + path: "/health" + interval: 10s + timeout: 5s + slow_start: 30s # 慢启动时间 + match: # 匹配条件 + status: ["200-299"] + body: "ok" + headers: + X-Health: "ok" +``` + +### 故障转移 + +```yaml +next_upstream: + tries: 3 # 重试次数 + http_codes: [502, 503, 504] # 触发重试的状态码 +``` + +### 代理头部 + +```yaml +headers: + set_request: # 设置请求头 + X-Real-IP: "$remote_addr" + X-Forwarded-For: "$proxy_add_x_forwarded_for" + X-Forwarded-Proto: "$scheme" + Host: "$host" + set_response: # 设置响应头 + X-Proxy-By: "lolly" + remove: # 移除请求头 + - "X-Internal" + hide_response: # 隐藏响应头 + - "X-Frame-Options" + set_forwarded_host: true # 设置 X-Forwarded-Host + set_forwarded_proto: true # 设置 X-Forwarded-Proto +``` + +### 代理缓存 + +```yaml +cache: + enabled: true + zone: "api_cache" + key: "$request_uri" # 缓存键 + duration: 10m # 缓存时间 + + # 缓存锁(防止缓存击穿) + cache_lock: true + cache_lock_timeout: 5s + + # 过期复用 + stale_while_revalidate: 30s + stale_if_error: 300s + stale_if_timeout: 60s + +cache_valid: + 200: 10m # 状态码缓存时间 + 301: 1h + 404: 1m + any: 5s # 其他状态码 +``` + +### 上游 SSL + +```yaml +proxy_ssl: + enabled: true + server_name: "api.internal" # SNI + trusted_ca: "/etc/ssl/ca.crt" + client_cert: "/etc/ssl/client.crt" + client_key: "/etc/ssl/client.key" + min_version: "TLSv1.2" + insecure_skip_verify: false +``` + +### Location/Refresh 头改写 + +```yaml +redirect_rewrite: + mode: "default" # default/off/custom + rules: # custom 模式规则 + - pattern: "http://backend:8000/" + replacement: "$scheme://$host:$server_port/" +``` + +### 代理超时 + +```yaml +timeout: + dial: 5s # TCP 连接超时 + connect: 30s # 总连接超时(含 DNS/TLS) + read: 30s # 读取超时 + write: 30s # 写入超时 +``` + +### 缓冲配置 + +```yaml +buffering: + mode: "default" # default/on/off + buffer_size: 16384 # 单缓冲区大小 + buffers: "8 16k" # 8 个 16KB 缓冲区 +``` + +## SSL/TLS + +### 服务端 SSL + +```yaml +ssl: + enabled: true + cert: "/etc/ssl/server.crt" + key: "/etc/ssl/server.key" + + # 双向 TLS + client_ca: "/etc/ssl/ca.crt" + client_verify: "require" # none/optional/require + + # 协议和加密套件 + protocols: ["TLSv1.2", "TLSv1.3"] + ciphers: ["ECDHE-RSA-AES256-GCM-SHA384"] + + # OCSP Stapling + ocsp_stapling: true + + # Session Tickets + session_tickets: true + session_tickets_keys: + - "/etc/ssl/ticket.key" +``` + +## 安全配置 + +### 访问控制 + +```yaml +security: + access: + allow: # 白名单 + - "192.168.0.0/16" + - "10.0.0.0/8" + deny: # 黑名单 + - "192.168.100.0/24" + default: "allow" # 默认策略 + trusted_proxies: # 信任的代理 IP + - "10.0.0.1" +``` + +### 速率限制 + +```yaml +security: + rate_limit: + request_rate: 100 # 每秒请求数 + burst: 10 # 突发容量 + mode: "exact" # exact/approximate + + # 滑动窗口 + sliding_window: + enabled: true + window: 1s + limit: 100 +``` + +### 连接限制 + +```yaml +security: + rate_limit: + conn_limit: 100 # 单 IP 并发连接数 +``` + +### 认证 + +```yaml +security: + auth: + type: "basic" + realm: "Restricted" + htpasswd: "/etc/lolly/.htpasswd" + algorithm: "argon2id" # bcrypt/argon2id + + # 子请求认证 + auth_request: + enabled: true + uri: "/internal/auth" + timeout: 5s +``` + +### 安全头部 + +```yaml +security: + headers: + x_frame_options: "DENY" + x_content_type_options: "nosniff" + x_xss_protection: "1; mode=block" + referrer_policy: "strict-origin-when-cross-origin" + content_security_policy: "default-src 'self'" + permissions_policy: "geolocation=()" + strict_transport_security: "max-age=31536000; includeSubDomains" +``` + +### GeoIP 过滤 + +```yaml +security: + geoip: + enabled: true + database: "/etc/geoip/GeoLite2-Country.mmdb" + allow: + - "CN" + - "US" + deny: + - "XX" + default: "allow" +``` + +### 错误页面 + +```yaml +security: + error_page: + pages: + 404: "/errors/404.html" + 500: "/errors/500.html" + 502: "/errors/502.html" + default: "/errors/default.html" + response_code: 200 # 返回状态码 +``` + +## 压缩配置 + +```yaml +compression: + enabled: true + min_length: 1024 # 最小压缩长度 + level: 6 # 压缩级别(1-9) + types: # 压缩的 MIME 类型 + - "text/html" + - "text/css" + - "application/json" + + # Gzip 静态 + gzip_static: true # 使用预压缩的 .gz 文件 + + # Brotli + brotli: + enabled: true + level: 4 +``` + +## Lua 脚本 + +### 配置 + +```yaml +lua: + enabled: true + package_path: "/etc/lolly/lua/?.lua" + package_cpath: "" + sandbox: true # 沙箱模式 + + # 执行阶段脚本 + rewrite_by_lua: "/etc/lolly/rewrite.lua" + access_by_lua: "/etc/lolly/access.lua" + content_by_lua: "/etc/lolly/content.lua" + header_filter_by_lua: "/etc/lolly/header_filter.lua" + body_filter_by_lua: "/etc/lolly/body_filter.lua" + log_by_lua: "/etc/lolly/log.lua" + + # 共享字典 + shared_dicts: + cache: 10000 # 名称: 最大条目数 + limit: 1000 +``` + +### 执行阶段 + +``` +请求 → rewrite → access → content → header_filter → body_filter → log → 响应 +``` + +### 常用 API + +```lua +-- 日志 +ngx.log(ngx.ERR, "error message") +ngx.log(ngx.WARN, "warning") +ngx.log(ngx.INFO, "info") + +-- 变量 +local uri = ngx.var.uri +local method = ngx.var.request_method +local remote_addr = ngx.var.remote_addr +local host = ngx.var.host +local scheme = ngx.var.scheme +local request_uri = ngx.var.request_uri + +-- 请求操作 +ngx.req.get_method() +ngx.req.get_uri() +ngx.req.set_uri("/new_path") +ngx.req.set_uri_args("a=1&b=2") +ngx.req.get_uri_args() +ngx.req.get_headers() +ngx.req.set_header("X-Custom", "value") +ngx.req.clear_header("X-Custom") +ngx.req.get_body_data() +ngx.req.read_body() + +-- 响应操作 +ngx.resp.get_status() +ngx.resp.set_status(200) +ngx.resp.get_headers() +ngx.resp.set_header("X-Response", "value") + +-- 快捷响应 +ngx.say("Hello World") +ngx.print("Hello") +ngx.flush() +ngx.redirect("/new", 302) +ngx.exit(200) + +-- 上下文 +ngx.ctx.user_id = 123 +local id = ngx.ctx.user_id + +-- 共享字典 +local dict = ngx.shared.DICT +dict:set("key", "value", 3600) +local val = dict:get("key") +dict:incr("counter", 1) +dict:delete("key") + +-- 子请求 +local res = ngx.location.capture("/internal/auth", { + method = ngx.HTTP_GET, + body = "data", + args = "a=1" +}) +-- res.status, res.body, res.headers + +-- 动态负载均衡 +ngx.balancer.set_current_peer("backend:8080") +ngx.balancer.set_more_tries(3) +``` + +### 状态码常量 + +```lua +ngx.HTTP_OK = 200 +ngx.HTTP_CREATED = 201 +ngx.HTTP_MOVED_PERMANENTLY = 301 +ngx.HTTP_FOUND = 302 +ngx.HTTP_BAD_REQUEST = 400 +ngx.HTTP_UNAUTHORIZED = 401 +ngx.HTTP_FORBIDDEN = 403 +ngx.HTTP_NOT_FOUND = 404 +ngx.HTTP_INTERNAL_SERVER_ERROR = 500 +ngx.HTTP_BAD_GATEWAY = 502 +ngx.HTTP_SERVICE_UNAVAILABLE = 503 +ngx.HTTP_GATEWAY_TIMEOUT = 504 +``` + +## URL 重写 + +```yaml +rewrite: + - pattern: "^/old/(.*)$" + replacement: "/new/$1" + flag: "last" # last/break/redirect/permanent + + - pattern: "^/api/v1/" + replacement: "/v1/" + flag: "break" +``` + +## TCP/UDP Stream 代理 + +```yaml +stream: + - listen: ":3306" + protocol: "tcp" + upstream: + load_balance: "round_robin" + targets: + - addr: "mysql1:3306" + weight: 3 + - addr: "mysql2:3306" + weight: 1 + ssl: # Stream SSL 终端 + enabled: true + cert: "/etc/ssl/server.crt" + key: "/etc/ssl/server.key" + proxy_ssl: # 上游 SSL + enabled: true + verify: true + trusted_ca: "/etc/ssl/ca.crt" +``` + +## HTTP/3 配置 + +```yaml +http3: + enabled: true + listen: ":443" # UDP 监听地址 +``` + +## 日志配置 + +```yaml +logging: + format: "json" # json/text + + access: + path: "/var/log/lolly/access.log" + format: '$remote_addr - $remote_user [$time] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"' + + error: + path: "/var/log/lolly/error.log" + level: "info" # debug/info/warn/error +``` + +### 日志变量 + +| 变量 | 说明 | +|------|------| +| `$remote_addr` | 客户端 IP | +| `$remote_user` | 认证用户名 | +| `$time` | 时间 | +| `$request` | 请求行 | +| `$status` | 响应状态码 | +| `$body_bytes_sent` | 响应体大小 | +| `$http_referer` | Referer 头 | +| `$http_user_agent` | User-Agent 头 | +| `$request_time` | 请求处理时间 | +| `$upstream_response_time` | 上游响应时间 | + +## 性能配置 + +```yaml +performance: + # Goroutine 池 + goroutine_pool: + enabled: true + max_workers: 10000 + min_workers: 100 + idle_timeout: 60s + + # 文件缓存 + file_cache: + max_entries: 50000 + max_size: 268435456 # 256MB + inactive: 20s + + # 连接池 + transport: + idle_conn_timeout: 90s + max_conns_per_host: 500 + max_idle_conns: 100 + max_idle_conns_per_host: 20 +``` + +### 容量规划 + +| 流量级别 | max_workers | file_cache.max_size | max_conns_per_host | +|----------|-------------|---------------------|-------------------| +| <10K RPS | 500 | 64MB | 100 | +| 10K-100K RPS | 5000 | 256MB | 300 | +| >100K RPS | 10000 | 512MB | 500 | + +## 监控配置 + +```yaml +monitoring: + # 状态端点 + status: + enabled: true + path: "/_status" + format: "json" + allow: + - "127.0.0.1" + - "localhost" + + # pprof 端点 + pprof: + enabled: true + path: "/debug/pprof" + allow: + - "127.0.0.1" +``` + +### 状态端点响应 + +```json +{ + "version": "0.2.2", + "uptime": "2h30m15s", + "connections": 150, + "requests": 125000, + "bytes_sent": 5368709120, + "bytes_received": 1073741824, + "pool": { + "workers": 256, + "idle_workers": 200, + "max_workers": 10000 + }, + "upstreams": [...], + "cache": {...} +} +``` + +## DNS 解析配置 + +```yaml +resolver: + servers: + - "8.8.8.8:53" + - "8.8.4.4:53" + timeout: 5s + cache_ttl: 30s +``` + +## 关闭配置 + +```yaml +shutdown: + graceful_timeout: 30s # 优雅关闭超时 + fast_timeout: 5s # 快速关闭超时 +``` + +## 信号处理 + +| 信号 | 行为 | +|------|------| +| SIGTERM, SIGINT | 快速停止 | +| SIGQUIT | 优雅停止 | +| SIGHUP | 重载配置 | +| SIGUSR1 | 重新打开日志 | +| SIGUSR2 | 热升级 | + +## 配置引入 + +```yaml +include: + - path: "/etc/lolly/conf.d/*.yaml" + required: false # 文件不存在是否报错 +``` + +## 内置变量 + +### 请求变量 + +| 变量 | 说明 | +|------|------| +| `$uri` | 请求 URI(不含查询参数) | +| `$request_uri` | 完整请求 URI | +| `$args` | 查询参数 | +| `$query_string` | 查询参数(同 $args) | +| `$request_method` | 请求方法 | +| `$request_body` | 请求体 | +| `$host` | Host 头 | +| `$hostname` | 服务器主机名 | +| `$scheme` | 协议(http/https) | +| `$server_port` | 服务器端口 | +| `$server_addr` | 服务器地址 | +| `$remote_addr` | 客户端 IP | +| `$remote_port` | 客户端端口 | +| `$request_length` | 请求长度 | +| `$request_time` | 请求处理时间 | + +### 头部变量 + +| 变量 | 说明 | +|------|------| +| `$http_` | 请求头(如 `$http_user_agent`) | +| `$sent_http_` | 响应头 | + +### Cookie 变量 + +| 变量 | 说明 | +|------|------| +| `$cookie_` | Cookie 值 | + +### 查询参数变量 + +| 变量 | 说明 | +|------|------| +| `$arg_` | 查询参数值 | + +### SSL 变量 + +| 变量 | 说明 | +|------|------| +| `$ssl_protocol` | SSL 协议 | +| `$ssl_cipher` | 加密套件 | +| `$ssl_client_s_dn` | 客户端证书 DN | +| `$ssl_client_verify` | 客户端证书验证结果 | + +### 代理变量 + +| 变量 | 说明 | +|------|------| +| `$proxy_add_x_forwarded_for` | 追加 X-Forwarded-For | +| `$upstream_addr` | 上游地址 | +| `$upstream_response_time` | 上游响应时间 | + +## nginx 配置导入 + +支持的指令: + +**server 块**: +- listen, server_name, ssl_certificate, ssl_certificate_key + +**location 块**: +- proxy_pass, root, alias, index, try_files + +**upstream 块**: +- server(weight, max_fails, fail_timeout, backup, down) +- least_conn, ip_hash, hash, random + +**其他**: +- gzip, gzip_types, gzip_min_length +- client_max_body_size +- access_log, error_log +- rewrite, return(301/302) +- error_page, auth_basic + +## 测试 + +```bash +make test # 单元测试 +make test-integration # 集成测试 +make test-e2e # E2E 测试(需要 Docker) +make test-cover # 测试覆盖率 +make bench # 基准测试 +``` + +## Docker + +```bash +# 构建镜像 +make docker + +# 运行容器 +docker run -d \ + --name lolly \ + -p 80:80 -p 443:443 -p 443:443/udp \ + -v /etc/lolly:/etc/lolly:ro \ + -v /var/www:/var/www:ro \ + lolly:latest +``` + +## 常见配置模式 + +### 静态网站 + +```yaml +servers: + - listen: ":80" + static: + - path: "/" + root: "/var/www/html" + try_files: ["$uri", "$uri.html", "/index.html"] + compression: + enabled: true +``` + +### API 网关 + +```yaml +servers: + - listen: ":80" + proxy: + - path: "/api/" + targets: + - url: "http://api1:8080" + - url: "http://api2:8080" + load_balance: "least_conn" + health_check: + path: "/health" + interval: 10s +``` + +### 虚拟主机 + +```yaml +servers: + - listen: ":80" + name: "api.example.com" + proxy: + - path: "/" + targets: + - url: "http://api:8080" + + - listen: ":80" + name: "static.example.com" + static: + - path: "/" + root: "/var/www/static" +``` + +### SSL 终端 + +```yaml +servers: + - listen: ":443" + ssl: + enabled: true + cert: "/etc/ssl/server.crt" + key: "/etc/ssl/server.key" + protocols: ["TLSv1.2", "TLSv1.3"] + proxy: + - path: "/" + targets: + - url: "http://backend:8080" +``` + +### 完整生产配置 + +```yaml +servers: + - listen: ":443" + name: "example.com" + + ssl: + enabled: true + cert: "/etc/ssl/server.crt" + key: "/etc/ssl/server.key" + protocols: ["TLSv1.2", "TLSv1.3"] + ocsp_stapling: true + + security: + access: + default: "allow" + rate_limit: + request_rate: 100 + burst: 20 + headers: + x_frame_options: "DENY" + x_content_type_options: "nosniff" + + compression: + enabled: true + min_length: 1024 + + proxy: + - path: "/api/" + targets: + - url: "http://backend1:8080" + weight: 3 + - url: "http://backend2:8080" + weight: 1 + load_balance: "weighted_round_robin" + health_check: + path: "/health" + interval: 10s + next_upstream: + tries: 3 + http_codes: [502, 503, 504] + +performance: + goroutine_pool: + enabled: true + max_workers: 10000 + file_cache: + max_entries: 50000 + max_size: 268435456 + +monitoring: + status: + enabled: true + path: "/_status" + pprof: + enabled: true +``` + +## 项目结构 + +``` +internal/ +├── app/ # 应用入口、信号处理 +├── config/ # 配置加载、验证 +├── server/ # HTTP 服务器核心 +├── handler/ # 请求处理器(静态文件) +├── proxy/ # 反向代理 +├── loadbalance/ # 负载均衡算法 +├── matcher/ # Location 匹配器 +├── middleware/ # 中间件链 +├── lua/ # Lua 脚本引擎 +├── ssl/ # TLS 配置 +├── cache/ # 缓存系统 +├── resolver/ # DNS 解析 +├── variable/ # 变量系统 +└── ... +``` + +## 依赖 + +| 库 | 用途 | +|---|---| +| fasthttp | HTTP 服务器核心 | +| fasthttp/router | HTTP 路由器 | +| quic-go | QUIC/HTTP/3 | +| zerolog | 日志 | +| gopher-lua | Lua 脚本引擎 | +| klauspost/compress | Gzip/Brotli 压缩 | +| geoip2-golang | GeoIP 查询 | +| yaml.v3 | YAML 配置解析 |