我在服务器上安装了 mercurial web-frontend (hgwebdir.cgi),并按照朋友的建议在它前面安装了 nginx 作为 web-frontend 的反向代理。但是,每当推送大型变更集(通过脚本)时,它都会失败。我找到了一个问题单@google-代码描述了类似的问题,并且有一个解决方案说(#39)
因此,服务器端的答案是:不要过早地发回 401。像“hg serve”一样慢/笨,并让 hg 客户端发送两次包。
我该怎么做?我当前的 nginx 配置
location /repo/testdomain.com {
rewrite ^(.*) http://bpj.kkr.gov.my$1/hgwebdir.cgi;
}
location /repo/testdomain.com/ {
rewrite ^(.*) http://bpj.kkr.gov.my$1hgwebdir.cgi;
}
location /repo/testdomain.com/hgwebdir.cgi {
proxy_pass http://localhost:81/repo/testdomain.com/hgwebdir.cgi;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_buffering on;
client_max_body_size 4096M;
proxy_read_timeout 30000;
proxy_send_timeout 30000;
}
从访问日志中我们不断看到 408 条条目
incoming.ip.address - - [18/Nov/2009:08:29:31 +0800] "POST /repo/testdomain.com/hgwebdir.cgi/example_repository?cmd=unbundle&heads=73121b2b6159afc47cc3a028060902883d5b1e74 HTTP/1.1" 408 0 "-" "mercurial/proto-1.0"
incoming.ip.address - - [18/Nov/2009:08:37:14 +0800] "POST /repo/testdomain.com/hgwebdir.cgi/example_repository?cmd=unbundle&heads=73121b2b6159afc47cc3a028060902883d5b1e74 HTTP/1.1" 408 0 "-" "mercurial/proto-1.0"
我还可以在服务器上做什么吗?因为最好在服务器端解决它:/
进一步的发现
Bitbucket 似乎已经在服务器端解决了这个问题(检查 liquidhg bitbucket 项目和诊断 wiki 页面),但是在任何地方都找不到配置 :/
- 接下来发生的情况取决于您的服务器。有些服务器拒绝 BODY,只是关闭来自客户端的管道并导致 Mercurial 失败。有些服务器,如 Apache(至少是我配置的方式,这可能是问题的一部分)和 nginx(BitBucket.org 配置的方式),接受 BODY,尽管可能需要重试几次。底线:如果 Mercurial 没有使推送失败,它会将变更集数据至少发送一次到已经告诉它缺少凭据的服务器(有关此内容的更多信息,请参阅 Blame)。
- 假设 Mercurial 仍在运行,它会重新发送“解除捆绑”请求和数据,这次带有身份验证。
- 最后,Apache 成功接受了数据。另一方面,Nginx 至少在 BitBucket 的配置下似乎重新组合了之前的主体(缺少身份验证的主体),并以某种方式阻止 Mercurial 重新发送整个主体。
答案1
我花了很长时间尝试让 hgwebdir 与 nginx 协同工作,但这有点麻烦,因为 hgwebdir 不会将请求发送到浏览器进行身份验证。最后我这样解决了它:
server {
listen 80;
listen 10240;
server_name code.zofrex.com;
access_log /home/zofrex/websites/code.zofrex.com/logs/access.log;
error_log /home/zofrex/websites/code.zofrex.com/logs/errors.log;
location / {
limit_except GET {
proxy_pass http://localhost:81;
}
fastcgi_pass 127.0.0.1:10001;
include fastcgi_params;
}
location ~ ^/(HGBot|ZeroBotAHD|zoebot|FZeroZBot|RDPrototype|RSPS3000|zerobot|rmi) {
proxy_pass http://localhost:81;
}
include defaults;
}
server {
listen 81;
access_log /home/zofrex/websites/code.zofrex.com/logs/access_secure.log;
error_log /home/zofrex/websites/code.zofrex.com/logs/errors_secure.log;
location / {
auth_basic "Restricted";
auth_basic_user_file /home/zofrex/passwords;
fastcgi_pass 127.0.0.1:10001;
include fastcgi_params;
}
include defaults;
}
这确实是你能做到的唯一方法,因为 limit_except 不能与 fastcgi_pass 结合使用 - 事实上没有条件可以,但它们可以与 proxy_pass 结合使用。不知道为什么。
那么它是如何工作的呢?如果收到 GET 请求,它会立即传递给 hgwebdir。如果收到 POST(即推送),请求会上传到端口 81 上的代理,然后总是提示基本身份验证,从而确保它发生。
为什么位置带有巨大的正则表达式? 这些都是受保护的项目,我希望即使是读取访问也需要身份验证。
为什么要监听 10240 端口?我不记得为什么会有这个端口。
哦,我使用的是 wsgi 和 spawn-fcgi,这就是为什么它是 fastcgi_pass。这个确切的配置可能不适合您,但希望同样的技巧可以解决您的推送问题。
答案2
问题是 httplib 是半双工的,响应后主动关闭套接字的服务器(其中包括 nginx)会导致 httplib 写入损坏的管道。1.4 版中有一个临时解决方法,但它并没有真正加快速度,只是不太可能完全崩溃。我不知道如何配置 nginx 来做你想做的事情,但我知道在足够大的推送时 BitBucket 也存在同样的问题。
您使用的是哪个版本的 Apache 和 nginx?这可能是我拥有更“完整”测试设置的好方法。
您使用什么进行身份验证?Apache 二进制文件中的某个东西?可能是 Apache 在身份验证失败后关闭大门太快了。
此外,FWIW,liquidhg 是 Brad Olson 的杰作,仅托管在 BitBucket 上。只是想给予应有的赞扬。
答案3
我最近遇到了类似的问题,但拒绝尝试listen 81
解决方法。我想出了这个。我认为我们遇到了类似的问题,请在此处查看我的问题/答案:Nginx 不会将 POST 发送到 FastCGI 后端,但 GET 可以正常工作?
答案4
为什么不简单地这样做:
server {
listen 80;
listen 10240;
server_name code.zofrex.com;
access_log /home/zofrex/websites/code.zofrex.com/logs/access.log;
error_log /home/zofrex/websites/code.zofrex.com/logs/errors.log;
location / {
fastcgi_pass 127.0.0.1:10001;
include fastcgi_params;
limit_except GET HEAD {
auth_basic "Restricted";
auth_basic_user_file /home/zofrex/passwords;
}
}
location ~ ^/(HGBot|ZeroBotAHD|zoebot|FZeroZBot|RDPrototype|RSPS3000|zerobot|rmi) {
auth_basic "Restricted";
auth_basic_user_file /home/zofrex/passwords;
}
include defaults;
}
它从 nginx 0.8.48 开始起作用,在旧版本中存在一个fastcgi_pass
未在 limit_except 块内继承的错误。