How to export repositories with the git-daemon

Git is probably the most used version control software in the world. Free and open source, it was created by Linus Torvalds, and it is the base of services provided by web platforms like Github and Gitlab. In a previous article we discussed the git workflow basics,

In this tutorial we see how to quickly export a git repository using the git-daemon.

In this tutorial you will learn:

  • How to install the git daemon
  • How to export a repository via the git daemon
  • How to create a systemd service for the git daemon
  • How to allow unauthenticated users to push changes to a repository
article-main
How to export a repository with the git-daemon

Software requirements and conventions used

Software Requirements and Linux Command Line Conventions
Category Requirements, Conventions or Software Version Used
System Distribution-independent
Software git-daemon
Other Root permissions
Conventions # – requires given linux-commands to be executed with root privileges either directly as a root user or by use of sudo command
$ – requires given linux-commands to be executed as a regular non-privileged user

Introducing the git-daemon

As stated in the official documentation, the Git daemon is a very simple daemon which by default listens on the TCP port 9418. The daemon provides no authentication nor encryption, since it is meant as a quick way of distributing source code tracked in git repositories in trusted environments, such as Local Area Networks (LAN). By default the service allows only clone and pull actions, and forbids anonymous push actions, but this behavior can be easily modified (dangerous!).

Installation

Installing the git-daemon is a fairly easy process, since in a way or another, it is included in the repositories of all the most used Linux distributions. On Debian and Archlinux, for example, all we have to do is to install the standard git package, since git-daemon is included in it (it gets installed as /usr/lib/git-core/git-daemon). To install the git package on Debian we run the following command:

$ sudo apt install git

To perform the installation on Arch, instead, we can use pacman:

$ sudo pacman -Sy git



On Fedora things are a little bit different, since the git-daemon package needs to be installed explicitly, since the daemon functionalities are not included in the base git package. We fire up our favorite terminal emulator and issue the following command:

$ sudo dnf install git-daemon

Allowing traffic through the firewall

As we already mentioned, the git daemon listens on TCP port 9418, therefore if we are using a firewall on our system, we need to allow traffic through it. How to do it, depends on what firewall-management software we are using.

Typically, on Debian and Debian-based distributions ufw (Uncomplicated Firewall) is the default choice. Here is the command we need to run to allow traffic trough the aforementioned port:

$ sudo ufw allow 9418/tcp

The command above will allow traffic trough the port from any IP. In case we want to allow access to the port from a specific address or network only, we have to use a slightly different syntax. Supposing we want to allow traffic only from the 192.168.0.0/24, we would run:

$ sudo ufw allow from 192.168.0.0/24 to any proto tcp port 9418



On Fedora, and more generally on the Red Hat family of distribution, instead, firewalld is used as the default firewall manager. We talked about this software in a previous tutorial, so take a look at it if you want to grasp the basics. Here we will just remind the fact this firewall manager creates a series of zones, which can be differently configured. We can modify firewalld settings via the firewall-cmd utility. To permanently allow traffic through the port used by the git-daemon on the default zone, we can run the following command:

$ sudo firewall-cmd --permanent --add-port 9418/tcp

To restrict access to the port from a specific source, we need to use what is called a rich rule. Here is the command we would run:

$ sudo firewall-cmd --permanent --add-rich-rule 'rule family="ipv4" port port="9418" protocol="tcp" source address="192.168.0.0/24" accept'

With the rich rule above, we allow access to the port 9418/tcp from the 192.168.0.0/24 subnet. In both cases, since we used the --permanent option, for the rule to become effective, we need to reload the firewall configuration:

$ sudo firewall-cmd --reload

Without further specifications a rule is added to the default zone. To add the rule to a specific zone, we have to add the --zone option to the commands above, and provide the name of the zone as argument. Just as an example, to add the first rule we discussed in this example to the “public” zone explicitly, we would run:

$ sudo firewall-cmd --permanent --zone=public --add-port 9418/tcp

Starting the git daemon

Once we installed the needed packages and we configured the firewall appropriately, we can see how to use and start the git daemon. First of all, we want to create a repository to be exported. For the sake of this example we will create the /srv/git directory and initialize an empty bare repository called “linuxconfig” in it:

$ sudo mkdir /srv/git && sudo git init --bare linuxconfig.git

