Setting up a git repository that is accessible via HTTP WebDAV
I finally managed to set up a git repository on my debian server that can be accessed via http WebDAV. Since there were a few stumbling blocks I could not find any information on, I thought I should blog a quick note. This won’t be interesting to many visitors of my blog, but perhaps it can save some people a bit of time if they run into the same problems as I did.
First I have to say that I don’t know very much about the ins and outs of git yet (and the same goes for WebDAV). I merely tried to follow some tutorials for setting up a central git repository. I am not even sure if access via http is a very good idea. But I am sharing the server and before git we used subversion via WebDAV, so it seemed like the most consistent way to go the same route for git.
For the most part I followed the instructions found in this “git server over http tutorial” on kernel.org
This almost worked, but left out issues with https and a strange command named “git update-server info” that needs to be run on the server after each commit. Luckily it will be run automatically eventually, but the first time it has to be run by hand (or so it seems).
Since the tutorial at kernel.org covers most steps, I’ll describe the problems I had first and then try to give a very brief summary of all steps in at the end of the article.
git update-server-info, file ownerships and update hooks
One issue I ran into was that after trying to push to the server, git push would end with
Updating remote server info
PUT error: curl result=22, HTTP code=403
And after that I could still not pull the changes from the server into another clone.
I could not find any info on this on the net. It turned out that there were some files in the git repository that were not owned by www-data (the apache2 user). I suspect it happened when I executed
git update-server-info
on the server, which I was supposed to do once in the beginning (according to a website I unfortunately can’t find anymore now). So making www-data the owner of all files by executing
chown -R www-data /path/to/git-repo
fixed that.
As for the initial call of git update-server-info, I am not sure. Maybe it would not have been necessary had the “hook” worked from the beginning. But in case there are problems, it is probably worth executing.
git update-server-info
in the root directory of the git repository once. After that, check again that all file permissions are correct (www-data should be the owner of all files).
It seems in subsequent git push calls git triggers the update-server-info hook automatically.
Frankly it makes me feel a bit uneasy – it seems WebDAV allows writing to the git repository and executing files – could it overwrite the executable and then execute it? A bit more than what I would like to allow guest users. But WebDAV and git where implemented by smart people, so for now I’ll assume that it is going to be OK (and I don’t have guests on there yet anyway).
HTTPS, self-signed root certificates and curl+ssl on OS X with MacPorts
The other problem I had was that I wanted to allow HTTPS access only. Our apache server uses a self signed root certificate that somehow had to be made known to git. Otherwise git operations would fail because it could not validate the certificate. The tutorial on kernel.org writes that you can disable the validation, but that is a temporary solution at best.
Apparently git uses libcurl, so making the certificate known to curl fixed the problem. However, by default curl on OS X does not even have ssl support built in if it is installed via MacPorts. I found a blog article on enabling https support which explains that the remedy is to install curl with options as follows:
sudo port install curl +ssl
First the old version has to be uninstalled, though (or MacPorts has to be convinced in some other way to do the upgrade – Update: via Twitter @MacPorts told me to use “sudo port -fn upgrade curl +ssl”). This turned out to be very complicated for someone who does not know MacPorts very well. Simple port uninstall commands would fail because of dependencies, and even
sudo port uninstall --follow-dependents curl
Would fail because sometimes there would still be multiple versions of packages around and MacPorts would then not know which ones to uninstall (yeah right, because I want to keep the outdated package??).
After a bit of Yahoogling I found that I could purge all the outdated packages with the command
sudo port -f uninstall inactive
The -f is for force, however, so it uninstalls even if there might be some dependencies. I have not yet checked if any other packages have stopped working. Also, for the future I know to run “port -u upgrade” instead of “port upgrade”, as the -u flag is supposed to tell MacPorts to uninstall the outdated versions right away.
With that cleared up, I could uninstall and reinstall curl and curl +ssl. One more thing to do about the certificates problem: make it known to curl. Our certificate was already in PEM format, so all there was to it was to add the text from the PEM certificate to /usr/share/curl/curl-ca-bundle.crt and git stopped complaining about the certificates. curl will name the location of it’s ca-bundle, in case it is located elsewhere on your system. I really added the certificate manually by opening curl-ca-bundle.crt in a text editor and copy+pasting the root certificate text (UPDATE: I just realized that MacPorts replaced that file when updating curl+ssl – looking for workaround). There are tutorials for importing the certificates from Firefox, but I don’t think they necessarily work for OS X. However, Firefox might provide an easy way to convert certificates to PEM, as it lets you choose the format for exporting certificates (in “Preferences”->”Advanced”->”View Certificates”).
Update: on Ubuntu 9.04 I also had problems to let curl know about the certificate. What worked where the instructions found at help.ubuntu.com for “Importing a Certificate into the System-Wide Certificate Authority Database”.
However, somehow git on Ubuntu does not ask me for a password and just fails with error code 22 (unauthorized). As a workaround for the time being I tried to hardcode my password into the remote URL (username:password@url), but that led to an error message (same as this one). Putting my login information into ~/.netrc as follows worked:
machine domain.name
login foo
password bar
I am not very happy with that, though, as it puts my password into a file in clear text.
quick steps summary (on Debian Linux)
Create directory for repository, either below apache2 DocumentRoot (usually /var/www) or some other lcoation you deem suitable
mkdir myproject.git
Init git repository with –bare option (apparently to make sure it never gets into unclean state – it should not be used the same way a local git repo is being used). Make accessible to www-data (apache user).
cd myproject.git
git --bare init
git update-server-info
chown -R www-data.www-data .
(note: install git with apt-get install git-core, the package “git” seems to be something else). Enable WebDAV (it seems I did not need the dav_fs as suggested in the kernel.org tutorial)
a2enmod dav
Configure apache for allowing WebDAV to the git repository. I also require SSL – however I won’t go into this. The infrastructure already existed on my server and I don’t want to search for tutorials now. There should be plenty of tutorials on setting up SSL for apache2. The same goes for setting up BasicAuth. Also I did not add my changes to /etc/apache2/httpd.conf but to the respective VirtualHost config file for my domain in /etc/apache2/sites-available (as our apache2 serves multiple domains).
My config looked something like this:
Alias /git/myproject /path/to/git/repo/on/server
<Location /git/myproject>
SSLRequireSSL
DAV on
AuthType Basic
AuthName "yourDomainForBasicAuth"
AuthUserFile /etc/apache2/path/to/password-file
Require user username-in-passwordfile
</Location>
Restart apache2 with /etc/init.d/apache2 restart and things should be ready to go. As described at kernel.org, configure the remote location for your local git repo as follows
git config remote.upload.url https://<username>@<servername>/git/myproject/
I suppose “upload” is actually an arbitrary name you can choose. The trailing “/” is important. From then on you can just
git push upload master
to the repository. (If the project is not yet in git, execute “git init” in the top level directory of the project first).
On the other hand, to check out the project from the server into a new working directory (let’s call it “my-project-dir”), I did
git clone https://<username>@<servername>/git/myproject/ my-project-dir
Not sure actually if that is the best way – git has so many variations. But when I had done it like that, the way to push changes to the server would be
git push origin master
I suppose because I pulled the project from the server, the server repo is now known as “origin”, no need to configure anything else. There is a certain logic to it apparently.
I have not yet set up passwords via .netrc as described in the kernel.org tutorial, so that step is optional.
February 15th, 2010 at 1:22 pm
Hi Björn,
I’ve got some trouble trying to set up a git server.
Here’s my goal:
1: read/write server (preferrably using webdav)
2: GitX client (eg. a user-interface client)
I’m used to CVS, and know how to use the terminal app. for basic CVS operations, but I don’t want to do that anymore. As it’s been a while since I used CVS, I don’t have any current installation, but want to have some version control again.
I also got tired of typing. Now I want a button I can click, whenever I want the computer to work for me.
Here’s what I’ve learned / done so far. I’m using Mac OS X Leopard for everything.
install git:
* Download git-1.7.0.tar.gz, depack it, run ./configure && make && sudo make install
* Check version by doing $git –version, verified, this works.
* Download and install man pages, verified, this works.
* Customize prompt to use __git_ps1, this works.
* Create a repository at /Web/git/repository.git/, enable WebDAV with BasicAuth, this seems to work, as when I go there, my browser asks me for username/password. I can view the files/folders in the browser after restarting Apache.
* Created a .netrc file in my home directory on my client machine. This seems to work if using curl –netrc.
Now… This is where I’m stuck.
I made a junk-project; eg. a folder with an Xcode project in it, and a few text-files.
I want to add this to the repository on the server.
From what I understood, I have to first create a repository inside the project folder, so I’ve tried…
$ git init
Initialized empty Git repository in /Users/username/MyProject/.git/
(master) $ git add .
(master) $ git config remote.upload.url http://username@domain/repository.git/
(master) $ git commit
[typing ‘initial commit.’ in vi and pressing :wq to write and exit
(master) $ git push upload master
Here I’m asked to type a password.
If I type my sudo password, I get
fatal: HTTP request failed
If I type my repository password, I get…
error: cannot lock existing info/refs
fatal: git-http-push failed
-So I guess I am supposed to type my repository password, which makes more sense.
I then tried something different…
$ mkdir test; cd test
$ git clone http://username:password@domain/repository.git/
Initialized empty Git repository in /Users/jens/__test/repository/.git/
warning: You appear to have cloned an empty repository.
$ cd repository/
(master) $ echo “helloiamjmp” >testfile.txt
(master) $ git add testfile.txt
(master) $ git commit
(master) $ git config remote.upload.url http://username@domain/repository.git/
(master) $ git push upload master
Password: (entered repository password)
Password: (entered repository password)
error: cannot lock existing info/refs
fatal: git-http-push failed
Do you have any idea on where I’m going wrong, and perhaps why / how ?
February 15th, 2010 at 1:51 pm
Alright, I got a bit further now, maybe it’s all solved.
After looking in /Web/git/Logs/ErrorLog, I found out there’s a permission problem on the lock file.
In my httpd-dav.conf, I have the line…
DavLockDB “/usr/var/DavLock”
I then checked the /usr/ directory, the ‘var’ directory was missing.
$ mkdir var
$ cd var
$ chown www .
$ chgrp www .
And then repeating the process seems that now I can push!! =)
So hereby the answer for those who should come by and have the same problem.
June 14th, 2010 at 7:39 pm
Hi, with respect to the self-signed certificate issues, using a linux machine I managed to solve it by following the steps you can find at (my webpage) http://aeminium.org/slug/software/tips/git-webdav-ssl.html