Git Repos auf shared Webspace

Vorweg: Theoretisch braucht man in Zeiten von GitHub, GitLab, VS-Online und den ganzen Git-Hostern nicht wirklich die Möglichkeit eigene Git-Repos auf Shared Webspace einzurichten – Manchmal gibt es jedoch Grenzfälle wo es durchaus Sinn macht.
In meinem Fall ist es ein relativ „wenig“ genutzter Webspace Account von 1und1 der unter anderem Unlimitiert Webspace verspricht, der ohnehin schon die Option bietet via SSH eigene Git-Repos zu hosten.
Für meinen Speziellen Fall möchte ich aber nicht über SSH sondern via HTTP auf die Repos zugreifen, was den Vorteil hat das man verschiedenen User-Authentifizierungen für verschiedene Git-Repos einrichten kann.

Alles was wir brauchen ist folgendes:
– ein Verzeichnis auf einem Webspace (z.b. „http://frickelblog.de/gitrepos“)
– eine git-http-backend.cgi Datei welche das git-eigene git-http-backend aufruft
– eine .htpasswd Datei für die Benutzer-Accounts
– eine .htaccess Datei im Stamm-Verzeichnis für mod_rewrite Einträge
– eine .htaccess Datei je Git-Repo für die Benutzer-Authentifizierung

Außerdem brauchen wir zusätzlich folgende Informationen:
– Physischen Pfad zum Webspace-Verzeichnis (z.B.: /kunden/homepages/55/d105929445/htdocs/gitrepos)
– Pfad zu git auf dem Server (z.b. 1und1: /usr/bin/git)
– Pfad zu git-http-backend auf dem Server (z.b. 1und1: /usr/lib/git-core/git-http-backend)

Wir gehen hier davon aus das unsere Git-Repos unter der Adresse http://frickelblog.de/gitrepos gehostet werden.
In diesem Verzeichnis legen wir nun die“git-http-backend.cgi“, die „.htpasswd“ und eine „.htaccess“:

/gitrepo/git-http-backend.cgi:
ACHTUNG: hier muss das GIT_PROJECT_ROOT zu dem Pfad zu eurem Verzeichnis geändert werden

1
2
3
4
5
6
7
8
9
10
11
#!/bin/sh
#first we export the GIT_PROJECT_ROOT
export GIT_PROJECT_ROOT=/kunden/homepages/55/d105929445/htdocs/gitrepos
 
if [ -z "$REMOTE_USER" ]
then
    export REMOTE_USER=$REDIRECT_REMOTE_USER
fi
 
#and run your git-http-backend
/usr/lib/git-core/git-http-backend

/gitrepo/.htpasswd:

1
test:9aaxEmXjPttFc

/gitrepo/.htaccess:
ACHTUNG: hier muss das RewriteBase zu eurem Verzeichnis geändert werden

1
2
3
4
5
6
7
8
9
10
<Files ~ (\.cgi$)>
SetHandler cgi-script
Options +ExecCGI
allow from all
</Files>
 
#This is the rewrite algorithm
RewriteEngine on
RewriteBase /gitrepos
RewriteRule ^([a-zA-Z0-9._]*\.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))$ /git-http-backend.cgi/$1

Als nächstes muss das Git-Repo erstellt werden.
Am einfachsten geht dies über den SSH Zugriff bei 1und1 – oder man erstellt sich lokal ein bare Repo und läd es via FTP auf dem Webspace.
Hier eine kurze Anleitung zum erstellen eines Git-Repo mit dem Namen „test.git“:

1
2
3
4
5
6
mkdir ./gitrepos/test.git
git init --bare ./gitrepos/test.git
cd ./gitrepos/test.git && git --bare update-server-info
cp ./hooks/post-update.sample ./hooks/post-update
chmod a+x ./hooks/post-update
touch ./git-daemon-export-ok"

Dieses Repo wäre nun über die URL http://frickelblog.de/gitrepos/test.git zu erreichen.
Für eine Benutzer-Authentifizierung legen wir noch eine „.htaccess“ Datei zusätzlich in das Verzeichnis des Git-Repo.

/gitrepo/test.git/.htaccess:
ACHTUNG: hier muss das AuthUserFile zu eurem Verzeichnis der .htpasswd geändert werden

1
2
3
4
AuthName "Private Git Access"
AuthType Basic
AuthUserFile /kunden/homepages/55/d105929445/htdocs/gitrepos/.htpasswd
Require user test

Die letzte Zeile „Require user test“ sagt aus, das nur der Benutzer „test“ auf das Repo zugreifen darf.

Ich habe hier mal ein kleines PHP-Script zusammen gefrickelt, welches diese oberen Schritte auf einem 1und1 Webspace automatisch ausführt (cgi-datei, htaccess und htpasswd Dateien erstellen).
Damit muss nur noch ein Name für das Repo, den Benutzer und ein Passwort vergeben werden – alles andere passiert völlig selbstständig 🙂

gitmin.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
<?
define("REPOROOT", str_replace("/gitmin.php","",$_SERVER["SCRIPT_FILENAME"]));
define("PASSWDFILE", REPOROOT."/.htpasswd");
define("GITHTTPBACKEND", "/usr/lib/git-core/git-http-backend");
define("GITHTTPBACKENDFILE", REPOROOT."/git-http-backend.cgi");
 
