<div align="center">
<img class="logo" src="https://raw.githubusercontent.com/umputun/reproxy/master/site/logo-bg.svg" width="355px" height="142px" alt="Reproxy | Simple Reverse Proxy"/>
</div>
Reproxy 是一个简单的边缘 HTTP(s) 服务器 / 反向代理,支持多种提供程序(docker、static、file、consul catalog)。一个或多个提供程序提供有关请求的服务器、请求的 URL、目标 URL 和健康检查 URL 的信息。它以单个二进制文件或 docker 容器的形式分发。
- 使用 <a href="https://letsencrypt.org/" rel="nofollow noopener noreferrer" target="_blank">Let's Encrypt</a> 自动进行 SSL 终止
- 支持用户提供的 SSL 证书
- 简单但灵活的代理规则
- 静态、命令行代理规则提供程序
- 动态、基于文件的代理规则提供程序
- 具有自动发现功能的 Docker 提供程序
- 通过服务标签进行发现的 Consul Catalog 提供程序
- 支持多个(虚拟)主机
- 可选的流量压缩
- 可选的基于 IP 的访问控制
- 按路由的基本身份验证
- 用户定义的大小限制和超时
- 单一二进制文件分发
- Docker 容器分发
- 内置静态资源服务器,可选“SPA 友好”模式
- 支持重定向规则
- 可选的限制器,用于整体活动以及用户活动
- 实时健康检查和故障转移/负载均衡
- 带有路由信息和 prometheus 指标的管理服务器
- 通过 RPC 支持插件,以实现自定义功能
- 可选的日志记录,同时支持 Apache 日志格式和简化的 stdout 报告。
---
<div align="center">
[](https://github.com/umputun/reproxy/actions/workflows/ci.yml) [](https://coveralls.io/github/umputun/reproxy?branch=master) [](https://goreportcard.com/report/github.com/umputun/reproxy) [](https://hub.docker.com/r/umputun/reproxy)
</div>
服务器(主机)可以设置为 FQDN,即 `s.example.com`、`*`(捕获所有)或正则表达式。精确匹配优先,因此如果有两条规则分别使用服务器 `example.com` 和 `example\.(com|org)`,对 `example.com/some/url` 的请求将匹配前者。请求的 URL 可以是正则表达式,例如 `^/api/(.*)`,目标 URL 可以包含正则匹配组,即 `http://d.example.com:8080/$1`。对于上面的示例,`http://s.example.com/api/something?foo=bar` 将被代理到 `http://d.example.com:8080/something?foo=bar`。
为方便起见,带有尾部 `/` 且没有正则组的请求会扩展为 `/(.*)`,在这些情况下目标会扩展为 `/$1`。即 `/api/` -> `http://127.0.0.1/service` 将被转换为 `^/api/(.*)` -> `http://127.0.0.1/service/$1`。
目标 URL 中支持主机替换。例如,`/files/${host}` 将被替换为匹配的主机名。也可以使用 `$host`(不带花括号)。
同时支持 HTTP 和 HTTPS。对于 HTTPS,既可以使用静态证书,也可以使用自动 ACME(Let's Encrypt)证书。可选的资源服务器可用于提供静态文件。启动 reproxy 至少需要定义一个提供程序。其余参数严格可选,并具有合理的默认值。
示例:
- 使用静态提供程序:`reproxy --static.enabled --static.rule="*,example.com/api/(.*),https://api.example.com/$1"`
- 使用自动 docker 发现:`reproxy --docker.enabled --docker.auto`
- 作为 docker 容器:`docker up -p 80:8080 umputun/reproxy --docker.enabled --docker.auto`
- 使用自动 SSL:`docker up -p 80:8080 -p 443:8443 umputun/reproxy --docker.enabled --docker.auto --ssl.type=auto --ssl.fqdn=example.com`
## 安装
Reproxy 以一个小型自包含二进制文件以及一个 docker 镜像的形式分发。二进制文件和镜像均支持多种架构和多种操作系统,包括 linux_x86_64、linux_arm64、linux_arm、macos_x86_64、macos_arm64、windows_x86_64 和 windows_arm。我们还提供 arm64 和 x86 的 deb 和 rpm 软件包。
- 对于二进制分发,请在[发布区](https://github.com/umputun/reproxy/releases)下载相应的文件
- 对于 Homebrew 用户:`brew install umputun/apps/reproxy`
- docker 容器可在 [Docker Hub](https://hub.docker.com/r/umputun/reproxy) 以及 [Github Container Registry](https://github.com/users/umputun/packages/container/reproxy/versions) 上获取。例如 `docker pull umputun/reproxy` 或 `docker pull ghcr.io/umputun/reproxy`。
最新稳定版本具有 `:vX.Y.Z` docker 标签(带有 `:latest` 别名),当前 master 具有 `:master` 标签。
## 提供程序
代理规则由各种提供程序提供。目前包括 - `file`、`docker`、`static` 和 `consul-catalog`。每个提供程序可以为代理请求和静态(资源)定义多条路由规则。用户可以同时设置多个提供程序。
_请参阅[示例](https://github.com/umputun/reproxy/tree/master/examples)中各种提供程序的示例_
### 静态提供程序
这是最简单的提供程序,直接在命令行(或环境变量)中定义所有映射规则。支持多条规则。每条规则由 3 到 7 个逗号分隔的元素组成 `server,sourceurl,destination[,ping-url[,forward-health-checks[,timeout[,throttle]]]]`。例如:
- `*,^/api/(.*),https://api.example.com/$1` - 将所有对任意主机/服务器且带有 `/api` 前缀的请求代理到 `https://api.example.com`
- `example.com,/foo/bar,https://api.example.com/zzz,https://api.example.com/ping` - 将所有对 `example.com` 且 url 为 `/foo/bar` 的请求代理到 `https://api.example.com/zzz`,并使用 `https://api.example.com/ping` 进行健康检查。
- `example.com,/foo/bar,https://api.example.com/zzz,https://api.example.com/ping,true` - 与上面相同,但还会将 `/ping` 和 `/health` 请求转发到后端。
- `example.com,^/upload/(.*),https://api.example.com/$1,,,5m` - 每条路由的请求超时为 5 分钟(第 4 和第 5 个字段留空以跳过 ping-url 和 forward-health-checks)。
- `example.com,^/login,https://api.example.com/login,,,,2` - 每条路由的限流为每用户每秒 2 个请求(前面的位置字段留空)。
第 4 个元素定义用于健康报告的可选 ping url。第 5 个元素可选地启用将健康检查请求转发到后端(`true`、`yes`、`1`)。有关更多详细信息,请参阅[健康检查](#ping-and-health-checks)部分。第 6 个元素是可选的每条路由请求超时(Go duration,例如 `5m`、`30s`);`0` 或空则继承全局 `--timeout.write` 设置。第 7 个元素是可选的每条路由每用户每秒请求数限制;`0` 或空则继承 `--throttle.user`。允许空的位置字段(例如 `,,` 用于未使用的中间字段)。
### 文件提供程序
此提供程序使用带有路由规则的 yaml 文件。
`reproxy --file.enabled --file.name=config.yml`
`config.yml` 示例:
```yaml
default: # the same as * (catch-all) server
- { route: "^/api/svc1/(.*)", dest: "http://127.0.0.1:8080/blah1/$1" }
- {
route: "/api/svc3/xyz",
dest: "http://127.0.0.3:8080/blah3/xyz",
ping: "http://127.0.0.3:8080/ping",
remote: "192.168.1.0/24, 127.0.0.1", # optional, restrict access to the route
forward-health-checks: true # optional, forward /ping and /health to backend
}
- {
route: "^/admin/(.*)",
dest: "http://127.0.0.4:8080/$1",
auth: "admin:$2y$05$..." # optional, per-route basic auth (htpasswd bcrypt format)
}
- {
route: "^/upload/(.*)",
dest: "http://127.0.0.5:8080/$1",
timeout: 5m # optional, per-route request timeout (Go duration). 0 or omitted inherits --timeout.write
}
- {
route: "^/login",
dest: "http://127.0.0.6:8080/login",
throttle: 2 # optional, per-route req/sec per user. 0 or omitted inherits --throttle.user
}
srv.example.com:
- { route: "^/api/svc2/(.*)", dest: "http://127.0.0.2:8080/blah2/$1/abc" }
- { route: "/web/", dest: "/var/www", "assets": true }
"*.files.example.com":
- { route: "^/files/(.*)", dest: "http://123.123.200.200:8080/$host/$1" }
```
这是一个动态提供程序,文件更改将自动应用。
**不同域名上的多个静态站点**可以通过将服务器名称作为键并设置 `assets: true` 来提供服务:
```yaml
site-en.example.com:
- { route: "/", dest: "/var/www/en", "assets": true }
site-ru.example.com:
- { route: "/", dest: "/var/www/ru", "assets": true }
```
**重要:** 资产规则的 `route` 字段必须是路径前缀(例如 `/`、`/web/`),而不是正则表达式。像 `^/(.*)` 这样的正则模式无法与 `assets: true` 配合使用,因为静态资产匹配使用的是路径前缀比较,而不是正则表达式。
### Docker provider
Docker provider 支持全自动发现(使用 `--docker.auto`),无需额外配置。默认情况下,它会将所有形如 `http://<url>/<container name>/(.*)` 的请求重定向到指定容器的内部 IP 和暴露端口。只有活跃(运行中)的容器会被检测到。
此默认行为可通过标签更改:
- `reproxy.server` - 要匹配的服务器(主机名)。也可以是用逗号分隔的服务器列表。
- `reproxy.route` - 源路由(位置)
- `reproxy.dest` - 目标路径。注意:这不是完整 URL,而只是将追加到容器 ip:port 的路径
- `reproxy.port` - 已发现容器的目标端口
- `reproxy.ping` - 目标容器的 ping 路径。
- `reproxy.remote` - 用逗号分隔的子网或 IP 列表限制对路由的访问
- `reproxy.auth` - 用逗号分隔的 `user:bcrypt_hash` 对(由 `htpasswd -nbB` 生成)要求该路由使用基本认证
- `reproxy.assets` - 将资产映射设置为 `web-root:location`,例如 `reproxy.assets=/web:/var/www`
- `reproxy.keep-host` - 保持 host 头原样(`yes`、`true`、`1`)或替换为目标主机(`no`、`false`、`0`)
- `reproxy.forward-health-checks` - 将 `/ping` 和 `/health` 请求转发到后端,而不是由 reproxy 处理(`yes`、`true`、`1`)。当后端有自己的健康检查端点且响应具有应用特定内容时很有用。
- `reproxy.timeout` - 每路由请求超时,使用 Go duration 格式(例如 `5m`、`30s`)。`0` 或未设置时继承全局 `--timeout.write`。无效值会被忽略并给出警告。
- `reproxy.throttle` - 每路由每用户请求/秒限制。`0` 或未设置时继承 `--throttle.user`。无效或负值会被忽略并给出警告。
- `reproxy.enabled` - 启用(`yes`、`true`、`1`)或禁用(`no`、`false`、`0`)容器作为 reproxy 目标。
请注意:在没有 `--docker.auto` 的情况下,目标容器必须至少有一个 `reproxy.*` 标签才会被视为潜在目标。
使用 `--docker.auto` 时,所有暴露端口的容器都会被视作路由目标。有 3 种方式限制它:
- 使用 `--docker.exclude` 显式排除某些容器,即 `--docker.exclude=c1 --docker.exclude=c2 ...`
- 使用 `--docker.network` 仅允许特定 docker 网络
- 设置标签 `reproxy.enabled=false` 或 `reproxy.enabled=no` 或 `reproxy.enabled=0`
如果未定义 `reproxy.route`,默认路由为 `^/<container_name>/(.*)`。如果所有代理源应具有相同的前缀模式,例如 `/api/(.*)`,用户可以为所有基于容器的路由定义公共前缀(在此例中为 `/api`)。这可以通过 `--docker.prefix` 参数完成。
Docker provider 还允许定义多组 `reproxy.N.something` 标签,以在同一容器上匹配多个不同的路由。这很有用,因为在某些情况下单个容器可能暴露多个端点,例如公共 API 和某些管理 API。上述所有标签都可以与“N 索引”一起使用,即 `reproxy.1.server`、`reproxy.1.port` 等。N 应在 0 到 9 范围内。
这是一个动态 provider,容器状态的任何变化都会自动应用。
### Consul Catalog provider
用法:`reproxy --consul-catalog.enabled`
Consul Catalog provider 会定期(默认每秒)调用 Consul API 以获取带有任何 `reproxy.` 前缀标签的服务。用户可以通过 `--consul-catalog.interval` 命令行标志重新定义检查间隔,也可以通过 `--consul-catalog.address` 命令行选项重新定义 consul 地址。默认地址为 `http://127.0.0.1:8500`。
例如:
```
reproxy --consul-catalog.enabled --consul-catalog.address=http://192.168.1.100:8500 --consul-catalog.interval=10s
```
默认情况下,provider 会为每个服务设置以下值:
- enabled `false`
- server `*`
- route `^/(.*)`
- dest `http://<SERVICE_ADDRESS_FROM_CONSUL>/$1`
- ping `http://<SERVICE_ADDRESS_FROM_CONSUL>/ping`
此默认值可通过标签进行修改:
- `reproxy.server` - 要匹配的服务器(主机名)。也可以是以逗号分隔的服务器列表。
- `reproxy.route` - 源路由(location)
- `reproxy.dest` - 目标路径。注意:这不是完整 URL,而只是将追加到服务 ip:port 之后的路径
- `reproxy.port` - 所发现服务的目标端口
- `reproxy.remote` - 使用以逗号分隔的子网或 IP 列表限制对该路由的访问
- `reproxy.auth` - 使用以逗号分隔的 `user:bcrypt_hash` 对(由 `htpasswd -nbB` 生成)要求该路由进行基本认证
- `reproxy.ping` - 目标服务的 ping 路径。
- `reproxy.forward-health-checks` - 将 `/ping` 和 `/health` 请求转发到后端(`true`、`yes`、`1`)。
- `reproxy.timeout` - 以 Go duration 表示的单路由请求超时(例如 `5m`、`30s`)。`0` 或未设置时继承全局 `--timeout.write`。无效值将被忽略并给出警告。
- `reproxy.throttle` - 单路由每用户每秒请求数限制。`0` 或未设置时继承 `--throttle.user`。无效值或负值将被忽略并给出警告。
- `reproxy.enabled` - 启用(`yes`、`true`、`1`)或禁用(`任何其他值`)该服务作为 reproxy 目标。
### Compose 相关细节
如果规则作为 docker compose 环境的一部分设置,带有正则分组的目标将与 compose 语法冲突。也就是说,在 compose 环境中尝试使用 `https://api.example.com/$1` 会因语法错误而失败。这里的标准解决方案是通过将 `$` 符号替换为 `$$` 来“转义”,即 `https://api.example.com/$$1`。此替换由 docker compose 支持,与 reproxy 本身无关。另一种方式是使用 `@` 代替 `$`,这在 reproxy 层面受支持,即 `https://api.example.com/@1`_
## SSL 支持
SSL 模式(默认为 none)可设置为 `auto`(ACME/LE 证书)、`static`(现有证书)或 `none`。如果开启 `auto`,将为所有发现的服务器名称自动签发 SSL 证书。用户可以通过设置 `--ssl.fqdn` 值来覆盖。在 `auto` 和 `static` SSL 模式下,Reproxy 将自动添加 `X-Forwarded-Proto` 和 `X-Forwarded-Port` 头。这些头对于代理后方的服务了解客户端使用的原始协议(http 或 https)和端口号非常有用。
当将 ACME 与发现 provider(docker、file、consul)一起使用时,会自动为新发现的服务器获取 SSL 证书,无需重启 reproxy。
### ACME 挑战
Reproxy 支持两种类型的 ACME 挑战用于 SSL 证书验证:
1. **HTTP-01 挑战**(默认):通过在特定 HTTP URL 上提供令牌来验证域名所有权。要求端口 80 可公开访问。
2. **DNS-01 挑战**:通过创建 DNS TXT 记录来验证域名所有权。此方法:
- 不要求端口 80 可访问
- 支持通配符证书
- 需要受支持的 DNS provider 配置
#### 挑战选择
Reproxy 会根据您的配置自动确定使用哪种挑战方法:
- **HTTP-01**(默认):未配置 DNS provider 时使用
- **DNS-01**:配置了 DNS provider 时使用
您无需显式选择挑战类型——只需在希望使用 DNS-01 挑战时配置 DNS provider 即可。
DNS 传播检查默认在 2 分钟后超时。对于发布挑战记录较慢的区域,可通过 `--ssl.dns.propagation-timeout=5m` 增加此时间。`--ssl.dns.ttl` 选项控制记录 TTL,不会改变传播超时。
#### 当前支持的 DNS Provider
Reproxy 目前包含对以下 DNS provider 的支持:
- **Cloudflare**:`--ssl.dns.type=cloudflare --ssl.dns.cloudflare.api-token=TOKEN`
- **Route53 (AWS)**:`--ssl.dns.type=route53 --ssl.dns.route53.region=REGION --ssl.dns.route53.hosted-zone-id=ID`
- **Gandi**:`--ssl.dns.type=gandi --ssl.dns.gandi.bearer-token=TOKEN`
- **DigitalOcean**:`--ssl.dns.type=digitalocean --ssl.dns.digitalocean.api-token=TOKEN`
- **Hetzner**:`--ssl.dns.type=hetzner --ssl.dns.hetzner.api-token=TOKEN`
- **Linode**:`--ssl.dns.type=linode --ssl.dns.linode.api-token=TOKEN`
- **GoDaddy**:`--ssl.dns.type=godaddy --ssl.dns.godaddy.api-token=TOKEN`
- **Namecheap**:`--ssl.dns.type=namecheap --ssl.dns.namecheap.api-key=KEY --ssl.dns.namecheap.user=USER`
- **Scaleway**:`--ssl.dns.type=scaleway --ssl.dns.scaleway.secret-key=KEY --ssl.dns.scaleway.organization-id=ID`
- **Porkbun**:`--ssl.dns.type=porkbun --ssl.dns.porkbun.api-key=KEY --ssl.dns.porkbun.api-secret-key=SECRET`
- **DNSimple**:`--ssl.dns.type=dnsimple --ssl.dns.dnsimple.api-access-token=TOKEN --ssl.dns.dnsimple.account-id=ID`
- **DuckDNS**:`--ssl.dns.type=duckdns --ssl.dns.duckdns.api-token=TOKEN`
以 Cloudflare 作为 DNS 提供商的示例:
```
export CLOUDFLARE_API_TOKEN=your_api_token
reproxy --ssl.type=auto [email protected] --ssl.fqdn=example.com
```
DNS-01 质询在以下情况下特别有用:
- 你的服务器没有公开暴露 80 端口
- 你需要通配符证书(例如 *.example.com)
- 你位于限制严格的防火墙之后
## 请求头
Reproxy 允许通过传递 `--drop-header` 参数(可重复)来清理(移除)传入的请求头。该参数可用于确保某些由服务内部设置的请求头无法被最终用户设置/伪造。例如,如果某些负责认证的服务设置了 `X-Auth-User` 和 `X-Auth-Token`,那么通过传递 `--drop-header=X-Auth-User --drop-header=X-Auth-Token` 参数或通过环境变量 `DROP_HEADERS=X-Auth-User,X-Auth-Token` 从传入请求中移除这些请求头通常是合理的。
相反的功能,即设置传出请求头,也同样受支持。这在许多情况下都很有用,例如强制执行某些自定义 CORS 规则、与安全相关的请求头等等。这可以通过 `--header` 参数(可重复)或环境变量 `HEADER` 来完成。例如,下面是通过 docker compose 实现的方式:
```yaml
environment:
- HEADER=
X-Frame-Options:SAMEORIGIN,
X-XSS-Protection:1; mode=block;,
Content-Security-Policy:default-src 'self'; style-src 'self' 'unsafe-inline';
```
## 日志记录
默认情况下不会生成请求日志。可以通过设置 `--logger.enabled` 来开启。该日志(自动轮转)采用 [Apache 组合日志格式](http://httpd.apache.org/docs/2.2/logs.html#combined)
用户还可以通过 `--logger.stdout` 开启标准输出日志。这不会影响上述文件日志记录,但会输出一些关于已处理请求的简要信息,类似如下:
```
2021/04/16 01:17:25.601 [INFO] GET - /echo/image.png - xxx.xxx.xxx.xxx - 200 (155400) - 371.661251ms
2021/04/16 01:18:18.959 [INFO] GET - /api/v1/params - xxx.xxx.xxx.xxx - 200 (74) - 1.217669m
```
## 资源服务器
用户可以开启资源服务器(默认关闭)以提供静态文件服务。只要设置了 `--assets.location`,它就会将 `assets.root` 下所有非代理请求视为对静态文件的请求。资源服务器可以在没有任何代理提供者的情况下使用;在此模式下,reproxy 充当静态内容的简单 Web 服务器。资源服务器还支持“spa 模式”,通过 `--assets.spa` 启用,此时所有未找到的请求都会转发到 `index.html`。
除了通用资源服务器外,还支持多个自定义资源服务器。每个提供者定义此类静态规则的方式不同,某些提供者可能根本不支持。例如,多个资源服务器在 static(命令行提供者)、file 提供者中是有意义的,甚至在 docker 提供者中也有用,但在 consul catalog 提供者中则几乎没有意义。
1. static 提供者 - 如果源元素以 `assets:` 或 `spa:` 为前缀,它将被视为文件服务器。例如 `*,assets:/web,/var/www,` 将使用位于 `/var/www` 目录之上的文件服务器来服务所有 `/web/*` 请求。
2. file 提供者 - 设置可选字段 `assets: true` 或 `spa: true`。注意:`route` 字段必须是路径前缀(例如 `/`、`/web/`),而不是正则表达式模式。
3. docker 提供者 - `reproxy.assets=web-root:location`,即 `reproxy.assets=/web:/var/www`。切换到 spa 模式通过将 `reproxy.spa` 设置为 `yes` 或 `true` 来完成。
### 缓存
资源服务器支持通过 `--assets.cache=<duration>` 参数进行缓存控制。`0s` 时长(默认值)会关闭缓存控制。时长是一系列十进制数字,每个数字带有可选的小数部分和单位后缀,例如 "300ms"、"1.5h" 或 "2h45m"。有效的时间单位为 "ns"、"us"(或 "µs")、"ms"、"s"、"m"、"h" 和 "d"。
有两种方式设置缓存时长:
1. 为所有静态资源设置单一值。这很简单,如 `--assets.cache=48h`。
2. 为不同 MIME 类型设置自定义时长。它应包含两部分——默认值和 mime:duration 对。在命令行中,这看起来像多个 `--assets.cache` 选项,即 `--assets.cache=48h --assets.cache=text/html:24h --assets.cache=image/png:2h`。环境变量值应以逗号分隔,即 `ASSETS_CACHE=48h,text/html:24h,image/png:2h`
自定义 404(未找到)页面可以通过 `--assets.not-found=<path>` 参数设置。该路径应相对于资源根目录。
## 将 reproxy 用作基础镜像
仅提供纯静态内容是流行的用例之一。通常这用于仅提供 UI 的独立前端容器。使用资源服务器,这样的容器几乎可以轻松构建。以下是一个来自提供 [reproxy.io](http://reproxy.io) 服务的容器的示例
```docker
FROM node:22-alpine as build
WORKDIR /build
COPY site/ /build
COPY README.md /build/src/index.md
RUN yarn --frozen-lockfile
RUN yarn build
RUN ls -la /build/public
FROM ghcr.io/umputun/reproxy
COPY --from=build /build/public /srv/site
EXPOSE 8080
USER app
ENTRYPOINT ["/srv/reproxy", "--assets.location=/srv/site"]
```
它只需要将静态资源复制到某个位置,并将该位置作为 `"--assets.location` 传递给 reproxy 入口点即可。
## SPA 友好模式
一些 SPA 应用依赖代理以特殊方式处理静态资源上的 404,即将其重定向到 "/index.html"。这类似于 nginx 的 `try_files $uri $uri/ …` 指令,而且显然,这一功能对现代 Web 应用来说有些重要。
此模式默认关闭,可通过设置 `--assets.spa` 或 `ASSETS_SPA=true` 环境变量来开启。
## 重定向
默认情况下,reproxy 将目标视为代理位置,即它在内部发起 http 调用并将响应返回给客户端。然而,通过在目标 URL 前加上 `@code` 前缀,可以将此行为改为永久(状态码 301)或临时(状态码 302)重定向。也就是说,将目标设置为 `@301 https://example.com/something` 将导致永久 http 重定向到 `Location: https://example.com/something`
支持的代码:
- `@301`、`@perm` - 永久重定向
- `@302`、`@temp`、`@tmp` - 临时重定向
## 更多选项
- `--gzip` 为响应启用 gzip(或 deflate)压缩。该决定按响应逐个做出,依据其最终标头:
- 匹配 `--gzip-exclude` 的媒体类型按原样发送。该值是以逗号分隔的精确类型(`image/png`)或前缀(`audio/*`)列表。默认会跳过音频、视频、压缩图像(jpeg、png、gif、webp、avif)、woff 字体和常见归档文件。自定义列表会替换默认值,而空值(`--gzip-exclude=`)会关闭排除。
- 部分响应(`206`,或任何带有 `Content-Range` 的响应)永远不会被压缩,因此 `Range` 请求可以继续正常工作。
- reproxy 不会重新压缩已带有 `Content-Encoding` 的响应。客户端的 `Accept-Encoding` 会被转发到上游,因此自行压缩的上游会为其响应做出决定,而排除列表仅适用于 reproxy 执行的压缩。
- 压缩后的响应会移除 `Accept-Ranges` 和原始的 `Content-Length`,并且强 `ETag` 会变为弱 `ETag`(`W/"..."`),因为其字节与原始内容不同。
- `--max=N` 允许设置请求的最大大小(默认 64k)。将其设置为 `0` 会禁用大小检查。
- `--timeout.*` 用于服务器和代理传输的各种超时。请参阅 [所有应用程序选项](#all-application-options) 中的 `timeout` 部分。零值或负值表示没有超时。
- `--insecure` 禁用对目标主机的 SSL 验证。这对于自签名证书很有用。
## 默认端口
为了消除传递自定义参数/环境变量的需要,默认的 `--listen` 是动态的,并试图对典型情况做到合理且有帮助:
- 如果用户为 `--listen` 设置了任何内容,则忽略下面的所有逻辑,直接使用传入的 host:port。
- 如果用户没有为 `--listen` 设置任何内容,并且 reproxy 在 docker 容器外运行,则 http 模式(`ssl.type=none`)的默认值为 `127.0.0.1:80`,ssl 模式(`ssl.type=auto` 或 `ssl.type=static`)的默认值为 `127.0.0.1:443`。
- 如果用户没有为 `--listen` 设置任何内容,并且 reproxy 在 docker 内运行,则 http 模式的默认值为 `0.0.0.0:8080`,ssl 模式的默认值为 `0.0.0.0:8443`。
另一个以类似动态方式设置的默认值是 `--ssl.http-port`。在 docker 容器内运行时它被设置为 `8080`,在容器外则为 `80`。
## Ping、健康检查和故障转移
reproxy 为此目的提供了两个端点:
- `/ping` 以 `pong` 响应,表示 reproxy 已启动并运行
- 如果所有目标服务器对其 ping 请求都以 `200` 响应,则 `/health` 返回 `200 OK` 状态;如果任何服务器以非 200 代码响应,则返回 `417 Expectation Failed`。它还会返回包含通过/失败服务详细信息的 json 正文。
除上述端点外,reproxy 还支持可选的实时健康检查。在此情况下(若已启用),会定期检查每个目标地址的 ping 响应,并排除失败的目标路由。同一或不同提供方可能返回多个相同目标,仅选取通过检查的那个。若发现并有多项匹配通过,则根据 `lb-type` 策略选取最终一项(默认为随机选择)。
要开启实时健康检查,用户应设置 `--health-check.enabled`(或环境变量 `HEALTH_CHECK_ENABLED=true`)。要自定义检查间隔,可使用 `--health-check.interval=`。
## 管理 API
可选,可通过 `--mgmt.enabled` 开启。在 `mgmt.listen`(地址:端口)上暴露 2 个端点:
- `GET /routes` - 所有已发现路由的列表
- `GET /metrics` - 返回 prometheus 指标(`http_requests_total`、`response_status` 和 `http_response_time_seconds`)
默认情况下,`http_response_time_seconds` 使用原始请求路径作为标签,这可能在动态 URL(例如 `/api/users/123`、`/api/users/456`)下导致高基数。使用 `--mgmt.low-cardinality` 可改为使用路由模式(例如 `^/api/users/(.*)`),从而显著降低指标基数。
_另见 [examples/metrics](https://github.com/umputun/reproxy/tree/master/examples/metrics)_
## 错误报告
若请求不匹配任何提供的路由和资源,Reproxy 返回 502(Bad Gateway)错误。若发生某些意外的内部错误,则返回 500。默认情况下,reproxy 渲染最简单的文本版错误——“Server error”。设置 `--error.enabled` 可开启默认的 HTML 错误消息,而通过 `--error.template` 用户可设置任意自定义 HTML 模板文件用于错误渲染。该模板有两个变量:`{{.ErrCode}}` 和 `{{.ErrMessage}}`。例如,模板 `oh my! {{.ErrCode}} - {{.ErrMessage}}` 将渲染为 `oh my! 502 - Bad Gateway`
## 限流
Reproxy 允许为整体系统活动以及每个用户定义系统级最大 req/sec 值。0 值(默认)视为不限制。
用户活动限制同时适用于匹配和不匹配的路由。所有不匹配的路由被视为“单一目标组”,并获得一个公共限流器,其值为 `rate*3`。这意味着若通过 `--throttle.user=10` 定义 10(req/sec),最终用户对静态资源或不匹配路由每秒最多可执行 30 次请求。对于匹配的路由,此限流器按目标(路由)维护,即代理到 s1.example.com/api 的请求允许 10 r/s,而代理到 s2.example.com 的请求允许另外 10 r/s。
### 按路由超时与限流
单个路由可通过提供方特定的 `timeout` 和 `throttle` 字段覆盖全局 `--timeout.write` 和 `--throttle.user` 设置。这对于需要高于全局写入超时截止时间的长时间运行端点(例如上传、报告生成)很有用,也适用于在不提高其他所有内容全局上限的情况下收紧敏感路由(例如登录)的速率限制。
优先级规则为“零继承全局,正值覆盖”:`timeout: 0`(或无 `timeout` 字段)的路由保留全局 `--timeout.write`;`timeout: 5m` 的路由仅对匹配请求覆盖它。同样的规则适用于 `throttle`。
按路由超时会覆盖匹配请求的连接读写截止时间,因此它可以超出全局 `--timeout.write`(默认 30s)。没有按路由超时的路由仍遵循全局设置。
**限制 — 传输层响应头超时:** 每路由的 `timeout` 不会覆盖 `--timeout.resp-header`(默认 5 秒)。该超时设置在共享的 `http.Transport` 上,并在上游开始发送响应头之前生效。如果上游开始响应所需时间超过 `--timeout.resp-header`(例如响应缓慢的报告端点),则无论每路由的 `timeout` 如何设置,请求都会在该边界处失败。要支持此类路由,请将 `--timeout.resp-header` 全局提升至任何慢响应路由所需的最大值。对传输层超时的每路由覆盖有意不在支持范围内。
提供程序语法:
- **文件提供程序**(YAML):`timeout: 5m`、`throttle: 2`
- **静态提供程序**(CSV):第 6 和第 7 个位置字段,例如 `*,^/upload/(.*),http://up:8080/$1,,,5m,2`
- **Docker 提供程序**:`reproxy.timeout=5m`、`reproxy.throttle=2`(对于多路由容器,使用 `reproxy.<n>.timeout` / `reproxy.<n>.throttle`)
- **Consul Catalog 提供程序**:`reproxy.timeout=5m`、`reproxy.throttle=2`
## 上游连接限制
Reproxy 允许配置上游连接池设置,以控制与后端服务器保持的连接数量:
- `--upstream.max-idle-conns` - 所有上游主机之间空闲连接的最大数量。默认值:100。
- `--upstream.max-conns` - 每个上游主机的最大连接数(0 = 无限制)。默认值:0。
设置 `--upstream.max-conns` 可限制与每个后端的并发连接数,这在上游服务器容量有限或需要防止连接耗尽时非常有用。
## 基本认证
Reproxy 支持两种模式的基本认证:全局(所有路由)和每路由。
### 全局基本认证
全局基本认证保护所有路由。这在开发和测试期间保护端点时非常有用。要启用,请使用 `--basic-htpasswd=<file location>` 或环境变量 `BASIC_HTPASSWD=<file location>` 设置 htpasswd 文件。
Reproxy 期望 htpasswd 文件采用以下格式:
```
username1:bcrypt(password1)
username2:bcrypt(password2)
...
```
这可以通过 `htpasswd -nbB` 命令生成,例如 `htpasswd -nbB test passwd`
### 按路由基本认证
按路由认证允许为不同路由设置不同的凭据。当某个路由配置了按路由认证时,该路由将绕过全局认证。按路由认证通过特定于提供程序的设置进行配置:
- **File 提供程序**:YAML 中的 `auth` 字段,例如 `auth: "user1:$2y$..., user2:$2y$..."`
---
[Read more](https://github.com/umputun/reproxy)