Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
reproxy — 轻量级边缘HTTP(S)服务器和反向代理,具有自动SSL、Docker/Consul发现、按路由认证、速率限制和基于健康检查的故障转移。 | Kitploit
工具/GitHubGitHub/umputun/reproxy
身份验证与授权通用工具Web安全网络安全API 安全
GitHubumputun/reproxy

reproxy

轻量级边缘HTTP(S)服务器和反向代理,具有自动SSL、Docker/Consul发现、按路由认证、速率限制和基于健康检查的故障转移。

查看仓库
1.3k96120小时36分前Kitploit 审核通过

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享
网站
Reproxy | 简易反向代理

Reproxy 是一个简单的边缘 HTTP(s) 服务器/反向代理,支持多种提供者(docker、static、file、consul catalog)。一个或多个提供者提供关于请求服务器、请求 URL、目标 URL 和健康检查 URL 的信息。它以单个二进制文件或 Docker 容器的形式分发。

  • 通过 Let's Encrypt 自动 SSL 终止
  • 支持用户提供的 SSL 证书
  • 简单但灵活的代理规则
  • 静态、命令行代理规则提供者
  • 动态、基于文件的代理规则提供者
  • Docker 提供者,自动发现
  • Consul Catalog 提供者,通过服务标签发现
  • 支持多个(虚拟)主机
  • 可选流量压缩
  • 可选基于 IP 的访问控制
  • 每路由基本认证
  • 用户自定义大小限制和超时
  • 单个二进制文件分发
  • Docker 容器分发
  • 内置静态资源服务器,支持可选的“SPA 友好”模式
  • 支持重定向规则
  • 可选的全局活动限制以及用户活动限制
  • 实时健康检查与故障转移/负载均衡
  • 管理服务器,提供路由信息和 Prometheus 指标
  • 通过 RPC 支持插件,实现自定义功能
  • 可选的日志记录,支持 Apache 日志格式和简化的 stdout 报告。

build Coverage Status Go Report Card Docker Hub

服务器(主机)可以设置为 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} 将被替换为匹配的主机名。也可以使用 $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 包。

  • 二进制分发:在发布页面下载合适的文件
  • Homebrew 用户:brew install umputun/apps/reproxy
  • Docker 容器可在 Docker Hub 以及 Github Container Registry 上获取。例如:docker pull umputun/reproxy 或 docker pull ghcr.io/umputun/reproxy。

最新稳定版本带有 :vX.Y.Z 的 Docker 标签(带 :latest 别名),当前 master 分支带有 :master 标签。

提供者

代理规则由各种提供者提供。目前包括 file、docker、static 和 consul-catalog。每个提供者可以为代理请求和静态资源定义多条路由规则。用户可以同时设置多个提供者。

在 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)。

