How to Self-Host a Git Server
This guide is a modified version of the git book instructions for Debian specifically.
It also includes setting up a cgit web front-end that allows you to view your git repositories conveniently on the web just like I do.
I'm assuming you already have a VPS with Debian installed and a domain purchased with proper DNS records pointing the git subdomain to your server IP. If not, you should research what all that means before continuing because you'll be unable to follow along.
Posted: Saturday May 30, 2026 2:45:23 PM
Setting up a Git Server
The very first thing to do is connect to your server, install git, create a git user, and set up ssh for remote access to that git user.
ssh root@example.com
apt install git
sudo adduser git
usermod -aG sudo git
su git
cd
mkdir .ssh && chmod 700 .ssh
touch .ssh/authorized_keys && chmod 600 .ssh/authorized_keys
To copy your home computer's ssh id to your server (assuming you have one generated), run this command:
ssh-copy-id git@example.com
Now let's create an example git repository and try to push from our home computer.
On your server, as the git user, run these commands to create a repo.
sudo mkdir /srv/git
cd /srv/git
sudo mkdir repo.git
cd repo.git
git init --bare
Ensure the repo (and really the entire git folder) is owned by the git user and group. Otherwise, git commands on your home computer will error.
chown -R git:git /srv/git
On your home computer, set up a git repo as well.
mkdir repo
cd repo
git init
git remote add origin git@example.com:/srv/git/repo.git
Make some changes. For example, create a file and try git push. It should work.
touch file.txt
git add .
git commit -m "changes"
git push origin main
The git user is no longer required to be a part of the sudo group. We just needed it for a few of the commands above. Remove it.
deluser git sudo
Preventing Shell Access
The final step is to prevent a remote login as git@example.com from acquiring a normal shell on the server.
This step isn't strictly necessary and can probably be skipped if you're the only one using git on your server.
First, check the location of the git shell. Then, append the output to /etc/shells.
which git-shell
vim /etc/shells
G
o
/usr/bin/git-shell
:wq
Now set the shell for the git user to git-shell.
sudo chsh git -s $(which git-shell)
Finally, prevent port forwarding by prepending this to each key in ~/.ssh/authorized_keys in the git user directory.
no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty
Attempting to login as git using ssh git@example.com should output an error such as this one and close the connection.
fatal: Interactive git shell is not enabled.
hint: ~/git-shell-commands should exist and have read and execute access.
Connection to example.com closed.
Perfect!
Next Steps
At this point, your git server is fully usable. You can begin to push, pull, etc. However, you might also want a front-end to browse your repositories and make them discoverable on the web.
How to Set up cgit for a Git Web Front-End
Install the necessary packages:
apt install nginx certbot fcgiwrap cgit
Generate a TLS certificate for your git domain and create a cron job to auto-renew it.
certbot certonly --standalone --register-unsafely-without-email -d git.example.com
crontab -e
Append this line to the file crontab opens:
0 0 1 * * certbot --nginx renew
Next, edit the nginx config. This is an example of what works for me. My config file is located at /etc/nginx/nginx.conf.
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen 443 ssl;
listen [::]:443 ssl;
ssl_certificate "/etc/letsencrypt/live/git.example.com/fullchain.pem";
ssl_certificate_key "/etc/letsencrypt/live/git.example.com/privkey.pem";
ssl_trusted_certificate "/etc/letsencrypt/live/git.example.com/chain.pem";
server_name git.example.com;
root /usr/share/cgit;
location ~* ^.+\.(css|js|png|ico)$ {
root /usr/share/cgit;
expires 30d;
}
location / {
try_files $uri @cgit;
}
location @cgit {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /usr/lib/cgit/cgit.cgi;
fastcgi_param PATH_INFO $uri;
fastcgi_param QUERY_STRING $args;
fastcgi_param HTTP_HOST $server_name;
fastcgi_pass unix:/run/fcgiwrap.socket;
}
}
}
Now it's time to edit the cgit config to make the front-end your own. Mine is located at /etc/cgitrc. Here's an example of my config:
#
# cgit config
# see cgitrc(5) for details
# copy your logo into /usr/share/cgit and change the file name here
logo=/bunny.webp
root-title=example
root-desc=a web front-end for my git repositories
favicon=
css=/cgit.css
# repository names
remove-suffix=1
clone-prefix=https://git.example.com
scan-path=/srv/git/
virtual-root=/
It's more than likely you will need to add the nginx user to the www-data group (root if you never created one). Otherwise, the front-end will display "502 Bad Gateway" instead of cgit.
Run this command to do so:
usermod -aG www-data <nginx-user>
It's time to restart nginx and check out the front-end. Use this command to restart it:
systemctl restart nginx
If you open git.example.com now, you might notice under "Owner" it says "git." To change this to your name, enter the following command on your server:
usermod -c "new_name" git
Conclusion
If you followed the steps, you now have a working self-hosted git server and read-only front-end to view and share your repositories. If you made it, I hope you agree this is a pretty simple setup and is definitely worth investing time into for many reasons.