终端里 curl 能通,程序里请求超时:代理没吃到
终端里 curl 能通,程序里请求超时:代理没吃到
同一个容器,curl https://example.com 秒回,Python 脚本和 Go 程序全部超时。这种情况十有八九不是网络问题,是代理变量没传到进程里。
先分清三件事
shell 有变量,不代表子进程有。 export 过的东西在交互 shell 里能看见,但 systemd 服务、cron、docker exec 起的新进程,环境是干净的。查一下:
systemctl show myservice -p Environment
输出为空就是没传进去。
大小写不通用。 curl 认小写 http_proxy,Go 的 net/http 认大写 HTTP_PROXY,某些库只读其中一个。两边都写,省事。
变量名对了,协议也可能不对。 ALL_PROXY 写 socks5:// 的时候,Go 的 transport 默认不认,得显式配。
最隐蔽的一种:TLS 被中间人
企业出口代理通常会做 TLS 解密,用自己的 CA 重签证书。程序不信任这张 CA,握手就失败。但报错往往不是 unknown authority,而是:
tls: first record does not look like a TLS handshake
这句话的意思是"对端返回的第一段数据不是 TLS"。真实原因是被代理拦下来之后,回了一个明文的 HTTP 错误页(403 或者认证提示),客户端拿着这堆明文当 TLS 记录解析,自然对不上。
看到这个报错,不要去查证书链,先确认请求是不是被代理接管了:
curl -sv https://example.com 2>&1 | grep issuer
issuer: CN=xxx Egress CA 就是被解密了。
修法
对 systemd 服务,写 drop-in,别去改 /etc/environment:
[Service]
Environment=HTTPS_PROXY=http://proxy:3128
Environment=HTTP_PROXY=http://proxy:3128
Environment=NO_PROXY=localhost,127.0.0.1,::1,100.64.0.0/10
Environment=SSL_CERT_FILE=/etc/ssl/certs/combined.pem
combined.pem 是系统 CA 加代理 CA 拼起来的:
cat /etc/ssl/certs/ca-certificates.crt /path/to/egress-ca.pem > /etc/ssl/certs/combined.pem
只放代理 CA 会让其他域名的 TLS 全挂,因为系统根证书没了。
Go 程序还有个细节:SSL_CERT_FILE 只在 Linux 上生效,Windows 和 macOS 要看系统钥匙串。同一份代码换个平台就不认,别以为是代码问题。
怎么确认真的走通了
看日志里有没有这条:
CONNECT response from http://proxy:3128 for target "example.com:443": 200 Connection Established
有这一行,说明代理握手成功。没有的话,要么变量没生效,要么 NO_PROXY 把目标排除了。
排查顺序我一般按这个来:systemctl show 看变量 → curl -v 看 issuer → 看目标是不是在 NO_PROXY 里 → 最后才怀疑代理本身。
- 点赞
- 收藏
- 关注作者
评论(0)