In this tutorial I will show you how to set up your own Git server. Here I have used an Ubuntu 20.04 server on a virtual machine which is called homeserver and my clinent machine is called client. The convention for the bash scripts is user@host:~$
The Protocols
Git can use four distinct protocols to transfer data: Local, HTTP, SSH and Git
Local
The URLs will be in the following form:
1 |
git clone /home/git/repos1 |
or
1 |
git clone file:///home/git/repos1 |
HTTP Protocols
Git can communicate over HTTP using Smart HTTP or Dumb HTTP.
Smart HTTP
Intelligently negotiate data transfer in a manner similar to how it does over SSH. Very similarly to the SSH or Git protocols but runs over standard HTTPS ports and can use various HTTP authentication mechanisms, meaning it’s often easier on the user than something like SSH, since you can use things like username/password authentication rather than having to set up SSH keys. It can be set up to both serve anonymously like the git://
protocol, and can also be pushed over with authentication and encryption like the SSH protocol.
Dumb HTTP
It is very simple and generally read-only. If a server does not respond with a Git HTTP smart service, the Git client will try to fall back to the simpler Dumb HTTP protocol. The Dumb protocol expects the bare Git repository to be served like normal files from the web server.To set up all you have to do is put a bare Git repository under your HTTP document root and set up a specific post-update hook.
1 2 3 4 5 |
d /var/www/htdocs/ git clone --bare /home/git/repos1 repos1.git cd gitproject.git mv hooks/post-update.sample hooks/post-update chmod a+x hooks/post-update |
The post-update hook that comes with Git by default runs the git update-server-info
to make HTTP fetching and cloning work properly. This command is run when you push to this repository (over SSH for example). You can clone via:
1 |
git clone https://hostname/repos1.git |
SSH Protocol
To clone a Git repository over SSH, you can specify an ssh://
URL like this:
1 |
git clone ssh://[user@]server/project.git |
Or you can use the shorter scp-like syntax for the SSH protocol:
1 |
git clone [user@]server:project.git |
The main drawback is that you need SSH authentication even for read only repositories.
Git Protocol
It is a daemon (that comes packaged with Git) and listens on a dedicated port (9418) that provides a service similar to the SSH protocol, but with absolutely no authentication. In order for a repository to be served over the Git protocol, you must create a git-daemon-export-ok
file. Either the Git repository is available for everyone to clone, or it isn’t. You can enable push access but, given the lack of authentication, anyone on could push to your repository. Generally, you’ll pair it with SSH or HTTPS access for the few developers who have push (write) access and have everyone else use git://
for read-only access. This protocol requires xinetd
or systemd
configuration or the like and also requires firewall access to port 9418,
Now let’s set up our server:
1) First on the server side make sure that the essential packages are installed:
1 2 |
behnam@homeserver:~$ sudo apt-get install openssh-server behnam@homeserver:~$ sudo apt-get install git-core |
2) Create a group for Git users:
1 |
behnam@homeserver:~$ sudo groupadd gituser |
3) Create users and add them to the gituser group:
1 2 3 4 5 6 7 8 9 |
behnam@homeserver:~$ sudo adduser git su git git@homeserver:~$ mkdir -p .ssh su behnam behnam@homeserver:~$ sudo adduser gitusera behnam@homeserver:~$ sudo adduser gituserb behnam@homeserver:~$ sudo usermod -a -G gituser git behnam@homeserver:~$ sudo usermod -a -G gituser gitusera behnam@homeserver:~$ sudo usermod -a -G gituser gituserb |
BTW If you want to:
List all groups:
1 |
behnam@homeserver:~$ cat /etc/group |
List groups of a user:
1 |
behnam@homeserver:~$ groups gitusera |
List all users:
1 |
behnam@homeserver:~$ cat /etc/passwd |
And if you want to complelty delete a user and remove the user home directory:
1 |
behnam@homeserver:~$ sudo deluser --remove-home git |
Hint: the user should do a login and logout to make the group assignment effective.
4) Create a git repository and tell it to share based on the group the user belongs to
1 2 3 4 |
behnam@homeserver:~$ su git git@homeserver:~$ cd ~ git@homeserver:~$ mkdir repos1 git@homeserver:~$ git init --bare --shared=group |
BTW if you want to create a non-bare repository that you can push into that:
1 |
git config --local receive.denyCurrentBranch updateInstead |
5) Give gituser group permission to access the repository directory
1 |
git@homeserver:~$ chgrp -R gituser /home/git/repos1 |
Hint:
All files in Linux belong to an owner and a group. chgrp command changes the group ownership of a file or directory. You can set the owner by using chown command, and the group by the chgrp command. -R means do it recursively. You can see the owner and permision by
1 |
git@homeserver:~$ ls -hl . |
1 |
git@homeserver:~$ chmod -R g+rw /home/git/repos1 |
This command will give the gituser group the permission of read and write.
1 |
git@homeserver:~$ chmod g+s <code>find /home/git/repos1 -type d |
chmod g+s sets the setgid mode bit on the current directory which will cause any new file or directory that placed in this directory inherit the group owner (gituser), but the current files and directories will not be effected. To aply changes on them we directly call the command on them by using find /home/git/repos1 -type d
6) Create and config the clients
Create two users on the client machine:
1 2 3 4 5 6 7 8 9 |
behnam@client:~$ sudo adduser gitusera behnam@client:~$ su gitusera gitusera@client:~$ ssh-keygen -t rsa gitusera@client:~$ ssh-copy-id -i .ssh/id_rsa.pub gitusera@homeserver behnam@client:~$ su behnam behnam@client:~$ sudo adduser gituserb behnam@client:~$ su gituserb gituserb@client:~$ ssh-keygen -t rsa gituserb@client:~$ ssh-copy-id -i .ssh/id_rsa.pub gituserb@homeserver |
SSH key pairs can be used to authenticate a client to an SSH server. That’s why we used ssh-copy-id to add them into ~/.ssh/authorized_keys so we can log in without password later.
Now copy the public key to the server and append it to the authorized_keys file as above
1 |
gitusera@client:~$ scp .ssh/id_rsa.pub git@homeserver:/home/git |
Append the client’s public key for ceach client to the authorized keys on server
1 2 |
ssh git@homeserver git@client:~$ cat ~/id_rsa.pub >> ~/.ssh/authorized_keys |
Now you should be able to clone the repository:
1 |
gituserb@client:~$ git clone ssh://gitusra@homeserver:/home/git/repos1 |
And you should be able to push:
1 2 3 4 5 6 7 |
gitusera@client:~$ cd ~/repos1/ gitusera@client:~$ date > date.txt gitusera@client:~$ git add . gitusera@client:~$ git config --global user.email "gitusera@client" gitusera@client:~$ git config --global user.name "gitusera" gitusera@client:~$ git commit -m 'date.txt added' gitusera@client:~$ git push |
and pull the changes with other user:
1 2 3 |
behnam@client:~$ su gituserb gituserb@client:~$ cd ~ gituserb@client:~$ git clone ssh://gituserb@homeserver:/home/git/repos1 |
If you want to see the URL that your local Git repository was originally cloned from:
1 |
git remote show origin |