How to Train Your Git Server

Justin Wernick <>
Curly Tail, Curly Braces
2022-06-10

Abstract

Have you considered hosting your own Git server? It's easier than you might think. In this article, I go step by step through setting up a simple self-hosted Git server which only supports private repositories for a single person.

Where do you currently host your Git repos? GitHub? BitBucket? GitLab?

Why not do it yourself?

Ok, there are reasons not to do it yourself. All of those services are fully featured products outside of Git, with user management, continuous integration, issue tracking, and basically free for most personal use. But it's also not as hard as you might think to just host Git yourself.

But why would you want to do this?

I want people to know how to do this because I'm a bit uncomfortable with the increasingly centralised nature of the internet, where it's controlled by a few massive corporations. I started hosting my own Git server as a learning exercise when Microsoft bought GitHub a few years ago. I don't think we all need to be hosting our own Git servers, but I think we should be able to if we need to. We should all be able to own our own data without being vulnerable to big companies changing the rules.

Packing away my tinfoil hat, it can also be useful to know just enough to set up something temporary for a week or two when the finance department forgets to pay for the Git hosting. Yes, this has happened to me.

I also wanted something specific: the ability to create as many private repos as I wanted, and to have them hosted close to home. I can rent a server that's physically located in the same city as me and run whatever I want on it, but the major Git hosting providers don't have servers in South Africa. I use Git a lot, and just having the Git server in South Africa with me decreases the latency on all Git fetches and pushes by a few hundred milliseconds. Not enough to have a real impact, but enough to be noticeable.

What will I cover in this article?

This article will cover setting up a simple Git server, meant for

There are a lot of other nice to haves and operational tricks that you might decide you want to add after this, but today I want to focus on the bare minimum.

This bare minimum is also enough for a lot of use cases. You can backup your local repos that you aren't sharing. You can sync your repos between multiple computers. You can even share your repos with someone else that you trust by sharing the user login. It's not web scale, but it is small web scale.

How do you host a Git server?

There's three steps to this:

  1. Get a Linux server.

  2. Add a user account with SSH access.

  3. Install Git.

Let's get into it!

Get a Linux server

The first thing you're going to need is a Linux server. In terms of where to get that server, you have many options. There are a few big cloud computing companies that don't need my advertising. I wanted to have my server close to home, so my server is hosted by CloudAfrica. This server is for Git repos, which can get big depending on how much you put in them, so make sure you know how much you'll be charged for storage, and how much you'll be charged for moving data in and out. Luckily, if you're the only user, you can usually go with the least powerful cheapest server available (you can always move to a pricier one if you need it).

As an aside, you can completely do this with an old laptop. You'd just need to make sure you can connect to it from any computer you want to do Git stuff on. I went with a cloud server because it's easier to get it available on the internet that way.

I'm not going to give specific steps for how to create a Linux server because it will vary from platform to platform and also on your particular flavour of Linux, but here's some stuff to look out for:

As an optional extra step, if you happen to have a domain, you can add a DNS record to point at your server. Which type of record will depend what your hosting platform gives you. If you can refer to your server by IPv4 address, then you need to add an A record. If you can refer to your server by IPv6 address, then you need an AAAA record. If your hosting platform shares IP addresses and only lets you refer to your server by URL, then you'll need a CNAME record. I added a subdomain to my website's domain, so code.worthe-it.co.za points at my Git server. If you don't have a domain, you can still refer to your server by IP address or a URL provided by your hosting platform, it's just nicer to type a domain name.

I provided my SSH key as part of the CloudAfrica sign up process, so at the end of this step I could login to my new server with ssh root@code.worthe-it.co.za.

Create a user account for yourself with SSH access

Chances are when you set up your server it gave you a root account. In theory you could just use the root user as your Git user, but it's generally better security practice to do most things with a normal user account that doesn't have the power to break everything.

User management and SSH key management for those users is pretty common, so if your cloud platform has a way to add a user you could just use their tools and skip this whole section. However, if you're not so lucky, you can open a terminal with that root user and do it yourself.

# Feel free to call your user account justin.
# Or swap it out for your own name if you prefer.
useradd justin

Next, you need to set up a way for Git to login to access your repos. To do this, you need your server to be running an SSH daemon. SSH (short for secure shell) is a way for you to login to a server remotely. There's a good chance that your server already has this set up, but if it's not you can just install it yourself.

# This might be called something different on your distro, and if
# you're using a cloud service it's probably already installed.
apt install openssh-server
systemctl enable ssh.service
systemctl start ssh.service

You might want to take a look at the SSH config and see if the settings make sense for you. The config file is generally filled, with all of the default options commented out, so it's easy to read through and see what the options are. Many people disable password-based authentication, and disable logging in as root, but if you're doing this be careful not to lock yourself out.

nano /etc/ssh/sshd_config

# if you made any changes, you'll need to restart the service for the
# changes to take effect.
systemctl restart ssh.service

