Self-hosting a Git service: an easy way to more personal freedom
I'm a huge fan of self-hosting, which is the act of hosting the services you need and use by yourself, rather than use it from a third-party such as Google or Amazon. These "free" service providers often don't have your best interests in mind and finance themselves by brokering your personal information to interested advertisers, which is really a stab in the back for anyone looking for privacy.
When you self-host something, however, you take all responsibility and ownership to yourself, and as a result can have much larger control and flexibility on what you can do. I've done it extensively in the past (sadly, I currently can't for most of these services) and even posted a video on my Podcast talking about the subject:
Out of all the services I've self-hosted before (website, XMPP service, NAS, etc), Git probably would be the last one I'd even start to consider, since I always wanted my software to be as openly and freely shareable with as many people as possible, and there are so many code hosting out there with so many interesting collaboration features like Notabug or Codeberg.
However, recently I wanted to have an easy and quick way to sync my essays (such as this very one) as well as some code snippets and software projects across machines in my house, and didn't want to refer to a publicly accessible server on the internet just for this matter. Short of installing some sort of
rsync solution, I decided to starting researching how hard it would be to host my own git server. And it was much easier than I thought.
Sizing the perfect solution for your case
For starters, I started looking into the existing hostable Git servers across the many repositories that can accessed on the internet. GitLab can be self-hosted on your own premises. There is also Gitea, a relatively new player. Notabug uses Gogs.
I'm pretty sure these are all fantastic alternatives and can do the job pretty well. However, they all seemed a little too big for my simple use case of sharing and versioning code snippets and essays alongside myself only. And some solutions like GitLab can be pretty heavy (4GB RAM minimum, four-core CPU etc for a minimal deployment). These seem a little bit overkill for my rather simple use-case.
So what did I go for eventually? Just a barebones git server sitting on my raspberry pi. No web interface, no fancy database backend, just versioning and synchronization among a few machines in my network for as little resources as possible. Does that sound like your goal as well? Then follow on for how I did it.
Setting up the server
I was lucky to have found this comprehensive guide in Linuxize that was my main source of instructions in this task. The goal was not to have a full-fledged git server with many users and a neat web interface, but rather a simple, compact and light on resources solution using whatever I already had. Thankfully, the Linuxize guide fulfilled every aspect of it.
The solution involved a very clever use of commonly available server software like
sshd, which is used for both authentication and transporting of the content between the server and the client, much in the same way that
sftp works without being much of an "ftp" itself. The setup works with the following steps:
- Generate a new SSH RSA keypair to be used exclusively for git in the client computer.
- Create a new user named "git" on the server, which will be doing all the updating and merging of the repositories.
- Configure SSH in the client to allow you to log in as the git user in the server with your public SSH key.
- Create a repository and commit to it.
Step 1 - Create a new SSH keypair
This is the basic requirement for everyone that needs to do ssh the proper way (no passwords, only credentials). We begin by creating a new ssh RSA keypair with the
ssh-keygen -t rsa -b 4096 -C "firstname.lastname@example.org"
Once your keys are created (private key and a public key with a .pub extension), I recommend moving them both to your
~/.ssh directory for neatness:
mv id_rsa id_rsa.pub ~/.ssh # for security, make sure nobody else can see this directory. chmod 700 ~/.ssh
You'll use the public key later, so keep in mind where it is for now.
Step 2 - Set up the git user in the server
On the server side, create a new user called
git with no password via this command:
sudo useradd -r -m -U -d /home/git -s /bin/bash git
At first, this creation command sounds a little strange: how useful is it to have a user that does not even has a password? But the answer relates to security; that git user cannot be brute-forced remotely by anyone because there is no password, leaving only a credential-based remote login as the option (which is considered much safer).
Now is also the time to also install
git if your system doesn't have it (unlikely, but has to be checked):
sudo apt install git # for debian-based systems
And with this, the server preparations are complete. Yes, really. We will be returning to the server side too, but in the meantime, let's go back to the client side.
Step 3 - Configuring SSH on the client
You now have to configure ssh on the client to be able to log in and perform work on the server as the git user you created on Step 2. This step is missing from the Linuxize guide, and actually gave me a bit of trouble until I figured it out. So let's get to it.
To allow the remote logging in via ssh, first append the contents of your public key that you generated in Step 1 to a file named
~/.ssh/authorized_keys on the server, like this:
# copy id_rsa.pub from client to server, then on the server: cat id_rsa.pub >> ~/.ssh/authorized_keys
Now create a file on the client side called
~/.ssh/config and write the following content to it:
Host gitserver Hostname your_server's_ip_address User git IdentityFile /home/your_username/.ssh/id_rsa # or whatever you called your Private Key.
With that entry, you can now log into your server as the git user by issuing
ssh git@gitserver or even just
ssh gitserver. You can name the hostname as you like.
Now the final step is to create your first repository and commit to it.
Step 4 - Create a git repository and contribute to it.
Since SSH has been configured, we can now log into the server as the git user:
To create your first repository, run in the server:
git init --bare my_repo.git
Exit the shell (press Ctrl+D) and now on the client machine, clone that repository:
git clone git@gitserver:my_repo.git
Git might alert you that you've cloned an empty repository, but that's not a problem, since you're going to start contributing now.
Enter that directory and create some files:
cd my_repo touch myfirstfile
Now commit that file normally like you would in any other git server"
git add \* git commit -m "Testing my local git server" git push -u origin master
And voilà: your changes have been pushed to your git server! If you clone this repository from any machine now, that file you just committed will be there too.
If you want to include another user or machine as part of the "committers" of the repository, repeat steps 1 and 3 in the desired machine / user. You'll be able to start contributing normally from there as well.
So there you have it, you've successfully self-hosted your first service across your local network as a git server. Admittedly, this was much easier than it looks like at first, and for small private projects, it works very nicely. This also shows how flexible ssh is as a technology: it eliminated all the need to set up an HTTPS certificate and everything just to pass content along the network, in a manner similar to sFTP.
You can also use this functionality to "sync" small stuff as well between machines, but keep in mind that git was designed to handle text content primarily and that changed often (large static binaries like video would not be very useful).
Is this scalable? Probably not very much, if you want to make public your work, you're probably better off using something like Gogs or Gitea. But still it's possible to ditch Github and go completely local just for your private stuff.
Have you ever tried self-hosting your own git server before? How did you do it? Let me know in Mastodon!
This post marks my first installment into the #100DaysToOffload challenge, a blogging challenge first issued by Kev Quirk. Let's see how this will turn out!
Last updated on 01/28/21