setting a git server is easy, and involves only common shell commands, this post will show you how i started my very first self-hosted git server. find one extra computer and set up a SSH connection to it, then you are ready to start. here i used my raspiberry pi, which is always up [1].

to setup the git server you should do the following on the server machine:

  1. create git user
  2. add sshd keys
  3. create projects dir
  4. create empty git repo
  5. using the git shell

create git user

this step is just sudo useradd -m git, no secret here. now log in this user.

add sshd keys

this part is the creation of the authorized_keys, so you can SSH in with this user. basically you just add the allowed public keys here. in my case i just copied from my main user, but the ideal case is creating another key and adding that to the git server.

mkdir .ssh
cat new-key.pub > .ssh/authorized_keys
chmod 600 .ssh/authorized_keys 

now you should be able for SSH into your git machine using the key you added.

create projects dir

this step is optional but i like creating a dedicated folder for my projects, so i ran: mkdir git, and entered it.

another cool thing to do is to change the default git branch:

git config --global init.defaultBranch main

create empty git repo

this is the command that creates a repo on the server, so you can push to this repo. to create it first create a folder, and then issue the init command:

mkdir project
cd project
git init --bare

at this stage you have a fully functional git repository, to use it you proceed as you do for new repos.

using you new repo

now in your other machine you can init a repo and push:

cd project
git init
git add .
git commit -m 'Initial commit'
git remote add origin git@:git/project
git push origin main 

you can stop here if you want, but in this state there are some anoying things on the server that can drive you nuts, for example:

the next section will deal with these issues using the git shell and some configurations.

using the git shell

first thing to improve is to remove port forwarding, so add this to the start of each entry in the ~/.ssh/authorized_keys file:

no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty 

now SSH users cannot get a login shell, only the non-interactive shell we are going to configure will be available.

the we must set the git shell to be used on login. so log in your server machine, now check if the git-shell is listed on the /etc/shells file with: cat /etc/shells, if you do not see git-shell there, you can add it:

sudo echo "$(which git-shell)" >> /etc/shells 

but i advise you to use an editor. now make it the login shell for the git user:

sudo chsh git -s $(which git-shell) 

now you will not be able to get a shell on a log in. so this user is useless for anything else than git stuff. you can only run git commands like pull, push and clone, plus the commands we created on git-shell-commands.

setup up greeting and commands

the git-shell can be customized by creating the folder git-shell-commands on the git home, the first and funnier thing to do it to just show a message when a login is atempted.

you can present a greeting to users connecting via SSH by creating a file named no-interactive-login in the folder we just created. it's funny, e.g.:

#!/bin/sh
echo "welcome to your git server!" 

so when git tries to log in your server this message is shown.

adding programs to this folder will let users run them. there are some convenient commands to add, for example, creating a new repository, deleting one and listing all repos. to make them available don't forget to let them be executable:

chmod +x git-shell-commands/program 

a good starting point is [2].

conclusion

i think this is a good configuration, it is safe and let's you fully interact with git, even creating and deleting repos.

at the same time this configuration is flexible as you can keep adding new commands. but there is room for improvements, for example, your repositories have zero visibility, there is no colaboration.

adding public access can be done using git-daemon, or setting up the git HTTP. but those are subjects for other articles.