$reponame = $_POST['reponame'];
$benutzer = $_POST['benutzer'];
$passwort = $_POST['passwort'];
$repoPfad = REPOROOT."/".$reponame.".git";
$URLPfad = str_replace("/gitmin.php","",$_SERVER["SCRIPT_NAME"]);
 
// .htpasswd erstellen,falls nicht vorhanden
if(!file_exists(PASSWDFILE))
{
	file_put_contents(PASSWDFILE,"");
}
 
//.htaccess für mod_rewrite und CGI erstellen, falls noch nciht vorhanden
if(!file_exists(REPOROOT."/.htaccess"))
{
	$htaccess_inhalt = '<Files ~ (\.cgi$)>'."\n";
	$htaccess_inhalt.= 'SetHandler cgi-script'."\n";
	$htaccess_inhalt.= 'Options +ExecCGI'."\n";
	$htaccess_inhalt.= 'allow from all'."\n";
	$htaccess_inhalt.= '</Files>'."\n";
	$htaccess_inhalt.= "\n";
	$htaccess_inhalt.= '#This is the rewrite algorithm'."\n";
	$htaccess_inhalt.= 'RewriteEngine on'."\n";
	$htaccess_inhalt.= 'RewriteBase '.$URLPfad.''."\n";
	$htaccess_inhalt.= 'RewriteRule ^([a-zA-Z0-9._]*\.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))$ '.$URLPfad.'/git-http-backend.cgi/$1'."\n";
 
	file_put_contents(REPOROOT."/.htaccess",$htaccess_inhalt);
}
 
 
// git-http-backend.cgi erstellen, falls nicht vorhanden
if(!file_exists(GITHTTPBACKENDFILE))
{
	$githttpbackend_inhalt = '#!/bin/sh'."\n";
	$githttpbackend_inhalt.= '#first we export the GIT_PROJECT_ROOT'."\n";
	$githttpbackend_inhalt.= 'export GIT_PROJECT_ROOT='.REPOROOT.''."\n";
	$githttpbackend_inhalt.= ''."\n";
	$githttpbackend_inhalt.= 'if [ -z "$REMOTE_USER" ]'."\n";
	$githttpbackend_inhalt.= 'then'."\n";
	$githttpbackend_inhalt.= '    export REMOTE_USER=$REDIRECT_REMOTE_USER'."\n";
	$githttpbackend_inhalt.= 'fi'."\n";
	$githttpbackend_inhalt.= ''."\n";;
	$githttpbackend_inhalt.= '#and run your git-http-backend'."\n";
	$githttpbackend_inhalt.= ''.GITHTTPBACKEND.''."\n";
 
	file_put_contents(GITHTTPBACKENDFILE,$githttpbackend_inhalt);
	exec("chmod 755 ".GITHTTPBACKENDFILE."");
}
 
if($_POST['action']=="repo_anlegen")
{
	if(file_exists($repoPfad))
	{
		echo "Fehler: Das Git Repo $repoPfad existiert bereits!<br>";
	}
	else
	{
		echo "Repo anlegen...<br>";
		exec("mkdir $repoPfad");
		exec("git init --bare $repoPfad");
		exec("cd $repoPfad && git --bare update-server-info");
		exec("cp $repoPfad/hooks/post-update.sample $repoPfad/hooks/post-update");
		exec("chmod a+x $repoPfad/hooks/post-update");
		exec("touch $repoPfad/git-daemon-export-ok");
 
		echo ".htaccess Datei schreiben...<br>";	
		$htaccess_inhalt = "#This is used for group/user access control\n";
		$htaccess_inhalt.= "AuthName \"Private Git Access ($reponame)\"\n";
		$htaccess_inhalt.= "AuthType Basic\n";
		$htaccess_inhalt.= "AuthUserFile ".PASSWDFILE."\n";
		$htaccess_inhalt.= "Require user $benutzer\n";
		$htaccess_inhalt.= "\n";
 
		file_put_contents($repoPfad."/.htaccess",$htaccess_inhalt);
 
		echo ".htpasswd Datei schreiben...<br>";
		$htpasswd_inhalt = file_get_contents(PASSWDFILE);
		$htpasswd_inhalt.= $benutzer.":".crypt($passwort)."\n";
		file_put_contents(PASSWDFILE,$htpasswd_inhalt);
		echo "...fertig!<br>";	
 
		echo "git clone http://$benutzer:$passwort@".$_SERVER["SERVER_NAME"]."".$URLPfad."/".$reponame.".git";
	}
 
}
 
?>
 
 
<form action "gitmin.php" method="POST">
<table>
	<tr>
		<td>Repo-Name:</td>		<td><input type="text" name="reponame"></td>
	</tr>
	<tr>
		<td>Benutzer:</td>		<td><input type="text" name="benutzer"></td>
	</tr>
	<tr>
		<td>Passwort</td>		<td><input type="text" name="passwort"></td>
	</tr>
	<tr>
		<td colspan=2>
			<input type="hidden" name="action" value="repo_anlegen">
			<input type="submit" text="Repo anlegen">
		</td>
	</tr>
</table>
</form>

Viel Spaß beim benutzen des Scriptes bzw der selbst gehosteten Git-Repos 🙂
Fragen und Anregungen sind wie immer jeder Zeit willkommen.

leave your comment


*

Unterstütze den Frickelblog!