Setting Up a Git Server with SSH
Git and SSH integrate seamlessly for version control infrastructure. An SSH-based Git server works well for small teams where all members are trusted and have administrator-level access to all repositories. This approach is straightforward to deploy, but lacks fine-grained access control.
For teams that need role-based repository access or audit trails, consider dedicated tools like Gitolite, Forgejo, or hosted solutions like GitHub/GitLab instead.
Server-Side Configuration
Log into your Git server with an account that has sudo/root privileges.
Install Git:
sudo dnf install git
Create a dedicated Git user:
sudo useradd -m -d /home/git -s /usr/sbin/nologin git
Restrict the git user to Git operations only by setting the shell to nologin or git-shell. If using git-shell, add it to /etc/shells first to avoid “invalid shell” errors:
echo /usr/bin/git-shell | sudo tee -a /etc/shells
sudo usermod -s /usr/bin/git-shell git
Create the git-shell commands directory (required for git-shell to function):
sudo mkdir -p /home/git/git-shell-commands
sudo chown git:git /home/git/git-shell-commands
sudo chmod 755 /home/git/git-shell-commands
Set up SSH key access:
On your local machine, generate an SSH key if you don’t have one:
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -C "your-email@example.com"
Copy your public key to the server:
ssh-copy-id -i ~/.ssh/id_ed25519.pub git@example.org
If ssh-copy-id isn’t available, manually append your key:
cat ~/.ssh/id_ed25519.pub | ssh username@example.org "sudo tee -a /home/git/.ssh/authorized_keys"
sudo chmod 600 /home/git/.ssh/authorized_keys
sudo chown git:git /home/git/.ssh/authorized_keys
Creating Repositories
On the server, create a bare repository (contains only version control data, no working directory):
sudo su - git -s /bin/bash
mkdir -p repos/myproject.git
cd repos/myproject.git
git init --bare
The --bare flag creates a repository suitable for receiving pushes from multiple users.
Initial Setup on Client
On your local machine, initialize a new project:
mkdir myproject
cd myproject
git init
touch README.md
git add README.md
git commit -m "Initial commit"
git remote add origin ssh://git@example.org/home/git/repos/myproject.git
git push -u origin main
For subsequent work:
git clone ssh://git@example.org/home/git/repos/myproject.git
cd myproject
git pull
# Make changes
git commit -am "Update feature X"
git push
Git Server Behind a Gateway (Port-Forwarded)
When your Git server is inside a private network accessed through a gateway with port forwarding (e.g., port 22111 on gate.example.org forwards to vm111:22), the setup is nearly identical—only the SSH connection details change.
Server-side setup is unchanged, but configure using the gateway:
ssh username@gate.example.org -p 22111
# Then follow the steps above identically
On the client, use the gateway address and forwarded port in your remote URL:
git remote add origin ssh://git@gate.example.org:22111/home/git/repos/myproject.git
git push -u origin main
When cloning:
git clone ssh://git@gate.example.org:22111/home/git/repos/myproject.git
Important Considerations
SSH Key Types: Use Ed25519 keys (ssh-keygen -t ed25519) for better security and performance than older RSA keys. Ensure your SSH client supports them (all modern clients do).
Repository Paths: Use absolute paths in remote URLs (/home/git/repos/myproject.git) rather than tilde expansion (~/repos/myproject.git), which can cause confusion with different shell contexts.
File Permissions: Ensure the git user owns all repositories and the .ssh directory. Incorrect permissions will silently fail during push/pull operations.
Backup Keys: Keep your SSH private keys backed up securely. Loss of the key means loss of access.
Multiple Users: Each user adds their public key to /home/git/.ssh/authorized_keys. All users authenticate as the git system user but are differentiated by their SSH keys. For per-repository access control or user attribution, migrate to Gitolite or similar tools.
Monitoring: Enable SSH logging to audit repository access:
sudo journalctl -u sshd -f
This basic SSH Git server works well for small teams or internal CI/CD systems but scales poorly beyond a handful of users. Plan migrations to more sophisticated tools as your infrastructure grows.

