My thoughts on Slackware, life and everything

Tag: apache

Fixing the cgit configuration of git.slackware.nl

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.

Alien Tip: protected apache URL

I run a apache webserver at home which is accessible on the local LAN as well as on the internet, In order to make an internal server visible on the Internet, I use port-forwarding on my cable router: incoming http requests are forwarded to my web server.

The issue is that I want to shield some private pages from public access. Outside the local LAN, I want these pages to be password protected. At the same time, I want these pages to have no restrictions when I access them from another computer on the LAN at home.

This is how I did that:

In apache’s configuration file (/etc/httpd/httpd.conf) you can limit page access by based on the validity of one of multiple options. In my case:

  • you are allowed direct access based on a hostmask/IP address, or if that condition is not satisfied,
  • you have to enter a valid username/password.

You achieve this by adding  something like this inside a <Directory></Directory> or <Location></Location> block where you define the behaviour of a web page:

require valid-user
Allow from .myhome.lan
Satisfy any

What I assumed here was that your home computers all have hostnames which end on “.myhome.lan“. If the apache webserver receives a page request from one of your computers, you will automatically get access to your protected URL. If your computer hostname does not end on “.myhome.lan” (for instance when you access the webserver from a computer on the internet), the second pre-condition will be checked by the apache webserver. A login form will be presented to you and you will have to enter your credentials. If apache decides that your credentials are that of a “valid user” then you will get access to the page.

If your network at home does not use domain names for the computers (the “.myhome.lan” is the domain name used in the above example) then the above line “Allow from .myhome.lan” will not work. Fortunately, you can use (partial) IP address as well, so that the example would become:

require valid-user
Allow from 192.168
Satisfy any

which would give full access to any computer with an IP address in the range 192.168.0.0/16 .

For more information about protecting your web pages:

More tips will probably follow. I have a lot of these useful snippets for which a whole Wiki page is just too much.

Cheers, Eric

© 2026 Alien Pastures

Theme by Anders NorenUp ↑