How can we export the repository using the git-daemon? To allow a repository to be exported using the git daemon we must create the git-daemon-export-ok file inside of it:

$ sudo touch /srv/git/linuxconfig.git/git-daemon-export-ok

With the file in place, we can launch the git-daemon:

$ git daemon --base-path=/srv/git

In the command above we invoked git with the “daemon” command, and used the --base-path option, why? When this option is used, all requests are remapped relatively to path given as argument, which is used as the base directory. In our case, to clone the “linuxconfig” repository, we can simply specify the IP of the machine on which the git daemon is running, and the repository name instead of its full path. Supposing the server IP to be 192.168.0.35, we would run:

$ git clone git://192.168.0.35/linuxconfig

If we want to export all the repositories inside a certain directory, instead of creating a git-daemon-export-ok inside each one of them, we can use the --export-all option when invoking the daemon:

$ git daemon --base-path=/srv/git --export-all

Starting the daemon automatically

In the previous example we started the git-daemon interactively, from the command line. If we want the daemon to be started automatically on boot we need to create a dedicated systemd service file.

Actually, on Fedora, such a configuration is included in the git-daemon package, so to start the daemon and enable it at boot, we can simply run:

$ sudo systemctl enable --now git.socket



You can notice that in this case the service is activated by using a systemd “.socket” unit: services implemented this way can be activate “on demand”, so when a request is actually received. The git.socket unit is associated with the git@.service file, which actually starts the service. On Fedora, the daemon runs as the nobody user.

On Debian and Arch we must create the service file from scratch. It is actually a pretty easy task. Before starting to create the file, however, we need to decide the user the service should run as. On Linux systems, the nobody user, is the absolute opposite of the root one, in the sense that it is meant to have the least possible privileges, and owns no files or directories. Traditionally some services were set to run as this user, so with its privileges, but is now common practice to create a specific user for each daemon that doesn’t need to run as root. Just as an example, in this case, we will create a dedicated “git” user with the useradd command:

$ sudo useradd --home-dir /srv/git --system --shell /usr/sbin/nologin git

With the command above we created the “git” user and set the /srv/git directory as its home. This is the directory we will use as a base to serve git repositories with the git-daemon. With the --system option we specified that the user should be created as a system user, and with --shell we assigned the user shell. In this case, since we don’t want the user to actually be able to login into the system for security reasons, we passed /usr/sbin/nologin as argument to the option.

With our favorite text editor we can now create the /etc/systemd/git.service file (the name is arbitrary, you can call it however you want). Here is its content:

[Unit]
Description=Start Git Daemon

[Service]
User=git
Group=git
ExecStart=/usr/bin/git daemon --reuseaddr --base-path=/srv/git --export-all --informative-errors --verbose
StandardError=journal

[Install]
WantedBy=multi-user.target

Here you can notice we start the git daemon with some options we didn’t use before:  --reuseaddr, --informative-errors and --verbose. The first allows the server to restart without waiting for old connections to timeout, the second makes so that informative errors are reported to clients, and finally, the third, is used to make the server log details about connections and requested files.

Once the service file is in place we can enable the service at boot and start it immediately with just one command:

$ sudo systemctl enable --now git.service

The git repositories in the /srv/git directory should now be served using the git daemon. Notice that the since the directory is used as the base path, it should exist, otherwise the service will fail.

Allowing unauthenticated users to push changes to the repository

As we said, by default, git-daemon works only in “read” mode, in the sense that it allows unauthenticated users only to clone a repository and pull from it. If we are aware of the risks, and we are really sure we want to allow unauthenticated users to commit and push changes to the repository shared via the git daemon, we have to enable the git receive-pack. We can do this via the --enable option we launch the daemon:

$ git daemon --reuseaddr --base-path=/srv/git --export-all --informative-errors --verbose --enable=receive-pack

Closing thoughts

In this tutorial we learned how to use the git daemon to distribute git repositories. We saw how to install it, how to configure the firewall to allow traffic thought the port used by the service, how to create a systemd service file to start the daemon automatically at boot, and finally, how to allow unauthenticated users to push changes to a repository accessed with this method. The git daemon should be used only in absolutely trusted environments, since it provides no authentication nor encryption.