Serving a Git repository over HTTP
Tags: git, http, apache, ubuntu
Published: 2019-05-13 11:03:15

---
title: Serving a Git repository over HTTP
published: true
description: An easy step by step guide to serve a Git repository over HTTP
tags: git,http,apache,ubuntu
cover_image: https://thepracticaldev.s3.amazonaws.com/i/7kxlmyvaa9sc8ih8ilxi.png
---

A while ago, I was assigned the task of researching how to serve a Git repository over HTTP. The tutorials and documentations I've found were either messy or incomplete.

After a painful process, I got it to work. But, unfortunately a decision was made to use a different approach to serve the repo.

I didn't want to just throw the effort away. So, here's a blog post about it.


#The setup
We'll use [Apache](https://httpd.apache.org) web server to serve the repository, and we'll install it on an [Ubuntu 16.04.5](http://releases.ubuntu.com/16.04/) machine ([AWS EC2](https://aws.amazon.com/ec2/) instance in my case).


#Installation
Let's start by installing Git and Apache
```
sudo apt-get update
sudo apt-get install git-core
sudo apt-get install apache2
```


#Creating the repo
For this tutorial, we will create a new Git repository in the documents root (**/var/www/html**)
```
cd /var/www/html
mkdir git
cd git
mkdir reponame
cd reponame
git init --bare
chgrp -R www-data /var/www/html/git
chown -R www-data /var/www/html/git
```
If you want to allow other people to push to the repo, open the file named **config** which was added to the repository by Git and append the following to it
```
[http]
    receivepack = true
```


#Authentication
We only want authenticated users to access the repo. So, first we'll create a dummy bash script named **auth.sh** in (**/usr/local/bin/**):
```
cd /usr/local/bin/
touch auth.sh
chmod 755 auth.sh
```
The script will check a given username and password and exit with **0** code if they are correct or **1** otherwise.
The content of the script is the following:
```bash
#! /bin/bash
read user
read password

if [[ ("$user" = "hello") && ("$password" = "world") ]]; then
  exit 0
else
  exit 1
fi
```

To be able to use our script with Apache, we should install the package [libapache2-mod-authnz-external](https://packages.ubuntu.com/xenial/libapache2-mod-authnz-external) that allows authentication against external services
```
apt-get install libapache2-mod-authnz-external
```

Then, we'll make sure the authentication module is enabled
```
a2enmod authnz_external
```


#Configuring Apache
create an Apache configuration file with the name **httpd.conf** in (**/etc/apache2/**)
```
cd /etc/apache2/
touch httpd.conf
```

The content of **httpd.conf** should be the following:
```conf
<VirtualHost *:80>

    SetEnv GIT_PROJECT_ROOT /var/www/html/git
    SetEnv GIT_HTTP_EXPORT_ALL
    SetEnv REMOTE_USER=$REDIRECT_REMOTE_USER

    DocumentRoot /var/www/html
    <Directory "/var/www/html">
        Options All Includes Indexes FollowSymLinks
        Order allow,deny
        Allow from all
        AllowOverride All
    </Directory>


    ScriptAliasMatch \
        "(?x)^/git/(.*/(HEAD | \
        info/refs | \
        objects/(info/[^/]+ | \
        [0-9a-f]{2}/[0-9a-f]{38} | \
        pack/pack-[0-9a-f]{40}\.(pack|idx)) | \
        git-(upload|receive)-pack))$" \
        "/usr/lib/git-core/git-http-backend/$1"

    Alias /git /var/www/html/git

    <Directory /usr/lib/git-core>
        Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
        AuthType Basic
        AuthName "Restricted"
        AuthBasicProvider external
        AuthExternal auth
        require valid-user
    </Directory>

    <Directory /var/www/html/git>
        Options +ExecCGI +Indexes +FollowSymLinks
        Allowoverride None
        AuthType Basic
        AuthName "Restricted"
        AuthBasicProvider external
        AuthExternal auth
        require valid-user
    </Directory>

    AddExternalAuth auth /usr/local/bin/auth.sh
    SetExternalAuthMethod auth pipe

</VirtualHost>
```

Now, open **/etc/apache2/apache2.conf** file and comment out the line:
```
IncludeOptional sites-enabled/*.conf
```
Then, add the line:
```
Include /etc/apache2/httpd.conf
```

Enable **mod_cgi**, **mod_alias** and **mod_env**
```
a2enmod cgi alias env
```

Finally, update the repo and restart Apache
```
cd /var/www/html/git/reponame
git update-server-info

service apache2 restart
```


#Testing
On your machine, clone the repository
```
git clone http://{SERVER_DOMAIN}/git/reponame/
```
Add something to the repo and commit it
```
touch test.txt
git add test.txt 
git commit -m "test commit"
```
Push the changes to the remote repository
```
git push -u origin master
```

And that's about it. If the clone and push succeed, it means we successfully served our repository.