我的问题是关于使用Nginx作为另一个代理的代理。 (有点混淆)
我想设置Nginx,所以它作为一个npm镜像caching代理服务器。 这里是链接: http : //eng.yammer.com/a-private-npm-cache/
在不受防火墙限制的本地机器上,以下configuration工作正常:
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环境variables。 在阅读文档后,我仍然不知道如何修改configuration,以便它可以在内部使用代理。
这两种解决scheme可以结合吗? caching仍然有效是非常重要的,否则,您可以直接使用外部镜像registry.npmjs.org。
也许,Nginx应该使用内部代理(proxy.abc.lan)作为proxy_pass ,但是内部代理怎么知道这个请求应该被发送到外部npm mirror( http://registry.npmjs.org )?
更新到Lukas的答案
我试过卢卡斯解决scheme:
rewrite ^(.*)$ "http://registry.npmjs.org$1" break; proxy_pass http://proxy.abc.lan:1234;
日志显示URL被重写,但是会导致redirect(由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调用的结果不是来自http://registry.npmjs.org的预期的JSONstring,而是由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>
Lukas的解决scheme的问题是HttpRewriteModule ,它会自动将前面的http(s)变成302。
如果你在两个阶段重写 – 第二个是“rest” – 它应该工作。 例如
rewrite ^(.*)$ "://registry.npmjs.org$1" break; rewrite ^(.*)$ "http$1" break; proxy_pass http://proxy.abc.lan:1234;
我怀疑有一个更好的方法来做到这一点,但似乎工作。
RFC 2616,第5.1.2节
向代理发出请求时,必须填写absoluteURI表单。
[…]
示例请求行将是: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指令构build它。
我想这可能比上述任何一个例子都要简单。 他们正在使用重写来重写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; } }