我的问题是关于使用 Nginx 作为另一个代理后面的代理。 (有点令人困惑。)
我想设置 Nginx,使其充当 npm 镜像的缓存代理服务器。以下是链接: http://eng.yammer.com/a-private-npm-cache/
在我的本地机器上,没有受到防火墙的限制,以下配置可以正常工作:
proxy_cache_path /var/cache/npm/data levels=1:2 keys_zone=npm:20m max_size=1000m
inactive=365d;
proxy_temp_path /var/cache/npm/tmp;
server {
listen 80;
server_name classen.abc.lan;
location / {
proxy_pass http://registry.npmjs.org/;
proxy_cache npm;
proxy_cache_valid 200 302 365d;
proxy_cache_valid 404 1m;
sub_filter 'registry.npmjs.org' 'classen.abc.lan';
sub_filter_once off;
sub_filter_types application/json;
}
}
现在我想将它应用到位于附加防火墙后面的服务器上。在日志中,我可以确认它访问了正确的上游 IP,但由于内部防火墙,请求失败。
我们有一个内部代理,我可以使用它来绕过防火墙,例如:
$ curl http://registry.npmjs.org
curl: (7) couldn't connect to host
$ http_proxy=http://proxy.abc.lan:1234/ curl http://registry.npmjs.org
... succeeds ...
此技巧不适用于 Nginx,因为它忽略了http_proxy
环境变量。阅读文档后,我仍然无法弄清楚如何修改配置,以便它可以在内部使用代理。
可以将这两种解决方案结合起来吗?重要的是缓存仍然有效,否则,您可以直接使用外部镜像 registry.npmjs.org。
也许,Nginx 应该使用内部代理(proxy.abc.lan)proxy_pass
,但是内部代理如何知道应该将请求发送到外部 npm 镜像(http://registry.npmjs.org)?
更新 Lukas 的回答
我尝试了 Lukas 的解决方案:
rewrite ^(.*)$ "http://registry.npmjs.org$1" break;
proxy_pass http://proxy.abc.lan:1234;
日志显示 URL 被重写但导致重定向(由 触发curl classen.abc.lan/test-url
):
2014/03/24 11:31:16 [notice] 13827#0: *2 rewritten redirect: "http://registry.npmjs.org/test-url", client: 172.18.40.33, server: classen.abc.lan, request: "GET /test-url HTTP/1.1", host: "classen.abc.lan"
curl 调用的结果不是预期的 JSON 字符串http://registry.npmjs.org但是Nginx生成的html页面:
$ curl classen.abc.lan/test-url
<html>
<head><title>302 Found</title></head>
<body bgcolor="white">
<center><h1>302 Found</h1></center>
<hr><center>nginx/1.4.7</center>
</body>
</html>
答案1
Lukas 的解决方案存在以下问题HttpRewrite模块,它会自动将以 http(s) 开头的所有内容转换为 302。
如果你分两个阶段进行重写 - 第二阶段“中断” - 它应该可以工作。例如
rewrite ^(.*)$ "://registry.npmjs.org$1";
rewrite ^(.*)$ "http$1" break;
proxy_pass http://proxy.abc.lan:1234;
我认为有更好的方法可以做到这一点,但它似乎有效。
答案2
当向代理发出请求时,必须使用绝对 URI 形式。
[...]
请求行的示例如下:GET http://www.w3.org/pub/WWW/TheProject.html HTTP/1.1
因此,您应该做的是使用以下修改后的指令将请求传递给代理:
rewrite ^(.*)$ "http://registry.npmjs.org$1" break;
proxy_pass http://proxy.abc.lan:1234;
根据nginx 文档,使用rewrite ... break;
将强制 nginx 使用重写 URI(现在是协议要求的绝对 URI)而不是尝试从指令构建它proxy_pass
。
答案3
我认为它可能比上面的任何一个示例都简单。他们使用 rewrite 来重写 url,我认为您可以使用 proxy_pass,但将 url 传递给代理,将主机标头参数设置为您要去的位置。例如
http {
upstream corporate_proxy {
server web-proxy.mycorp.com:8080;
}
server {
listen 80;
server_name classen.abc.lan;
location / {
proxy_pass_header on;
proxy_set_header Host "registry.npmjs.org";
proxy_pass http://corporate_proxy;
proxy_cache npm;
proxy_cache_valid 200 302 365d;
proxy_cache_valid 404 1m;
sub_filter 'registry.npmjs.org' 'classen.abc.lan';
sub_filter_once off;
sub_filter_types application/json;
}
}