Recently, I was in a situation where I had a few hundred clients reading from a git repository simultaneously.
The default git over ssh was painfully for my use case and I started looking for git over http.
This is how I was able to make it work with Nginx
and git-smart-http
Install the required packages Link to heading
sudo apt-get install nginx git fcgiwrap apache2-utils -y
nginx
: is needed as the webservergit
: well, git.fcgiwrap
: will be our interface to the git-http-backendapache2-utils
: is needed to generate the password hash for authentication
Configure the repository Link to heading
Create the directory where you want to store the repositories.
sudo mkdir /srv/git
Let’s create our repository, let’s call it repo1
cd /srv/git
sudo mkdir repo1
cd repo1
sudo git init . --bare --shared
sudo git update-server-info
Enable git push Link to heading
By default the service that is used for git push (receivepack) is disabled, meaning you won’t be able to push to the repository via http. Let’s enable that
Navigate to your repository /srv/git/repo1
and edit the file config
in your favourite text editor
Add the following entry to the /srv/git/repo1/config
file
[http]
receivepack = true
This is how my /srv/git/repo1/config
file look like
root@debian:~# cat /srv/git/repo1/config
[core]
repositoryformatversion = 0
filemode = true
bare = true
sharedrepository = 1
[receive]
denyNonFastforwards = true
[http]
receivepack = true
root@debian:~#
Once that is done, run the following commands for the changes to take effect (Obviously, these commands needs to be run from the repository on the server)
sudo git config --bool core.bare true
Let’s set the permissions so that the directory is owned by Nginx (here, www-data is the user under which Nginx is running)
sudo chown -R www-data:www-data /srv/git
Configuring Nginx Link to heading
Now that we have our repository ready to serve, let’s setup Nginx.
Create your nginx config file at /etc/nginx/sites-enabled/git
or whatever file you want to. Copy the following into it
Note: Make sure to change the server_name to your preferred domain name. You can use
server_name _;
in case you want to use this for only git and no other website or service is running on this server on port 80
server {
listen 80;
server_name git.mydomain.com;
# This is where the repositories live on the server
root /srv/git;
location ~ (/.*) {
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.gitpasswd;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /usr/lib/git-core/git-http-backend;
# export all repositories under GIT_PROJECT_ROOT
fastcgi_param GIT_HTTP_EXPORT_ALL "";
fastcgi_param GIT_PROJECT_ROOT /srv/git;
fastcgi_param PATH_INFO $1;
}
}
Generating the password hash Link to heading
As you may have noticed, we are restricting the access to the git repository using http basic authentication. Now we need to generate a username and password.
Run the following. Make sure to replace user
with a username of your choice.
This will ask you to enter a password. Enter a strong one. You will be using this password for authenticating to this repository
sudo htpasswd -c /etc/nginx/.gitpasswd user
Starting services Link to heading
Now that we have everything installed and configured, we can start our services
Before starting, verify that you didn’t mess up the nginx configuration. Run the below command
sudo nginx -t
If you did something wrong, Nginx won’t be shy to pointing it out. Fix it before continuing.
# Make sure these services start on boot
sudo systemctl enable fcgiwrap
sudo systemctl enable nginx
# Start them now
sudo systemctl start fcgiwrap
sudo systemctl start nginx
Let’s test it Link to heading
By this point, you should have everything you need (theoretically speaking)
Let’s see if it works.
From one of your client, run the below command. Make note of the username and password. user:foo
and make sure you replace it with the correct username and password from the previous step.
git clone http://user:[email protected]/repo1
Now you should be able to do your usual git things. (At least it works for me :shrug: )
➜ /tmp git clone http://user:[email protected]/repo1
Cloning into 'repo1'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
➜ /tmp
➜ /tmp cd repo1
➜ repo1 git:(master)
➜ repo1 git:(master) ls -l
total 4
-rw-r--r-- 1 mansoor wheel 5 Apr 25 12:14 hello.md
➜ repo1 git:(master) echo 'version 2' > hello.md
➜ repo1 git:(master) ✗
➜ repo1 git:(master) ✗ git add . && git commit -m "version 2"
[master b20c024] version 2
1 file changed, 1 insertion(+), 1 deletion(-)
➜ repo1 git:(master)
➜ repo1 git:(master) git push origin master
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Writing objects: 100% (3/3), 251 bytes | 251.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To http://git.mydomain.com/repo1
5d42d6c..b20c024 master -> master
➜ repo1 git:(master)
➜ repo1 git:(master)
Alright, that’s it. Leave a comment if it didn’t work