Run git on your own server
For things that are not ready to be shared with the world… #git #server #vps #privacy #ssh
The goal of this text is to teach you how to use your server to create your own private git
repository—and be able to share it with a selected few. It is based on a Digital Ocean tutorial, with some improvements.1
Scenario. More specifically, say you have a folder on your local machine, which may or may not be under git
’s version control, and you wish to set it up under git
(if that is not already the case), and create a version of it in a server you control, so that you (and others selected by you) can push and pull to/from it.
Prerequisites. A server (or VPS) that you own, and to which you have SSH access configured (in particular, access with key files is required). In what follows, I assume the server is accessible at example.com
. Also, git
must be installed. The following instructions were tested in Ubuntu Server, but they should work, mutatis mutandis, with other Linux distributions.
First, we deal with the server. We have to create an user to own the location where the git projects will be stored. It (the user) can be named anything, but to keep it simple, let’s name it git
.2 Create like so:3
# useradd git --home-dir /srv/git --user-group --shell /bin/git-shell
Here, I use git-shell
, provided by git
itself, as the login shell. That basically ensures that it is not possible to login with this user (after all, its only purpose is to handle git
stuff). This is not strictly true, but it is with the default configuration—it will not be possible to login with the git user (you can try it just to make sure). The --user-group
ensures that a group called git
will also be created (to which the user git
will belong).
Now by default, the new user’s home directory will not be created if it does not exist. So let’s create it (and couple of more things), and set up permissions (ssh
can make a fuss if some files have the wrong permissions).
# mkdir -p /srv/git/.ssh
# touch /srv/git/.ssh/authorized_keys
# chown -R git:git /srv/git
# chmod 700 /srv/git/.ssh/
# chmod 600 /srv/git/.ssh/authorized_keys
In that file—/srv/git/.ssh/authorized_keys
—append the public part of your SSH key (i.e., the contents of the file with a name that ends in .pub
). Be careful to not add any white space (or white lines) while in the copy/paste process.
So, the git
user’s home folder is /srv/git
— and I use it also as the location for the repositories. It is not strictly necessary, but it quite simplifies matters. In that location, create a bare git repository like so (git
might issue a warning about the default name of the master branch, but we can just ignore it):
# git init --bare my-project.git
Don’t worry about doing this as root
, it is an empty repository, which can be created without setting up any identity information (recall that if, for example, you try to commit without having set your name and email, git
complains somewhat loudly). And besides, the next step is to change the ownership of this folder to the git
user and group:
# chown -R git:git my-project.git
Now if you already have a local repository under git
control, that you want to push to this server, do:
$ git remote set-url origin git@example.com:my-project.git
On the other hand, if you are going to create a new repository in the folder where your project resides, then after doing git init
, do:
$ git remote add origin git@example.com:my-project.git
Now you can make changes and push them to the server, like so:4
$ GIT_SSH_COMMAND='ssh -i ~/.ssh/mykey -o IdentitiesOnly=yes' git push
mykey
is the private key corresponding to the public key that was added to /srv/git/.ssh/authorized_keys
above (the public key corresponding to mykey
should be named mykey.pub
).
The environment variable GIT_SSH_COMMAND
must be specified for all commands that need to contact the server: besides push
, there will be pull
, fetch
, and of course, clone
(inter alia). So a more convenient approach might be to use an SSH config file (usually ~/.ssh/config
; create it if it does not exist), and place the following inside:
Host mygit
Hostname example.com
Port 22
User git
IdentityFile ~/.ssh/mykey
IdentitiesOnly=yes
And thus, the push
command is reduced to: $ git push
.5 The string in Host
is arbitrary: just pick something convenient and short.6
Finally, to share access with someone else, let us call him John, ask him for an SSH key (the .pub
part), and append that to the server’s /home/git/.ssh/authorized_keys
file, just as done above. After that, he can clone the repository, like so:
$ GIT_SSH_COMMAND='ssh -i ~/.ssh/john_priv_key -o IdentitiesOnly=yes'
git clone git@example.com:my-project.git
(Remove the linebreak; I added it above only for improved readability.)
He will also be able to push any changes made back to the server, albeit always with the need to use that ghastly environment variable GIT_SSH_COMMAND
. So it might pay off for him to also setup an SSH config file, just as shown above (but with the path of his own SSH key, of course). The clone
command then shortens to just (assuming John also sets Host
to mygit
):
$ git clone mygit:my-project.git
However, he will not be able to get a shell (because the login shell of the git
user, git-shell
, will not allow it).
February 23, 2022.