uWSGI + nginx + git-http-backend

2019-05-20 04:29发布

问题:

I have a problem to establish connection to git-http-backend on nginx with uwsgi. I can clone the repo but couldn't push anything because this:

17:20:58.877539 git.c:344               trace: built-in: git push -v
17:20:58.877648 run-command.c:640       trace: run_command: 
GIT_DIR=.git git-remote-http origin http://example.com/test.git
Pushing to http://example.com/test.git
* Couldn't find host example.com in the .netrc file; using defaults
*   Trying 192.168.0.120...
* TCP_NODELAY set
* Connected to example.com (192.168.0.120) port 80 (#0)
> GET /test.git/info/refs?service=git-receive-pack HTTP/1.1
Host: example.com
User-Agent: git/2.17.0
Accept: */*
Accept-Encoding: gzip
Accept-Language: pl, en-US;q=0.9, *;q=0.8
Pragma: no-cache

< HTTP/1.1 301 Moved Permanently
< Server: nginx
< Date: Thu, 19 Apr 2018 15:20:58 GMT
< Content-Type: text/html
< Content-Length: 178
< Location: https://example.com/test.git/info/refs?service=git-receive-pack
< 
* Ignoring the response-body
* Connection #0 to host example.com left intact
* Issue another request to this URL: 'https://example.com/test.git/info/refs?service=git-receive-pack'
* Couldn't find host example.com in the .netrc file; using defaults
*   Trying 192.168.0.120...
* TCP_NODELAY set
* Connected to example.com (192.168.0.120) port 443 (#1)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
  CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
*  subject: CN=example.com
*  start date: Apr 16 11:50:53 2018 GMT
*  expire date: Jul 15 11:50:53 2018 GMT
*  subjectAltName: host "example.com" matched cert's "example.com"
*  issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
*  SSL certificate verify ok.
> GET /test.git/info/refs?service=git-receive-pack HTTP/1.1
Host: example.com
User-Agent: git/2.17.0
Accept: */*
Accept-Encoding: gzip
Accept-Language: pl, en-US;q=0.9, *;q=0.8
Pragma: no-cache

< HTTP/1.1 401 Unauthorized
< Server: nginx
< Date: Thu, 19 Apr 2018 15:20:58 GMT
< Content-Type: text/html; charset=utf-8
< Content-Length: 188
< Connection: keep-alive
< WWW-Authenticate: Basic realm="name"
< 
* Connection #1 to host example.com left intact
* Couldn't find host example.com in the .netrc file; using defaults
* Found bundle for host example.com: 0x56415ea02740 [can pipeline]
* Re-using existing connection! (#1) with host example.com
* Connected to example.com (192.168.0.120) port 443 (#1)
* Server auth using Basic with user 'user'
> GET /test.git/info/refs?service=git-receive-pack HTTP/1.1
Host: example.com
Authorization: Basic c290ZWs6Z2l0cHNvasdHRlaw==
User-Agent: git/2.17.0
Accept: */*
Accept-Encoding: gzip
Accept-Language: pl, en-US;q=0.9, *;q=0.8
Pragma: no-cache

< HTTP/1.1 200 OK
< Server: nginx
< Date: Thu, 19 Apr 2018 15:21:06 GMT
< Content-Type: application/octet-stream
< Content-Length: 0
< Last-Modified: Wed, 18 Apr 2018 19:11:48 GMT
< Connection: keep-alive
< ETag: "5ad79874-0"
< Accept-Ranges: bytes
< 
* Connection #1 to host example.com left intact
warning: redirecting to https://example.com/test.git/
* Couldn't find host example.com in the .netrc file; using defaults
* Found bundle for host example.com: 0x56415ea02740 [can pipeline]
* Re-using existing connection! (#1) with host example.com
* Connected to example.com (192.168.0.120) port 443 (#1)
* Server auth using Basic with user 'user'
> GET /test.git/HEAD HTTP/1.1
Host: example.com
Authorization: Basic c290ZWs6Z2l0cHNvasdHRlaw==
User-Agent: git/2.17.0
Accept: */*
Accept-Encoding: gzip
Accept-Language: pl, en-US;q=0.9, *;q=0.8
Pragma: no-cache

< HTTP/1.1 200 OK
< Server: nginx
< Date: Thu, 19 Apr 2018 15:21:06 GMT
< Content-Type: application/octet-stream
< Content-Length: 23
< Last-Modified: Wed, 18 Apr 2018 18:43:32 GMT
< Connection: keep-alive
< ETag: "5ad791d4-17"
< Accept-Ranges: bytes
< 
* Connection #1 to host example.com left intact
17:21:06.316813 run-command.c:640       trace: run_command: git http-push --helper-status --verbose https://example.com/test.git/ refs/heads/master:refs/heads/master
17:21:06.318781 git.c:576               trace: exec: git-http-push --helper-status --verbose https://example.com/test.git/ refs/heads/master:refs/heads/master
17:21:06.318828 run-command.c:640       trace: run_command: git-http-push --helper-status --verbose https://example.com/test.git/ refs/heads/master:refs/heads/master
* Couldn't find host example.com in the .netrc file; using defaults
*   Trying 192.168.0.120...
* TCP_NODELAY set
* Connected to example.com (192.168.0.120) port 443 (#0)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
  CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
*  subject: CN=example.com
*  start date: Apr 16 11:50:53 2018 GMT
*  expire date: Jul 15 11:50:53 2018 GMT
*  subjectAltName: host "example.com" matched cert's "example.com"
*  issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
*  SSL certificate verify ok.
> PROPFIND /test.git/ HTTP/1.1
Host: example.com
User-Agent: git/2.17.0
Accept: */*
Depth: 0
Content-Type: text/xml
Content-Length: 166
Expect: 100-continue

* The requested URL returned error: 401 Unauthorized
* stopped the pause stream!
* Closing connection 0
error: Cannot access URL https://example.com/test.git/, return code 22
fatal: git-http-push failed
error: failed to push some refs to 'http://example.com/test.git'

It looks that git-http-backend doesn't get working. This is nginx.conf:

server {
    listen 12080;
    server_name example.com;

    location /.well-known {
    root /etc/letsencrypt;
    try_files $uri $uri/ =404;
    }

    # enforce https
    location / {
    return 301 https://$server_name$request_uri;
    }

}

server {
    listen 12443 ssl http2;
    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;
    ssl_prefer_server_ciphers on;
    ssl_stapling on;
    ssl_stapling_verify on;

    root /mnt/raid/git;
#    should be
#    root / to gitlab

    access_log /var/log/nginx/example.com.access.log upstreamlog1;
    error_log /var/log/nginx/example.com.error.log;

    auth_basic "as";
    auth_basic_user_file /etc/nginx/htpasswd;

#    location / {
#        # First attempt to serve request as file, then
#        # as directory, then fall back to displaying a 404.
#        try_files $uri $uri/ =404;
#    }    

    # static repo files for cloning over https
    location ~ ^.*\.git/objects/([0-9a-f]+/[0-9a-f]+|pack/pack-[0-9a-f]+.(pack|idx))$ {
        root /mnt/raid/git/;
    }

    # requests that need to go to git-http-backend
    location ~ ^.*\.git/(HEAD|info/refs|objects/info/.*|git-(upload|receive)-pack)$ {
#    location ~ (/.*) {
        root /mnt/raid/git/;
        try_files $uri /@git;
    }

    location @git {
        gzip off;
        include uwsgi_params;

    # export all repositories under GIT_PROJECT_ROOT
#   uwsgi_param SCRIPT_FILENAME /usr/lib/git-core/git-http-backend;
        uwsgi_param GIT_HTTP_EXPORT_ALL "";
        uwsgi_param GIT_PROJECT_ROOT    /mnt/raid/git;
        uwsgi_param PATH_INFO           $1;
        # required for pushing to repo
#        uwsgi_param REMOTE_USER         $remote_user;
#        uwsgi_param AUTH_TYPE      Basic;
#   uwsgi_read_timeout 10;

        uwsgi_modifier1 9;
        uwsgi_pass unix:/run/uwsgi/git.sock;
    }
}

And the last one but not least the uwsgi.ini:

[uwsgi]
plugins = cgi
procname-master = uwsgi %n
master = true
socket = /run/uwsgi/%n.sock

uid = http
gid = http
chmod-socket = 664

processes = 4
cheaper = 1

touch-reload = %p

cgi = /usr/lib/git-core/git-http-backend
logto = /var/log/uwsgi/git-http-backend.log

Anybody have some suggestion what i can do to make push available and working with git-http-backend.

EDIT

I found the problem with code return 22. It was the try_files:

location ~ ^.*\.git/(HEAD|info/refs|objects/info/.*|git-(upload|receive)-pack)$ {
    root /mnt/raid/git/;
    try_files $uri /@git;
}

If I join this section with @git the git start works.

Unfortunately now I have the problem that after somebody clone the repo I can't clone it again. Worst I can't pull/fetch or sometimes push the change. The only info that I have is this:

fatal: The remote end hung up unexpectedly

and I believe is connected with some timeout of the POST. Do you now how to resolve POST timeout problem?

回答1:

To fix the hang-after-POST issue, you need to add cgi-close-stdin-on-eof = true to your uWSGI configuration. So your config would look something like this:

[uwsgi]
plugins = cgi
procname-master = uwsgi %n
master = true
socket = /run/uwsgi/%n.sock

uid = http
gid = http
chmod-socket = 664

processes = 4
cheaper = 1

touch-reload = %p

cgi = /usr/lib/git-core/git-http-backend
logto = /var/log/uwsgi/git-http-backend.log

# The new configuration option here:
cgi-close-stdin-on-eof = true

NOTE: This option is only available in uWSGI >= 2.0.13.

I first read about this fix in the comments of this blog post: https://www.burgundywall.com/post/nginx-uwsgi-supervisord-git