Envoy
在 Envoy 后部署 RustFS,用 TLS 终结的独立路由分别转发 S3 API 与 Console。
使用 Envoy 终结 TLS,并把独立主机名分别路由到 RustFS 的 S3 API 与 Console。本部署在同一个 Docker 网络上运行 Envoy 和单节点 RustFS。你需要 Docker Engine、两条 DNS 记录,以及一张覆盖两个主机名的 TLS 证书(本指南测试环境使用自签证书)。
本指南使用以下示例主机名:
s3.example.com对应 S3 APIconsole.example.com对应 Console
请替换为解析到 Docker 主机的主机名。
Serve S3 from the root path
不要把 S3 API 发布在 /s3/ 之类的路径下。AWS Signature Version 4 的签名包含请求路径与主机,改写其中任何一个都会导致签名失效。Envoy 原样转发传入的 Host 头,签名因此保持有效。
创建部署目录
为 Envoy 配置与 TLS 证书创建目录:
mkdir -p rustfs-envoy/certs
cd rustfs-envoy本地测试可以生成覆盖两个主机名的自签证书:
openssl req -x509 -newkey rsa:2048 -nodes \
-keyout certs/privkey.pem -out certs/fullchain.pem -days 30 \
-subj "/CN=*.example.com" \
-addext "subjectAltName=DNS:s3.example.com,DNS:console.example.com"
chmod 644 certs/privkey.pemEnvoy 镜像以非 root 用户运行,证书必须可读——600 的私钥会产生误导性的 Failed to load incomplete private key 报错。
配置 Envoy
创建带 HTTPS 监听器和两个虚拟主机的配置。路由超时设为 timeout: 0s(禁用),避免长时间的流式 S3 上传被中断:
static_resources:
listeners:
- name: https
address: {socket_address: {address: 0.0.0.0, port_value: 8443}}
filter_chains:
- transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
common_tls_context:
tls_certificates:
- certificate_chain: {filename: /certs/fullchain.pem}
private_key: {filename: /certs/privkey.pem}
filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: rustfs_https
route_config:
virtual_hosts:
- name: s3
domains: ["s3.example.com", "s3.example.com:*"]
routes:
- match: {prefix: "/"}
route: {cluster: rustfs_s3, timeout: 0s}
- name: console
domains: ["console.example.com", "console.example.com:*"]
routes:
- match: {prefix: "/"}
route: {cluster: rustfs_console, timeout: 0s}
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: rustfs_s3
connect_timeout: 5s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: rustfs_s3
endpoints:
- lb_endpoints:
- endpoint: {address: {socket_address: {address: rustfs, port_value: 9000}}}
- name: rustfs_console
connect_timeout: 5s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: rustfs_console
endpoints:
- lb_endpoints:
- endpoint: {address: {socket_address: {address: rustfs, port_value: 9001}}}host:* 形式的 domain 条目很重要:客户端在非标准端口上发送的是 Host: s3.example.com:8443,Envoy 按 authority 匹配时包含端口。
启动 Envoy
在与 RustFS 相同的 Docker 网络上运行 Envoy,只发布代理端口:
docker run -d --name envoy --network oo-rustfs_default -p 8443:8443 \
-v "$PWD/envoy.yaml":/envoy.yaml:ro \
-v "$PWD/certs":/certs:ro \
envoyproxy/envoy:v1.34-latest -c /envoy.yaml验证两个端点
用 curl --resolve 把示例主机名指向代理(生产环境由 DNS 完成):
curl -sk --resolve s3.example.com:8443:127.0.0.1 \
https://s3.example.com:8443/health/ready -o /dev/null -w "s3 api: %{http_code}\n"
curl -sk --resolve console.example.com:8443:127.0.0.1 \
https://console.example.com:8443/rustfs/console/ -o /dev/null -w "console: %{http_code}\n"s3 api: 200
console: 200-k 跳过证书校验,因为这里是自签证书;使用受信任的证书后去掉该参数即可。
通过 Envoy 发送签名 S3 请求
把任意 S3 客户端的端点指向代理即可,如同指向 RustFS。将客户端配置为 https://s3.example.com:8443 并启用路径风格寻址;代理证书受信任时,签名后的 AWS Signature Version 4 请求原样透传。要在纯 HTTP 上快速测试,可以增加一个与 HTTPS 监听器共享相同虚拟主机路由的 HTTP 监听器(端口 8080),然后使用以下端点:http://s3.example.com:8080
rc alias set rustfs-envoy http://s3.example.com:8080 <your-access-key> <your-secret-key>
rc ls rustfs-envoy/rclone-demo/[ ] 0B seed/
[2026-09-29 11:12:41] 5 B write-test.txt由于 Envoy 原样转发 Host 头,签名可以在 RustFS 侧通过校验。
多节点后端
分布式 RustFS 部署时,把每个节点加入 S3 cluster:
- name: rustfs_s3
connect_timeout: 5s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: rustfs_s3
endpoints:
- lb_endpoints:
- endpoint: {address: {socket_address: {address: node1, port_value: 9000}}}
- lb_endpoints:
- endpoint: {address: {socket_address: {address: node2, port_value: 9000}}}
- lb_endpoints:
- endpoint: {address: {socket_address: {address: node3, port_value: 9000}}}
- lb_endpoints:
- endpoint: {address: {socket_address: {address: node4, port_value: 9000}}}Console cluster 按相同模式使用 9001 端口。
故障排查
Failed to load incomplete private key from path
Envoy 容器以非 root 用户运行,读不了 600 且属主为 root 的私钥。执行 chmod 644(或把属主改为容器用户,官方镜像中为 UID 1001)。
主机名正确但路由返回 404
Envoy 按 authority(含端口)匹配。如上文配置所示,在每个虚拟主机的 domains 里加入 host:* 变体。
经代理访问 RustFS 返回 Access Denied
确认代理没有改写路径或 Host 头。签名请求必须以客户端签名时的主机名到达 RustFS。