Introduction #
Pretty much the moment I started to work with Git a few years ago, I’ve wanted to host my own server. I didn’t really bother looking into how that could work for a very long time. I assumed it would be rather complex considering Git itself is an extremely complex (set of) tool(s) to work with. I was hilariously wrong. It’s so simple to me that I’m under the impression that the lack of posts regarding the topic on blogs like this, is because it’s so simple. Still, I’m going to spend the rest of this post explaining how to set up a server and why even calling a basic configuration a server, is a bit of an exaggeration.
Setting up the server #
The first step is to set up a Unix box of any kind. Linux, any of the BSDs and probably even Darwin will work (hell, even Haiku might suffice). The rest of this post assumes a Debian system (or rather, that you have the core GNUtils available). Basics requirements are quite few:
- It needs to be accessible using SSH.
- It needs Git installed.
Adding an account #
Common practice dictates that you have a dedicated account for managing your Git repositories.
Common practice again dictates that this account be called git
.
Its home directory doesn’t really matter, but I like tossing it into /srv/git
.
Login shell also doesn’t matter yet, I tend to change it to bash
for when I need to do things as the git
user.
You can create an account with the following:
sudo useradd git -md /srv/git -s /bin/bash
-d
specifies where the home directory should be-m
creates the home directory-s
specifies what binary to use as login shell
Setting up SSH #
Client side #
On the machine from where you want to push your git repositories, generate a new SSH key to access your Git server:
ssh-keygen -t ed25519 -f ~/.ssh/<git-key>
I also recommend creating an entry in ~/.ssh/config
for your Git server:
Host <host>-git
Hostname <hostname>
User git
Identityfile ~/.ssh/<git-key>
Server side #
Next step is to make the git
account accessible over SSH.
ssh-copy-id
won’t work because the git
user doesn’t have a password.
So instead, log in as the git
user and create a .ssh
directory with an authorized_keys
file with the public half of the <git-key>
keypair:
sudo su - git
umask 077 # strict read write permissions
mkdir ~/.ssh
cat <git-key>.pub >> ~/.ssh/authorized_keys
Adding a repository #
You should now be able to log into your host as the git
user with using <git-key>
.
Setting up the route from client to server is half the work.
Next step.
Make this actually serve Git repositories.
All this requires is a bare Git repository somewhere within /srv/git
.
To do this, log in as the git
user and run:
git init --bare <repo-name>.git
That’s it.
You now have a Git “server” with a repo named <repo-name>
.
To add something to this repo, on your client machine create a new repository and add <host>-git:/srv/git/<repo-name>.git
as remote and push your project to it.
Common practice dictates that this remote be called origin
:
mkdir my-fancy-project
cd my-fancy-project
git init
git remote add origin <host>-git:/srv/git/<repo-name>.git
echo "# Self-hosted repo!" > README.md
git add -A
git commit -m "Initial commit"
git push -u origin main # assuming you use main as your default branch name
To clone this repository on another machine, add the <git-key>
SSH keypair and related configuration section in ~/.ssh/config
to said machine and run:
git clone <host>-git:/srv/git/<repo-name>.git
Automation #
Creating bare repositories by hand gets annoying quite quickly. I have an SSH forced command for another key that runs a script with the following:
#!/bin/sh
BASELOC="/srv/git"
echo "Enter new repo name:"
read REPONAME
[ -z $REPONAME ] && echo "No repo initialised" && exit 1
git init --bare $BASELOC/$REPONAME.git
authorized_keys
entry for git
user:
command="/srv/git/.bin/new-repo" ssh-ed25519 <new-repo-git-key>.pub
Another thing you could do is change the login shell binary to a script that does something similar. I haven’t bothered to do so for reasons that presently escape me.