Setting up my private git server
Worth the pay off trust me!
I recently rented an ubuntu VM with a public IP and finally got the chance, without supervision, to architect what I wanted my little piece of processing power to do
So I wrote down what I needed/wanted
- A portfolio website - needed
- A blog website - wanted
- A sandbox - needed
- A scalable system - desperately wanted
- An intermediary testing/delivery pipeline - needed
And all roads led back to Docker, more specifically, docker compose with plans on switching to Kubernetes the moment I had more than one VM
The next step was figuring out what to do. I needed a load balancer, not to deal with load balancing ironically enough, but redirecting traffic from sub domains to their respective containers, I needed a pipeline of sorts where I have full control on what my users end up getting, and lastly I needed a production and development environment with very minimal extra configuration
Now I could, host my code on GitHub, create a CI/CD pipeline with integration tests that publishes the images to a docker hub, use GitHub as the secret manager for production images and set everything up nicely with an organization worth biliions of dollars watching my back
But where’s the fun in that
I built my own private git server
That’s right! I built a private git server with hooks, Docker compose, hopes and dreams, and I’ve loved every moment of it. I will focus on explaining setting up the architecture and in future blogs talk about my individual repos/images - that’s right every repo becomes an image
Repo is slang for repository chat
Setting up your private repo
Firewall
The first thing I did was to install a firewall. I used ufw. It’s called the “Uncomplicated Firewall” and I’ll be honest, it felt that way. It was intuitive to use and there wasn’t any hiccup along the way
Now the last thing you want to do is set up a firewall and then realize you’re blocked from your VM the next time you ssh in, so you probably want this as a script, but here’s a run down of the commands I used
sudo apt update
sudo apt install ufw
Install ufw
sudo ufw allow 22/tcp
sudo ufw allow 443/tcp
Allow SSH and HTTPS through
sudo ufw enable
Enable Firewall
That’s it I think, you could search on their page for more commands and this
sudo ufw status verbose
shows the beauty you just created
Install git
sudo apt install git
It’s kind of expected but you don’t want to know how long it took me to figure this part out
Creating a git user
The next step was creating a git user, he’ll be the one responsible for everything git, including cloning - especially cloning
Here’s are the steps
sudo groupadd git
Create a git
group
sudo useradd -m -s /usr/bin/git-shell -g git --disabled-password git
Create a git
user, locked to the git shell, and without a password
The git shell’s a sanity check to make sure your git user doesn’t do anything(like running a script) other than git stuffs.
If you’re still paranoid - like me -, you could edit your /etc/ssh/sshd_config
to include this block
Match User git
PasswordAuthentication no
AuthenticationMethods publickey
This prevents password login from the git user - even if they have a password
Enabling SSH access to git user
This part’s a bit messy, usually you’d sudo -iu git
to become the git user,
but the git user can only use git commands so that won’t help
Here’s what I did
# As root, cd to git's home directory
cd /home/git
# Then create a .ssh folder
mkdir .ssh
# cd to the .ssh folder
cd .ssh
# Create a file for storing the public keys
touch authorized_keys
# Set folder permissions
sudo chmod 700 /home/git/.ssh
# Set file permissions
sudo chmod 600 /home/git/.ssh/authorized_keys
# Ensure git owns it
sudo chown -R git:git /home/git/.ssh
And that’s it!
Create a public/private ssh key pair
The next step is to create a public/private key on your local laptop for ssh connection
Here’s what I used, and here’s where I got the code
ssh-keygen -t ed25519 -C "your_email@example.com"
The next part’s more aesthetic, but I’ll be assuming you all are fancy individuals and I’m also too lazy to assume otherwise
In your config file located at ~/.ssh
- you’ll have to create one if you don’t have it -
you’ll want to add this block
Host git-server
HostName ip.number.goes.here
User git
IdentityFile absolute/path/to/private/key/goes/here
IdentitiesOnly yes
You can change the Host
name from git-server
to whatever feels right to you,
the Hostname
is the IP of your git server and the IdentityFile
is the
absolute path to your newly created private key(the one without .pub)
Once you create the config file, you’ll also want to copy the content of the public part of the pair of keys you just created and move right back into your server - fingers crossed you aren’t locked out
Enabling access to SSH
cd /home/git/.ssh
Boo! Jumpscare haha
The next part is getting back to your git user .ssh
directory
restrict content-from-public-key-here
and then updating the authorized_keys
file with restrict
followed by a
single space and the content of the public file you copied earlier
Creating a repo
With all that out of the way, we can start with the cool parts
I’ll be using /opt/repos
to store my repos, but honestly I think you should be
good to create a folder in /home/git
for your repos
Once you decide where to keep your repos, the next part is creating one!
Here’s my current system
mkdir my-project.git
Create the repo directory(my-project
)
sudo -u git git init --bare my-project.git
Initialize the folder as a bare git repo
chown -R git:git my-project.git
Ensure the repo is owned by the git user - despite the shell witchery above, yes I’m paranoid
chmod -R 770 my-project.git
Add the right permissions for the git repo (full permissions for only user and group)
And that’s it
To be fair, initially I only created the directory and then ran git init --bare
but along the way it morphed into this
monstrosity.
Feel free to copy if you’d like to automate the process, it’s the same
thing with a lot more checks and redundant code
Clone repo
And now for the moment of truth, if everything worked, and I recounted correctly, this single command should get your repo right into your local computer
git clone git@git-server:/opt/repos/my-project.git
git-server
was my fancy Host
name, you’ll have to replace it with what you
called it in the config
file earlier if you decided to be even more fancy, and
/opt/repos/my-project.git
is a dummy stapler for the absolute directory to
your previously created git repo
Author’s Notes
-
Bare repositories are built different. It sounds like a joke but I mean it, they look something like this
root@localhost:~# ls /opt/repos/blog.git/ branches config description HEAD hooks index info logs objects refs
You’ll have to clone the repo to get the actual code, currently I’ve only messed with the
hooks
andbranches
folders but that’s for another blog -
I wrote this blog mostly from recollection and going through my chatgpt history, my brain may have completely shut down some hours of debugging to protect me haha, if there’s any error or pain point following the blog, join my little community and I’ll do my best to help you get through it!