Hướng Dẫn Sử Dụng
正确为 localhost 和内部 API 配置 NO_PROXY

目录
在企业环境中,应用通常需要通过代理访问互联网,以满足网络策略和流量管控要求。但是,连接 localhost、本机服务或内部 API 时,通常需要直接连接。如果不区分这些目标,请求可能会被意外转发到代理,导致连接错误或干扰服务之间的通信流程。
配置 NO_PROXY 可以为支持该机制的 HTTP 客户端指定不使用代理的地址。要正确配置,需要了解应用如何读取环境变量、如何匹配域名,以及 localhost 在不同部署环境中的含义。
NO_PROXY 如何工作?
NO_PROXY 是一个环境变量,其中包含要求 HTTP 客户端直接连接、而非使用已配置代理的目标列表。该列表通常由主机名、域名或 IP 地址组成,各项之间用逗号分隔。
一组常见的代理环境变量包括:
- HTTP_PROXY: 用于 HTTP 请求的代理地址,前提是客户端支持此变量。
- HTTPS_PROXY: 用于 HTTPS 请求的代理地址。
- NO_PROXY: 直接连接的目标列表。
发送请求时,客户端会根据生效的配置以及例外列表的匹配方式,决定是否使用代理。因此,NO_PROXY 并不是自动应用于整个操作系统的路由规则。它只对实现了相应机制的程序或库生效。
尤其需要注意,HTTPS_PROXY 并不一定要包含以 https:// 开头的 URL。对于支持 CONNECT 方法的 HTTP 代理,可以使用 http://proxy.corp.example:8080 这样的值处理 HTTPS 请求。URL 中的协议描述的是连接代理的方式,而不是目标网站的协议。
localhost 和内部 API 的基本配置
假设应用必须通过组织的代理访问互联网,同时调用本地服务以及位于 api.corp.example 的 API。在兼容 POSIX 的 shell 中,可以这样设置:
export HTTP_PROXY='http://proxy.corp.example:8080'
export HTTPS_PROXY='http://proxy.corp.example:8080'
export NO_PROXY='localhost,127.0.0.1,::1,api.corp.example'
示例中的地址和端口仅供说明,应替换为管理员提供的配置。设置完成后,请从同一个 shell 会话中启动应用,以便进程获取这些环境变量。
为 localhost 绕过代理需要配置哪些内容?
如果应用可能同时使用 localhost 名称、IPv4 回环地址和 IPv6 回环地址,建议列出 localhost、127.0.0.1 和 ::1。不要假设配置 localhost 就会自动涵盖所有发往回环地址的请求。
通常,匹配依据是 URL 中出现的主机名或地址,而不是 DNS 可能解析出的所有地址。因此,http://localhost 和 http://127.0.0.1 可能会得到不同处理。NO_PROXY 中的 IPv6 语法也需要使用实际客户端进行验证。
按适当范围配置内部 API
如果只有一个 API 需要直接连接,请先使用具体的主机名,例如 api.corp.example。如果同一内部域中的多个服务采用相同的连接策略,可以考虑按域名后缀设置例外。
一个常见示例是 NO_PROXY='localhost,127.0.0.1,::1,corp.example,.corp.example'。但是,各客户端对根域名和前导点号的解释并不一致。在大范围应用之前,需要验证 corp.example 以及 api.corp.example 等子域名的匹配情况。
需要验证的匹配规则
主机名不是完整 URL
在常规配置中,NO_PROXY 包含的是连接目标,不包含协议或路径。应使用 api.corp.example,而不是 https://api.corp.example/private。此变量并不是为各个 API 路径设置独立策略的工具。
如果需要按路径区分流量,请使用应用的路由功能或适当的网络组件。不应将 NO_PROXY 的含义扩展到客户端支持范围之外。
不要默认通配符始终受支持
不同库对 *.corp.example 语法的解释可能不同。某些客户端支持单独使用 *,表示直接连接所有目标,但这并不意味着它们支持域名中的通配符模式。
对于访问互联网时仍需使用代理的应用,不应设置 NO_PROXY='*'。对支持该值的客户端而言,它可能会使代理配置失效。
IP 地址、CIDR 和端口的支持取决于客户端
并非所有库都能识别 NO_PROXY 中采用 CIDR 表示法的网段。此外,支持 CIDR 并不意味着客户端会先解析所有主机名,再检查解析结果是否位于该网段内。
同样,主机名:端口 语法只对支持按端口匹配的客户端有意义。如果没有特殊需求,应优先使用具体的主机名或 IP,并在添加复杂规则之前验证其行为。
大小写与优先级
许多环境同时使用 HTTP_PROXY、HTTPS_PROXY、NO_PROXY 以及对应的小写变量。支持程度和优先级取决于具体程序,因此不存在适用于所有应用的统一规则。
为了减少工具之间的差异,可以在 shell 中同步这些变量:
export http_proxy="$HTTP_PROXY"
export https_proxy="$HTTPS_PROXY"
export no_proxy="$NO_PROXY"
不要让功能相同的两个变量具有相互冲突的值。 例如,NO_PROXY 包含内部 API,而 no_proxy 为空,可能导致不同客户端产生不同结果。
特别是 curl,出于与 CGI 环境相关的安全考虑,在通过环境变量配置 HTTP 代理时,只接受小写形式的 http_proxy。这个例子说明,应阅读所使用工具的文档,而不是仅依赖常见的变量名称。
在应用和容器中应用配置
以系统服务方式运行的应用
在终端中设置变量不会改变已运行服务的环境。使用服务管理器时,需要在服务的环境配置中设置变量,然后按照相应机制执行重新加载或重启操作。
请检查实际应用进程的环境。在终端中看到 NO_PROXY,只能证明当前 shell 会话具有该变量,并不能证明后台服务已经获取它。
容器和 Docker Compose
主机上的环境变量不会自动出现在所有容器中。需要通过部署配置机制,将 HTTP_PROXY、HTTPS_PROXY 和 NO_PROXY 传入容器的运行环境。
容器中的 localhost 指向该容器自身的网络命名空间。 如果 API 位于另一个容器中,应用通常需要通过服务名调用,例如 internal-api。此时,如果客户端正在使用代理,就需要将 internal-api 添加到例外列表中。
还需要区分镜像构建环境和应用运行环境。在构建阶段下载软件包时代理能够正常工作,并不能证明运行时的配置正确。
Kubernetes 集群
在 Kubernetes 中,应用可以通过短名称、带命名空间的名称或完整 DNS 名称访问服务。例外配置应准确反映应用实际使用的名称形式。
不应直接照搬其他集群的域名或网段列表。DNS 后缀和网络规划可能不同;同时,客户端也可能不支持所配置的语法。
HTTP 库之间的差异
即使环境层面的配置正确,如果应用使用自己的代理机制,配置仍可能不生效。处理内部 API 的代理问题时,应同时检查运行时和发送请求的库。
- Python Requests: 通常会从环境中读取代理配置。但是,session 配置或禁用 trust_env 可能改变这一行为。
- Go: 使用 http.ProxyFromEnvironment 的 transport 可以读取环境变量。自定义 transport 则可能不使用此机制。
- Node.js: 不应假设所有版本、库或 HTTP agent 都会自动读取同一组代理变量。需要检查实际发送请求的组件。
- Java: 许多应用使用 http.proxyHost 和 http.nonProxyHosts 等 JVM 属性,而不是直接依赖 NO_PROXY。例外列表的语法也有所不同。
如果应用在源代码中直接设置代理,请确认该配置是否仍会参考 NO_PROXY。显式代理选项可能改变例外处理机制。
NO_PROXY 配置验证流程
- 确认环境变量:在正确的容器、运行会话或相关进程中检查;分享结果时应遮蔽身份验证信息。
- 测试一个互联网目标:使用获准访问的端点,并通过日志或连接信息确认请求仍经过代理。
- 测试 localhost:使用应用实际采用的主机名和端口发起调用,然后检查是否直接连接。
- 测试内部 API:使用与应用相同的库和配置进行验证,而不只是使用命令行工具。
- 交叉核对证据:结合应用日志、代理日志,以及在获得授权的情况下对网络连接的观察进行确认。
可以使用 curl -v https://api.corp.example/health 观察连接过程。详细模式可能显示敏感数据,因此分享日志前需要检查并遮蔽相关信息。
收到成功响应并不足以证明请求是直接连接的。 反过来,直接连接失败也不一定是 NO_PROXY 导致的:原因可能在于 DNS、防火墙、路由或 TLS 证书。
常见错误与运维原则
常见错误包括变量名设置错误、使用 URL 代替主机名、忘记将变量传入容器、尚未重启服务,或调用 API 时使用了与配置不同的名称。HTTP 重定向到其他主机名,也可能使后续请求受不同的代理规则约束。
在安全方面,应将例外列表限制在必要范围内,不要将代理密码提交到代码仓库,也不要通过关闭 TLS 验证来解决连接错误。NO_PROXY 仅控制客户端的代理选择;它不会授予网络访问权限,也不能替代防火墙策略。
结论
要有效地配置 NO_PROXY,请先配置 localhost、所需的回环地址以及具体的内部 API 主机名。随后同步环境变量,检查库的支持情况,并确认请求的实际路径。这种方法可以让应用继续通过代理访问互联网,同时确保内部连接按设计运行。