# 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.<ext>` | 请求路径加扩展名（如 `$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_<name>` | 请求头（如 `$http_user_agent`） |
| `$sent_http_<name>` | 响应头 |

### Cookie 变量

| 变量 | 说明 |
|------|------|
| `$cookie_<name>` | Cookie 值 |

### 查询参数变量

| 变量 | 说明 |
|------|------|
| `$arg_<name>` | 查询参数值 |

### 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 配置解析 |
