In an earlier article here on the blog, I documented how I have setup cgit to create a browseable web interface to my git repositories, most notably git.liveslak.org and git.slackware.nl.
That configuration has worked just fine for years, and you could clone a branch of a repository using the “https://” git URI and that works.
However…
Cgit is a nice graphical shell around git repositories, but it does not serve the actual git protocol.
I found out when I tried to setup a mirror of the “current” repository on the Slackware Forge. For that, I needed to perform a full clone including all branches and tags. That failed mysteriously with the error:
$ git clone https://git.slackware.nl/current Cloning into 'current'... error: Unable to find d8220d28e5d53cd896b28d9dea13e2258923f35a under https://git.slackware.nl/current Cannot obtain needed object d8220d28e5d53cd896b28d9dea13e2258923f35a while processing commit 897670f2f2e1795652dfa3da21f9879d04a9b8dc. error: fetch failed.
At first I thought that the remote repository was damaged or corrupted,but that was ruled out by searching for the hash to see if it would actually return something else than an error. From within the bare git repositorty on the server:
# git cat-file -t d8220d28e5d53cd896b28d9dea13e2258923f35a commit
The hash does exist and it is a commit. That rules out the corruption.
Examining those errors “unable to find under ” and “cannot obtain needed object … while processing commit …” the conclusion is that the webserver only serves the bare repository as static files over plain HTTP, with no git-http-backend smart protocol behind it.
A working “git clone” over https needs the git-http-backend configured alongside the cgit configuration in Apache. Since that backend runs as the webserver user “apache”, and the git repositories are owned by user “git”, we need to deal with file permissions/ownership and what git considers “safe directories”. Modern git (2.35.2 and later) refuses to operate on a repository owned by a different user than the one running git, and aborts with:
fatal: detected dubious ownership in repository at '/the/path/to/current'
The final configuration that adds the “git-http-backend” protocol to the Apache webserver and also resolves the “dubious ownership” error comes in two parts.
First:
A global git configuration directive which will only be used by the Apache user so that it won’t trip over the “git” user-owned repository files.
Create the file “/etc/httpd/http-git-config” and add these lines to it:
# ---
[safe]
directory = *
# ---
Second:
Adding a code block to the VHost definition of the git server. In my previous article I described the git.liveslak.org configuration but actually this is identical to that for git.slackware.nl.
Therefore, to the file “/etc/httpd/extra/git.slackware.nl_content.conf” we add the following right before the “SetEnv CGIT_CONFIG” line:
# ---- smart HTTP for git clients (git-http-backend) ---- # Root directory that contains the bare repositories (current.git, etc.). SetEnv GIT_PROJECT_ROOT /local/path/to/git/repositories # Apache trips over the git:git ownership of the repositories, so we # need to tell git that for Apache, all repositories should be considered # as having safe ownership: SetEnv GIT_CONFIG_GLOBAL /etc/httpd/http-git-config # Route ONLY the git protocol paths to git-http-backend. Everything else # (the cgit pretty URLs) is left untouched and handled by cgit below. # The character classes accept both SHA-1 (40 hex) and SHA-256 (64 hex) # object names, so this keeps working When we ever migrate hash formats. # This MUST appear before the cgit ScriptAlias in the vhost. ScriptAliasMatch \ "(?x)^/(.*/(HEAD | \ info/refs | \ objects/(info/[^/]+ | \ [0-9a-f]{2}/[0-9a-f]{38,62} | \ pack/pack-[0-9a-f]{40,64}\.(pack|idx)) | \ git-(upload|receive)-pack))$" \ /usr/libexec/git-core/git-http-backend/$1 <Directory "/usr/libexec/git-core"> Options +ExecCGI Require all granted </Directory> # -------------------------------------------------------
Test the Apache configuration for errors after saving your changes:
# apachectl configtest
And reload the webserver gracefully (not aborting current connections):
# apachectl -k graceful
Now, let’s test the server response when we send it a request:
$ curl -sI "https://git.slackware.nl/info/refs?service=git-upload-pack" | grep -Ei 'HTTP/|Content-Type' HTTP/1.1 200 OK Content-Type: application/x-git-upload-pack-advertisement
The content-type of “application/x-git-upload-pack-advertisement” instead of something like “text/plain” or “octet-stream” means that we have a properly working HTTP backend for git now. Cloning the repository no longer returns an error:
$ git clone https://git.slackware.nl/current Cloning into 'current'... remote: Enumerating objects: 103427, done. remote: Counting objects: 100% (103427/103427), done. remote: Compressing objects: 100% (31583/31583), done. remote: Total 103427 (delta 69643), reused 103103 (delta 69319), pack-reused 0 (from 0) Receiving objects: 100% (103427/103427), 759.01 MiB | 69.60 MiB/s, done. Resolving deltas: 100% (69643/69643), done.
This fix allowed me to mirror https://git.slackware.nl/current/ to https://forge.slackware.nl/slackware/distrodevelopment with a sync frequency of 1 hour.

Recent comments