hello,
thank you for your useful article.
can i use this in linux cent os 5.4?
Hello. I haven’t try it on cent os 5.4. I make it run on Fedora 11. But it should work. You can have a try ;)
As far as I know, you should install git by yourself since git is not in it’s repository.
git isn’t in RHEL or CentOS’s repository. But the community supported EPEL has git. Users of CentOS or RHEL can use it to install git:
https://fedoraproject.org/wiki/EPEL
Articles like these put the consumer in the driver seat-very improatnt.
Thanks a lot!
hi,
when I changed the shell to: /usr/bin/git-shell
I wasn’t able to push anymore so I restored it to /bin/bash
OS: Fedora 14
@Slavi,
Thanks for the information. I have marked it in the post.
@Slavi and @Zhiqiang Ma,
The problem isn’t really with Fedora.
I was setting up a private Git repository on a Debian server yesterday and experienced the same problem. After changing the shell from bash to git-shell I wasn’t able to push anymore too. But looking at /var/log/auth.log I noticed something like: “user ‘git’ has invalid shell, rejected”.
Googling around I found that you have to append the line “/usr/bin/git-shell” to the /etc/shells file. Doing that I was able to push again, this time using the restricted Git shell.
Great and thanks for your solution to this!
I update the original post to contain this tips.
Hi,
Sadly, gitosis is unmaintained and unsupported. The regular folks on the IRC channel (#git on freenode) constantly have to tell people this, and point them to gitolite, which *is* maintained, supported, and has lots of documentation. And then they have to migrate.
Even though gitolite also comes with amigration guide, in the interests of letting people avoid this needless step if they haven’t yet started at all, may I request you change the links above to refer to gitolite. If you’re looking for a tutorial, http://sites.google.com/site/senawario/home/gitolite-tutorial is good. There are many others too, I’m sure.
PS: I’m the gitolite author, so this may be biased, but if you hang around on #git you’ll see there are many others who use it and happily recommend it, so I feel reasonably “not biased” :-)
Hi Sitaram,
Thanks for your suggestion. It is not biased at all—I know gitosis is not maintained now and gitolite seems do the work (and better through continuous development) that gitosis did.
I will edit this post and suggest gitolite to the readers.
BTW: thanks for your work on gitolite which give us a good choice beside gitosis.
Thanks for the post. Wish I could have found it few hours back.
I missed “git init” on local machine and I was getting error (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).
Now I could setup my repositories.
-lb
Pleasure to know this post helps. Enjoy.
Thanks for the tutorial!
Leave out the part about git-shell. If you do it as written, it will mess you up in subsequent steps. The git-shell is not likely intended to be used as a login shell. If you change the login shell from its default (typically /bin/bash) to /usr/bin/git-shell, you will no longer be able to log into the server as the git user and will be unable to complete the subsequent steps which require logging in or su’ing to the git user.
Thanks for a very helpful tutorial. There are also some instructions on setting up a git server on Ubuntu using the apt-get installer at coderatlarge.net/howto/setting-git-server-linux
guide fails for me
“fatal: couldn’t not switch to..”
You can change user shell either at creation time with adduser -s /path/to/git-shell
or by using usermod -s /path/to/git-shell gituser. Hand editing of /etc/passwd should be avoided.
Good tip! Thanks for the suggestion. I have updated the post suggesting using usermod.
# usermod -s /usr/bin/git-shell git
usermod: no changes
and then
fatal: Interactive git shell is not enabled.
hint: ~/git-shell-commands should exist and have read and execute access.
Got this error and solution is perhaps with permissions [1] but cannot yet understand which permissions, ideas?
[1] http://serverfault.com/questions/285324/git-shell-not-enabled
What about:
$ chmod 755 ~/git-shell-commands
Hi H,
I had a similar problem on Fedora 13, and found that it was an SeLinux issue. The fix was:
sudo chcon -t shell_exec_t /usr/bin/git-shell
for selinux to allow it to run as a shell.
You can check with:
ls -lhZ /usr/bin/git-shell
and see if it has the bin_t or shell_exec_t label.
-timrc
Ok.. in your Tutorial..
First you changed the default shell to git-shell and then you created a new directory with mkdir?! Are you sure that it works like that?
This is a bug. Fixed now.
thanks
this tutorial really helped me
im using cent os
your guide is good
Why the hell do you specifie uid while creating it ?
A good question but not asked in a very good way.
There are lots possible reasons. For us, the reason is to make the id of `git` special so that you can identify which users in one of our system are special ones (like the git account for providing service only and not login should be allowed) rather than normal users.
Thanks, the /etc/shells tip saved my day ;-)
Great to know this!
Hey
thanks for the post, I almost have it working…
But, Ive discovered that git-shell is not that restricted as it seems.
It has access to any folder on the system.
The /etc/passwd file of my server looks like:
git:x:1002:1002::/var/www/public-git-repos:/usr/bin/git-shell
and from the local machine I can do
git clone ssh://git@..../var/www/public-git-repos/repo1
and even
git clone ssh://git@..../~/repo1
BUT I can clone ANY repository on my server!
# knowing absolute path i can access any git repo in the machine
git clone ssh://git@..../var/very-private-files/git-repo/
this at first doesnt seem a problem, its very unlikely anyone guessing an repo full path. but im worring
Is there any way to limit the access to only home folder of the git user?
thanks in advance!
Hi Carlos,
git over ssh is truly with less access limitation.
You may take a look at http://www.fclose.com/5323/how-to-set-up-gitolite-git-server-a-ten-minute-tutorial/ for using Gitolite. It is not complex to set up and will give you better access control over repositories, branches, users and etc.
Many many thanks man,
I’ve readed gitosis was discontinued and (dont know why) I thought the git-shell was the only alternative… didn’t found anything about gitolite but I think it fits my needs. Im going to give it a try!
Thanks again :)
My pleasure that it helps. gitolite is great. I use it on my own git server and it works like a charm.
Gitolite is great, I second that.
Now I have it working, configured and behaviouring exactly as I wanted,
Thanks again Eric
regards
Nice to know that it is working for you. I am glad it helped. Enjoy!
Thank you very much, it is really helpful.
How cloning as other user?
in ssh exist -i
ssh -i ~/.ssh/some_key server
how get and git push and specyfic key?
You can use the “method two” in http://ask.systutorials.com/2138/how-to-choose-the-key-used-by-ssh-for-a-specific-host
This article is still easy and helpful.
Thank you all guys for your efforts.