Three months ago we decided to move our projects to Git. I guess you already know the advantages of Git over Subversion, as there are too many discussions for this subject. I will describe here a fast and minimal configuration of how to turn a Debian GNU/Linux box to a Git server that supports read and write actions via HTTP(S).
Git supports 4 network protocols to transfer data: SSH, Local, Git, and HTTP(S). Many people are behind a firewall, which most of times permit access only to HTTP(S). Until recently, Git HTTP(S) was working only for read actions (only clone, fetch, pull, …). Almost 2 years ago Smart HTTP Transport came up. Using these clever cgi scripts, which now are part of stable Git, we can easily setup a Git server that supports read/write via HTTP(S).
1) Install all required packages on Debian:
$> su - $> apt-get install git apache2 apache2-utils openssl
2) As we need many Git repositories, we create a base directory that all repositories will be included.
$> mkdir -p /opt/allgit/repos
3) Create a bare Git repository, where developers can pull and push code.
$> cd /opt/allgit/repos $> mkdir repo1.git $> cd repo1.git $> git init --bare
4) We will use Apache 2 HTTP server to support HTTP(S) for Git. On Debian, when you install apache2 package, user www-data is created and is the user of Apache. As we need Apache to execute the Git actions, then www-data user must have read and write permissions on each Git repository.
$> chown -R www-data:www-data repo1.git/
5) The www-data user is used only by Apache and not by developers, so we need to define our Git users somewhere else. We can use HTTP authentication that is provided by Apache. We can use htpasswd, which is an Apache tool that produce an encrypted password from a plain text password for a user. These users are irrelevant to Unix users of OS. So, using this strategy we can define as many Git users as we need, without creating Unix users. Create a specific directory and file, with restricted privileges to www-data user, in order to keep git users and passwords.
$> mkdir /etc/gitdata $> cd /etc/gitdata $> htpasswd -c gitusers.passwd gituser1 $> htpasswd gitusers.passwd gituser2
6) I choose to use secure HTTP for Git communication. So, I created a self signed SSL certificate using openssl. On the same directory create the certificate and the private keys pair. Fill all the fields you like that the next command requires.
$> openssl req -x509 -nodes -days 999 -newkey rsa:2048 -keyout mygit_ssl.key -out mygit_ssl.crt
7) Also, we need a few modules to be enabled on Apache, so make sure mod_ssl, mod_cgi, mod_alias, and mod_env are enabled. This can be easily done on Debian with a2enmod command, where it create symbolic links in the next directory.
$> a2enmod <apache_module> $> ls /etc/apache2/mods-enabled/
8) Now you only need to configure Apache site and you are ready. Assume you already have a domain name (e.g. mygitdomain.com) in order to use it for your server. A fast way to configure your Apache site(and test immediately) is to copy the existing configuration of Apache and make the required configuration changes.
$> cd /etc/apache2/sites-available $> cp default-ssl mygitdomain.com
9) Add (or alter) the existing configuration of mygitdomain.com file, which you just created, based on the next configuration.
ServerName mygitdomain.com ServerAdmin webmaster@localhost ErrorLog /var/log/apache2/git_apache_error.log SetEnv GIT_PROJECT_ROOT /opt/allgit SetEnv GIT_HTTP_EXPORT_ALL SetEnv REMOTE_USER=$REDIRECT_REMOTE_USER ScriptAlias /allgit/ /usr/lib/git-core/git-http-backend/ <Directory "/usr/lib/git-core/"> AllowOverride None Options +ExecCGI -Includes Order allow,deny Allow from all </Directory> <LocationMatch "^/allgit/repos/.*$"> AuthType Basic AuthName "My Git Repositories" AuthUserFile /etc/gitdata/gitusers.passwd Require valid-user </LocationMatch> SSLEngine on SSLCertificateFile /etc/gitdata/mygit_ssl.crt SSLCertificateKeyFile /etc/gitdata/mygit_ssl.key
Test your Git server
1) Configuration is finished. Enable this site in your Apache server and then restart Apache.
$> a2ensite mygitdomain.com $> /etc/init.d/apache2 restart
2) Try to clone your empty git repository.
$> git clone https://mygitdomain.com/allgit/repos/repo1.git repo1
Certificate verification error
error: server certificate verification failed. CAfile: /etc/ssl/certs/ca-certificates.crt CRLfile: none while accessing https://mygitdomain.com/allgit/repos/repo1.git/info/refs fatal: HTTP request failed
You have 3 options to solve this:
- Set this variable in the current shell (will be enabled for all the following commands).
- $> export GIT_SSL_NO_VERIFY=false
- Set before each git command the same variable as before.
- $> env GIT_SSL_NO_VERIFY=true
- In order to treat your certificate as trusted, even it is a self signed certificate, you can get server’s certificate and install it on one of the next directories:
This is just a fast configuration that I did 3 months ago in order to evaluate Git. There are many points that you can improve (stronger security) in order to have a better configuration.
All the configuration is make by root user.
Democracy requires Free Software
It’s an awesome article designed for all the online people; they will obtain advantage from it I am sure.
i’m stuck on GIT_PROJECT_ROOT is set but PATH_INFO is not, can you help me?
I am also struck with this issue GIT_PROJECT_ROOT is set but PATH_INFO is not. how can i resolve this
How did you solve that problem? “GIT_PROJECT_ROOT is set but PATH_INFO is not”
In Debian Wheezy, my configuration works as it is.
The only configuration changes I have done are these I wrote.
I guess your GNU Linux distribution needs something extra, which I am not aware of.
Thank you *so* much !
fatal: could not create workt tree dir ‘repo1’.???????? ? ???????
What is it?
Awesome! Its really remarkable post, I have got much
clear idea regarding from this paragraph.
Excellent post – not explained so well anywhere else.
On Ubuntu had to:
sudo a2enmod ssl
to install mod_ssl.
sudo service apache2 restart.
Thanks – really appreciated.
How about the Directory and LocationMatch closing tags? Are those two separate tags, or is LocationMatch inside Directory? Should the SSL options be inside one of them?
Somehow Directory & LocationMatch are missing close tags!!!
I fix them now. Thanks for the catch.