第4个元素定义可选的 ping URL,用于健康报告。第5个元素可选地启用将健康检查请求转发到后端(true、yes、1)。有关详细信息,请参见健康检查部分。第6个元素是可选的每条路由请求超时时间(Go 持续时间,例如 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" }
root@kitploit:~
这是一个动态提供器,文件更改将自动应用。

**不同域名上的多个静态网站**可以通过将服务器名称作为键并使用 `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 提供器

Docker 提供器支持完全自动发现(使用 --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 头不变(、、)或替换为目标主机(、、)

请注意:如果没有 --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 提供器还允许定义多组 reproxy.N.something 标签以匹配同一容器上的多条不同路由。这在某些情况下很有用,例如单个容器可能暴露多个端点,比如公共 API 和管理 API。上述所有标签都可以使用“N 索引”,即 reproxy.1.server、reproxy.1.port 等。N 的取值范围为 0 到 9。

这是一个动态提供器,容器状态的任何更改都会自动应用。

Consul Catalog 提供器

使用:reproxy --consul-catalog.enabled

Consul Catalog 提供器定期调用 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

root@kitploit:~
默认情况下,provider 会为每个服务设置以下值:
- enabled `false`
- server `*`
- route `^/(.*)`
- dest `http://<SERVICE_ADDRESS_FROM_CONSUL>/$1`
- ping `http://<SERVICE_ADDRESS_FROM_CONSUL>/ping`

可通过标签修改这些默认值:

- `reproxy.server` - 要匹配的服务器(主机名)。也可以是用逗号分隔的服务器列表。
- `reproxy.route` - 源路由(路径)
- `reproxy.dest` - 目标路径。注意:这不是完整 URL,而是将附加到服务 IP:端口 的路径
- `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 持续时间格式,例如 `5m`、`30s`)。`0` 或未设置则继承全局 `--timeout.write`。无效值将被忽略并发出警告
- `reproxy.throttle` - 每个路由、每个用户的请求速率限制(req/sec)。`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 模式(默认无)可设置为 `auto`(ACME/LE 证书)、`static`(现有证书)或 `none`。如果启用 `auto`,则会为所有发现的服务器名称自动签发 SSL 证书。用户可通过设置 `--ssl.fqdn` 值进行覆盖。在 `auto` 和 `static` SSL 模式下,Reproxy 会自动添加 `X-Forwarded-Proto` 和 `X-Forwarded-Port` 头部。这些头部有助于代理后的服务了解客户端使用的原始协议(http 或 https)和端口号。

当通过发现提供者(docker、file、consul)使用 ACME 时,SSL 证书会自动为新发现的服务器获取,无需重启 reproxy。

### ACME 挑战

Reproxy 支持两种类型的 ACME 挑战用于 SSL 证书验证:

1. **HTTP-01 挑战**(默认):通过在特定 HTTP URL 上提供令牌来验证域名所有权。需要 80 端口可公开访问。

2. **DNS-01 挑战**:通过创建 DNS TXT 记录来验证域名所有权。此方法:
   - 不需要 80 端口可访问
   - 支持通配符证书
   - 需要配置支持的 DNS 提供商

#### 挑战选择

Reproxy 根据您的配置自动决定使用哪种挑战方法:

- **HTTP-01**(默认):未配置 DNS 提供商时使用
- **DNS-01**:配置了 DNS 提供商时使用

您无需显式选择挑战类型——只需在希望使用 DNS-01 挑战时配置 DNS 提供商即可。

#### 当前支持的 DNS 提供商

Reproxy 目前支持以下 DNS 提供商:

- **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';

root@kitploit:~
## 日志记录

默认情况下不生成请求日志。可以通过设置 `--logger.enabled` 来启用。日志(自动轮替)采用 [Apache Combined Log 格式](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 服务器。资产服务器还通过 --assets.spa 支持“spa 模式”,该模式下所有未找到的请求都会被转发到 index.html。

除了公共资产服务器外,还支持多个自定义资产服务器。每个提供者定义此类静态规则的方式不同,有些提供者可能根本不支持。例如,多个资产服务器在静态(命令行提供者)、文件提供者,甚至在 docker 提供者中都很有用,但在 consul 目录提供者中意义不大。

  1. 静态提供者 - 如果源元素以 assets: 或 spa: 为前缀,则将被视为文件服务器。例如 *,assets:/web,/var/www, 将使用基于 /var/www 目录的文件服务器处理所有 /web/* 请求。
  2. 文件提供者 - 设置可选字段 assets: true 或 spa: true。注意:route 字段必须是路径前缀(例如 /、/web/),而不是正则表达式模式。
  3. docker 提供者 - reproxy.assets=web-root:location,即 reproxy.assets=/web:/var/www。通过将 reproxy.spa 设置为 yes 或 true 来切换到 spa 模式。

缓存

资产服务器通过 --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。

可以通过 --assets.not-found=<path> 参数设置自定义 404(未找到)页面。该路径应相对于资产根目录。

将 reproxy 用作基础镜像

提供纯静态内容是常见的用例之一。通常用于只提供 UI 的独立前端容器。有了资产服务器,制作这样的容器几乎毫不费力。以下示例来自服务 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"]

root@kitploit:~
只需将静态资源复制到某个位置,并将该位置作为 `"--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 压缩。
- `--max=N` 允许设置请求的最大大小(默认为 64k)。设置为 `0` 则禁用大小检查。
- `--timeout.*` 服务器和代理传输的各种超时设置。参见[所有应用选项](#all-application-options)中的 `timeout` 部分。零值或负值表示无超时。
- `--insecure` 禁用对目标主机的 SSL 验证。这对于自签名证书很有用。

## 默认端口

为了消除传递自定义参数/环境的需求,默认的 `--listen` 是动态的,并尽量对典型场景合理且有用:

- 如果用户为 `--listen` 设置了任何值,则忽略以下所有逻辑,直接使用传入的主机:端口。
- 如果用户未设置 `--listen` 且 reproxy 在 Docker 容器外运行,则默认为 `127.0.0.1:80`(HTTP 模式,`ssl.type=none`)和 `127.0.0.1:443`(SSL 模式,`ssl.type=auto` 或 `ssl.type=static`)。
- 如果用户未设置 `--listen` 且 reproxy 在 Docker 容器内运行,则默认为 `0.0.0.0:8080`(HTTP 模式)和 `0.0.0.0:8443`(SSL 模式)。

另一个以类似动态方式设置的默认值是 `--ssl.http-port`。在 Docker 容器内运行时设为 `8080`,否则设为 `80`。

## Ping、健康检查和故障转移

reproxy 为此提供了两个端点:

- `/ping` 响应 `pong`,表示 reproxy 正在运行。
- `/health` 如果所有目标服务器对其 ping 请求都响应了 `200`,则返回 `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 允许为总体系统活动以及每个用户定义系统级别的最大请求/秒值。0 值(默认)视为无限制。

用户限制适用于匹配和未匹配的路由。所有未匹配的路由被视为一个“单一目标组”,并获得一个公共限制器,其速率为 `rate*3`。这意味着如果通过 `--throttle.user=10` 定义了 10(请求/秒),则最终用户能够对静态资源或未匹配路由每秒执行最多 30 个请求。对于匹配的路由,该限制器按目标(路由)维护,即代理到 s1.example.com/api 的请求将允许 10 请求/秒,而代理到 s2.example.com 的请求将允许另外 10 请求/秒。

### 每路由超时与限流

单个路由可以通过提供者特定的 `timeout` 和 `throttle` 字段覆盖全局的 `--timeout.write` 和 `--throttle.user` 设置。这对于需要比全局写入超时更高的截止时间的长时间运行端点(例如上传、报告生成)以及在不提高所有其他全局上限的情况下收紧敏感路由(例如登录)的速率限制非常有用。

优先级规则是:零值继承全局设置,正值覆盖全局设置:设置 `timeout: 0`(或没有 `timeout` 字段)的路由保持全局的 `--timeout.write`;设置 `timeout: 5m` 的路由则仅在匹配的请求上覆盖该设置。同样的规则适用于 `throttle`。

每路由超时会覆盖匹配请求的连接读取和写入截止时间,因此它可以超出全局的 `--timeout.write`(默认 30 秒)。没有每路由超时的路由仍然遵循全局设置。

**限制——传输层响应头超时:** 每路由 `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=<文件位置>` 或环境变量 `BASIC_HTPASSWD=<文件位置>` 设置 htpasswd 文件。

Reproxy 期望 htpasswd 文件采用以下格式:```
username1:bcrypt(password1)
username2:bcrypt(password2)
...

此密码可通过 htpasswd -nbB 命令生成,例如 htpasswd -nbB test passwd

按路由的基本认证

按路由认证允许不同路由使用不同凭据。当路由配置了按路由认证时,该路由的全局认证将被绕过。按路由认证通过提供者特定设置进行配置:

  • 文件提供者:YAML 中的 auth 字段,例如 auth: "user1:$2y$..., user2:$2y$..."
  • Docker 提供者:reproxy.auth 标签
  • Consul Catalog 提供者:reproxy.auth 标签
  • 静态提供者:不支持(请使用文件提供者进行按路由认证)

格式是逗号分隔的 user:bcrypt_hash 对列表(与 htpasswd 格式相同)。可以为同一路由指定多个用户。

使用 docker-compose 的示例:```yaml services: admin-api: labels: - "reproxy.route=^/admin/(.*)" - "reproxy.dest=/$1" - "reproxy.auth=admin:$$2y$$05$$hashedpassword"

root@kitploit:~
注意:在 docker-compose 中,`$` 必须转义为 `$$`。

## 基于IP的访问控制

Reproxy 允许通过逗号分隔的子网或 IP 列表来限制对路由的访问。这在开发和测试阶段很有用,之后才允许无限制访问。它也可以用于限制对内部服务的访问。默认情况下,所有路由都对所有客户端开放。

要限制对路由的访问,用户应为路由设置相应的键,即对于 docker 和 consul 使用 `reproxy.remote`,对于文件提供程序使用 `remote`。该值应为逗号分隔的子网或 IP 或子网的列表。例如 `127.0.0.1, 192.168.1.0/24`。更多详情请参阅 [docker 提供程序](#docker-provider) 和 [consul 目录提供程序](#consul-catalog-provider) 部分。

默认情况下,reproxy 会检查客户端请求的远程地址。然而,在某些情况下,例如在其他代理后面或使用 docker 桥接网络时,这可能无法按预期工作。可以通过 `--remote-lookup-headers` 参数来改变这种行为,使其检查 `X-Real-IP` 或 `X-Forwarded-For` 头部的值(按此顺序)并进行检查。如果未设置头部,则仍会针对客户端的远程地址进行检查。这些头部由客户端提供,且极易被伪造,因此仅当 reproxy 运行在受信任的前端代理之后,且该代理始终设置并覆盖这些头部时,才应启用此参数。

应谨慎使用头部检查,因为它们可能被伪造。当启用 `--remote-lookup-headers` 时,IP 白名单完全依赖于这一信任假设:发送包含允许地址的 `X-Real-IP` 或 `X-Forwarded-For` 头部的客户端可能会绕过限制。仅当 reproxy 位于控制这些头部的受信任代理之后,并且您能保证它们不会被伪造时,才启用此选项。

## 插件支持

reproxy 的核心功能可以通过外部插件扩展。每个插件都是一个独立的进程/容器,实现了 [rpc 服务器](https://golang.org/pkg/net/rpc/)。插件向 reproxy 调度器注册,并添加到中间件链中。每个插件接收包含原始 URL、头部和所有匹配路由信息的请求,并返回头部和状态码。任何 >= 400 的状态码都被视为错误响应,并立即终止流程,返回代理错误。插件可以设置两种类型的头部:

- `HeadersIn` - 传入头部。这些头部将发送到代理的 URL
- `HeadersOut` - 传出头部。将发送回客户端

默认情况下,插件设置的头部将与原始头部混合。如果插件需要控制所有头部,例如丢弃其中一些,插件可以设置 `OverrideHeaders*` 字段,向核心 reproxy 进程指示需要覆盖所有头部而不是混合。

- `OverrideHeadersIn` - 表示插件负责所有传入头部。
- `OverrideHeadersOut` - 表示插件负责所有传出头部

为简化开发过程,提供了所有构建模块。其中包括处理注册、监听和分发调用的 `lib.Plugin`,以及定义输入和输出的 `lib.Request` 和 `lib.Response`。插件作者应实现满足 `func(req lib.Request, res *lib.HandlerResponse) (err error)` 签名的具体处理程序。每个插件可以包含多个此类处理程序。

_更多信息请参阅 [examples/plugin](https://github.com/umputun/reproxy/tree/master/examples/plugin)_

## 容器安全

默认情况下,reproxy 容器以 root 用户身份运行,以简化初始设置并访问 Docker 套接字。这是为了让 Docker 提供程序发现正在运行的容器。但是,如果不需要此类发现或未使用 Docker 提供程序,建议将用户更改为具有较低权限的用户。可以在 docker-compose 级别和 docker 级别通过 `user` 选项完成此操作,详情请参见以下部分。

有时,即使在 Docker 内部路由的情况下,禁用 Docker 提供程序并使用静态或文件提供程序设置规则也是合理的。在同一 compose 中运行的所有容器共享同一网络,并可通过本地 DNS 访问。用户可以设置如下规则以避免 Docker 发现:`- STATIC_RULES=*,/api/email/(.*),http://email-sender:8080/$$1`。此规则期望 `email-sender` 容器定义在同一个 compose 中。请注意:即使目标服务定义在不同的 compose 文件中,用户也可以通过使用 Docker 网络来实现相同的结果。这样,reproxy 配置就可以与实际服务保持分离。

reproxy 容器内部除了 reproxy 二进制文件之外没有其他内容,因为它构建在空(scratch)镜像之上。

### 以非 root 用户运行

容器内预创建了一个 UID 为 `1001`(属于组 `1001` 和 `999`)的用户,可用于以非 root 用户身份运行 reproxy:```yaml
services:
  reproxy:
    user: 1001
    image: umputun/reproxy:latest
# <...>
# see examples/ssl/docker-compose.yml for the full file example

如果您想使用 Docker 提供商,您需要确保该用户有权访问主机系统上的 Docker 套接字。如何设置这些权限取决于您的主机系统配置。有关配置 Docker 套接字权限的更多信息,请参阅 Docker 关于保护 Docker 守护进程套接字的文档。

选项

每个选项可以通过两种形式提供:命令行或环境键值对。某些命令行选项有短格式,例如 -l localhost:8080,而所有选项都有长格式,即 --listen=localhost:8080。每个选项的环境键(名称)列在 作为后缀,例如 [$LISTEN]。

所有大小选项都支持单位后缀,例如 10K(或 10k)表示千字节,16M(或 16m)表示兆字节,10G(或 10g)表示吉字节。没有任何后缀(即 1024)表示字节。

某些选项是可重复的,在这种情况下,用户可以通过命令行多次传递,或者在环境变量中以逗号分隔。例如 --ssl.fqdn 就是这样一个选项,可以传递为 --ssl.fqdn=a1.example.com --ssl.fqdn=a2.example.com 或作为环境变量 SSL_ACME_FQDN=a1.example.com,a2.example.com

以下是支持多个元素的所有选项列表:

  • ssl.fqdn (SSL_ACME_FQDN)
  • assets.cache (ASSETS_CACHE)
  • docker.exclude (DOCKER_EXCLUDE)
  • static.rule ($STATIC_RULES)
  • header ($HEADER)
  • drop-header ($DROP_HEADERS)

所有应用程序选项```

-l, --listen= listen on host:port (default: 0.0.0.0:8080/8443 under docker, 127.0.0.1:80/443 without) [$LISTEN] -m, --max= max request size (default: 64K) [$MAX_SIZE] -g, --gzip enable gz compression [$GZIP] -x, --header= outgoing proxy headers to add [$HEADER] --drop-header= incoming headers to drop [$DROP_HEADERS] --basic-htpasswd= htpasswd file for basic auth [$BASIC_HTPASSWD]
--lb-type=[random|failover|roundrobin] load balancer type (default: random) [$LB_TYPE] --signature enable reproxy signature headers [$SIGNATURE] --remote-lookup-headers enable remote lookup headers, trust only behind a trusted proxy [$REMOTE_LOOKUP_HEADERS] --keep-host keep original Host header as default when proxying [$KEEP_HOST] --insecure skip SSL verification on destination host [$INSECURE] --dbg debug mode [$DEBUG]

ssl: --ssl.type=[none|static|auto] ssl (auto) support (default: none) [$SSL_TYPE] --ssl.cert= path to cert.pem file [$SSL_CERT] --ssl.key= path to key.pem file [$SSL_KEY] --ssl.acme-location= dir where certificates will be stored by autocert manager (default: ./var/acme) [$SSL_ACME_LOCATION] --ssl.acme-email= admin email for certificate notifications [$SSL_ACME_EMAIL] --ssl.http-port= http port for redirect to https and acme challenge test (default: 8080 under docker, 80 without) [$SSL_HTTP_PORT] --ssl.fqdn= FQDN(s) for ACME certificates [$SSL_ACME_FQDN]

assets: -a, --assets.location= assets location [$ASSETS_LOCATION] --assets.root= assets web root (default: /) [$ASSETS_ROOT] --assets.spa spa treatment for assets [$ASSETS_SPA] --assets.cache= cache duration for assets [$ASSETS_CACHE] --assets.not-found= path to file to serve on 404, relative to location [$ASSETS_NOT_FOUND]

logger: --logger.stdout enable stdout logging [$LOGGER_STDOUT] --logger.enabled enable access and error rotated logs [$LOGGER_ENABLED] --logger.file= location of access log (default: access.log) [$LOGGER_FILE] --logger.max-size= maximum size before it gets rotated (default: 100M) [$LOGGER_MAX_SIZE] --logger.max-backups= maximum number of old log files to retain (default: 10) [$LOGGER_MAX_BACKUPS]

docker: --docker.enabled enable docker provider [$DOCKER_ENABLED] --docker.host= docker host (default: unix:///var/run/docker.sock) [$DOCKER_HOST] --docker.network= docker network [$DOCKER_NETWORK] --docker.exclude= excluded containers [$DOCKER_EXCLUDE] --docker.auto enable automatic routing (without labels) [$DOCKER_AUTO] --docker.prefix= prefix for docker source routes [$DOCKER_PREFIX] --docker.api-version= docker API version (default: 1.24) [$DOCKER_API_VERSION]

consul-catalog: --consul-catalog.enabled enable consul catalog provider [$CONSUL_CATALOG_ENABLED] --consul-catalog.address= consul address (default: http://127.0.0.1:8500) [$CONSUL_CATALOG_ADDRESS] --consul-catalog.interval= consul catalog check interval (default: 1s) [$CONSUL_CATALOG_INTERVAL]

file: --file.enabled enable file provider [$FILE_ENABLED] --file.name= file name (default: reproxy.yml) [$FILE_NAME] --file.interval= file check interval (default: 3s) [$FILE_INTERVAL] --file.delay= reload only after the file has been unchanged for this long (default: 500ms) [$FILE_DELAY]

static: --static.enabled enable static provider [$STATIC_ENABLED] --static.rule= routing rules [$STATIC_RULES]

timeout: --timeout.read-header= read header server timeout (default: 5s) [$TIMEOUT_READ_HEADER] --timeout.write= write server timeout (default: 30s) [$TIMEOUT_WRITE] --timeout.idle= idle server timeout (default: 30s) [$TIMEOUT_IDLE] --timeout.dial= dial transport timeout (default: 30s) [$TIMEOUT_DIAL] --timeout.keep-alive= keep-alive transport timeout (default: 30s) [$TIMEOUT_KEEP_ALIVE] --timeout.resp-header= response header transport timeout (default: 5s) [$TIMEOUT_RESP_HEADER] --timeout.idle-conn= idle connection transport timeout (default: 90s) [$TIMEOUT_IDLE_CONN] --timeout.tls= TLS hanshake transport timeout (default: 10s) [$TIMEOUT_TLS] --timeout.continue= expect continue transport timeout (default: 1s) [$TIMEOUT_CONTINUE]

mgmt: --mgmt.enabled enable management API [$MGMT_ENABLED] --mgmt.listen= listen on host:port (default: 0.0.0.0:8081) [$MGMT_LISTEN] --mgmt.low-cardinality use route patterns instead of raw paths for metrics labels [$MGMT_LOW_CARDINALITY]

error: --error.enabled enable html errors reporting [$ERROR_ENABLED] --error.template= error message template file [$ERROR_TEMPLATE]

health-check: --health-check.enabled enable automatic health-check [$HEALTH_CHECK_ENABLED] --health-check.interval= automatic health-check interval (default: 300s) [$HEALTH_CHECK_INTERVAL]

throttle: --throttle.system= throttle overall activity' (default: 0) [$THROTTLE_SYSTEM] --throttle.user= limit req/sec per user and per proxy destination (default: 0) [$THROTTLE_USER]

upstream: --upstream.max-idle-conns= max idle connections total (default: 100) [$UPSTREAM_MAX_IDLE_CONNS] --upstream.max-conns= max connections per upstream host (0=unlimited) (default: 0) [$UPSTREAM_MAX_CONNS]

plugin: --plugin.enabled enable plugin support [$PLUGIN_ENABLED] --plugin.listen= registration listen on host:port (default: 127.0.0.1:8081) [$PLUGIN_LISTEN]

Help Options: -h, --help Show this help message

root@kitploit:~
## 状态

该项目正在积极开发中,在 `v1` 发布前可能会有破坏性变更。不过,除非有充分理由,我们尽量不破坏现有功能。自 0.4.x 版本起,reproxy 被认为已足够用于实际使用,许多部署已在生产环境中运行。
下载工具
  • example.com,^/login,https://api.example.com/login,,,,2 — 每条路由的每个用户限流为 2 请求/秒(前面的位置字段留空)。
  • yes
    true
    1
    no
    false
    0
  • reproxy.forward-health-checks - 将 /ping 和 /health 请求转发到后端,而不是由 reproxy 处理(yes、true、1)。当后端具有特定于应用程序响应的健康检查端点时很有用。
  • reproxy.timeout - 每个路由的请求超时时间,格式为 Go 持续时间(例如 5m、30s)。0 或未设置时继承全局 --timeout.write。无效值会被忽略并发出警告。
  • reproxy.throttle - 每个路由的每个用户每秒请求限制。0 或未设置时继承 --throttle.user。无效或负值会被忽略并发出警告。
  • reproxy.enabled - 启用(yes、true、1)或禁用(no、false、0)容器作为 reproxy 目标。