When you're happy with your SSH daemon config, it's time to upload your SSH public key. This is the same SSH public key that you would have uploaded to other managed Git servers. The only difference is that you need to put it in a specific file rather than uploading it through a web interface. It needs to go in ~/.ssh/authorized_keys. We'll put your ssh public keys on the server using scp (secure file copy, essentially cp over ssh), and then login and stick it on the end of the authorized_keys file.

# This part is run on your computer (not the server). It's based on
# Linux, so if you're on Mac or Windows you may need to do the
# equivalent for your platform.

# If you don't already have an SSH key, you need to make one. If you
# already have one that you use with GitHub / GitLab / BitBucket /
# Whatever, then you can just use the same one.
ssh-keygen

# We're doing this as root because we can't ssh in as "justin" yet. If
# you're adding a second key later and still have the first, you can
# do this without the root account.
scp ~/.ssh/id_rsa.pub root@your-cool-server-ip:new_ssh_key.pub

Now that you've uploaded your SSH key, you need to put it in the right place. Login as root and then do the following:

# These steps should be run on the server.

# Remember to swap out "justin" for your username. This will show you
# if the .ssh folder and the authorized_keys files already exist.
ls -l /home/justin/.ssh/

# If .ssh doesn't exist, you'll need to create it. Skip this if the
# .ssh directory already exists.
mkdir /home/justin/.ssh
chown justin:justin /home/justin/.ssh
chmod 700 /home/justin/.ssh

# If authorized_keys doesn't exist, you'll need to create that
# too. Skip this if authorized_keys already exists.
touch /home/justin/.ssh/authorized_keys
chown justin:justin /home/justin/.ssh/authorized_keys
chmod 600 /home/justin/.ssh/authorized_keys

# Now that everything exists, stick your new key on the end
cat new_ssh_key.pub >> /home/justin/.ssh/authorized_keys

If that all worked correctly, you should now be able to ssh in as your new git user.

# If you can run  this on your computer (not the server) and it gives
# you a shell on the server, you have SSH access!
ssh justin@your-cool-server-ip

This simple setup gives you only one user account. If you want to share your git repos with someone else, or share with yourself on another computer, you can repeat adding SSH keys to the end of authorized_keys as many times as you like. If you do add other people this way, just keep in mind that there's only one user account from the server's point of view, so all the repos are shared.

Install Git

You don't need any fancy Git package here. You just need the normal Git package in the distro that you're working on installed.

On Ubuntu, this meant running.

apt install git

You know you're done if you can run git.

git --version
git version 2.36.0

Believe it or not, you now have a functioning Git server. All you need is a server with Git installed, and a user that can log into that a server over SSH.

How do you use your new Git server?

Creating a new repository

To create a new repo, you ssh in and run git init. Since nobody is actually working on the repository directly on the server, you'll generally want to create a "bare" repo. Bare repos are basically just the .git directory, they don't have a checked out working copy of the repo.

# Use ssh to connect to your server
ssh justin@your-cool-server-ip
# Then run git init on the server (in the ssh session)
git init --bare my-awesome-project.git

You can now clone your repo and do anything that you might have done with it if it were hosted elsewhere.

# The justin@your-cool-server-ip part here is the same username and
# hostname you'd call ssh with to login.
#
# Anything after the colon (:) is relative to your home directory on
# the server.
git clone justin@your-cool-server-ip:my-awesome-project.git

All of your normal Git stuff using your new Git server should just work!

Where can I learn more?

The best source that I found explaining how to do this was in an online book called Pro Git. It has a chapter on hosting your own Git server, and goes into much more detail on the setup and various options than I have in this article.

What's missing, and what next steps did I take?

For my own Git server, I didn't stop here.

I also have plans for the future.

I'm probably missing a lot when it comes to keeping my server running reliably, making it easy to make changes, scaling, and all sorts of other things that I still don't know about. Operations and site reliability engineering are their own massive discipline. I'm a developer primarily, doing ops badly, and that's OK. One of the great things of being small web scale is that it only needs to support my own needs.

I chose to start hosting my own Git server because I wanted to learn from it, I wanted to control my own data, and I enjoy trying out this sort of thing. It's obviously much more work and much more manual than signing up to some managed service. But it's been working well for me, and I'm having fun. I hope that if you try it out, you also learn a lot and have fun doing so.


If you'd like to share this article on social media, please use this link: https://www.worthe-it.co.za/blog/2022-06-10-how-to-train-your-git-server.html

Copy link to clipboard

Tags: blog, git, linux, shell-script


Support

If you get value from these blog articles, consider supporting me on Patreon. Support via Patreon helps to cover hosting, buying computer stuff, and will allow me to spend more time writing articles and open source software.


Related Articles

Automated Syncing with Git

I wanted Dropbox-style syncing of my notes between my computers. However, rather than actually using Dropbox, I wanted to keep my notes in a Git repo so that I can manage it the same way that I manage code that I write. This article shows how I achieved this using Git Sync and Systemd.

The Fundamentals of Version Control

In this article, I aim to explain what version control is, and the core concepts that you're likely to encounter in any version control system.