Setting Up Gitolite for SSH-Based Git Repositories
Gitolite provides fine-grained access control over Git repositories without the overhead of a full-featured platform. It uses SSH keys for authentication and handles per-user, per-repository, and even per-branch permissions through a simple configuration file. This guide covers a working installation on modern Linux distributions.
Prerequisites
Server:
- Linux (Ubuntu 20.04 LTS or later, Debian 11+, RHEL/Rocky 8+, Fedora 38+)
- Git installed
- SSH running (standard port 22)
- Unprivileged user with sudo access (or root, though running as unprivileged is safer)
Workstation:
- Linux, macOS, or WSL2
- SSH key pair (generate with
ssh-keygen -t ed25519if needed) - Git and SSH client
Quick Start
Set these variables before running commands:
GIT_SERVER=git.example.com
GIT_USER=git
ADMIN=$USER
ADMIN_KEY=$HOME/.ssh/id_ed25519.pub
Replace git.example.com with your actual server hostname or IP. Use Ed25519 keys if your workstation and server both support them (better than RSA for new setups).
Copy Your Public Key to the Server
Transfer your public key to the server:
scp $ADMIN_KEY $USER@$GIT_SERVER:/tmp/$ADMIN.pub
ssh $USER@$GIT_SERVER "chmod 644 /tmp/$ADMIN.pub"
Install Gitolite
SSH to the server and run the installation as the unprivileged user (or adapt if using root):
ssh $USER@$GIT_SERVER << 'EOFINSTALL'
sudo adduser --disabled-password --gecos '' $GIT_USER 2>/dev/null || true
sudo -u $GIT_USER bash << 'EOFGIT'
mkdir -p ~/bin
git clone https://github.com/sitaramc/gitolite /tmp/gitolite-src
/tmp/gitolite-src/install -to ~/bin
~/bin/gitolite setup -pk /tmp/$ADMIN.pub
EOFGIT
EOFINSTALL
This command:
- Creates the unprivileged
gituser - Clones gitolite from GitHub
- Installs gitolite to the user’s
~/bin - Initializes gitolite with your public key
You should see output confirming the creation of the gitolite-admin and testing repositories.
Verify the Installation
Clone the test repository:
git clone $GIT_USER@$GIT_SERVER:testing
cd testing
echo "test" > testfile.txt
git add testfile.txt
git commit -m "test commit"
git push
If this succeeds without permission errors, your server is ready.
Managing Repositories and Users
All administration happens through the gitolite-admin repository. Clone it on your workstation:
git clone $GIT_USER@$GIT_SERVER:gitolite-admin
cd gitolite-admin
The directory structure:
conf/gitolite.conf— All repository and permission ruleskeydir/— User SSH public keys (one file per user, namedusername.pub)
Adding a User
Copy the user’s public key to keydir/:
cp /path/to/alice.pub keydir/alice.pub
git add keydir/alice.pub
git commit -m "Add alice"
git push
Creating a Repository with Permissions
Edit conf/gitolite.conf and add:
repo my-project
RW+ = alice
RW = bob
R = charlie
Permission levels:
R— read-onlyRW— read and write (no force push or delete)RW+— read, write, force push, delete-— deny access
Commit and push:
git add conf/gitolite.conf
git commit -m "Add my-project repo with user permissions"
git push
The repository is created immediately on the server. Users can clone it:
git clone git@$GIT_SERVER:my-project
Branch-Level Access Control
Restrict write access to specific branches:
repo feature-work
RW+ refs/heads/feature/* = alice bob
RW refs/heads/main = alice
R refs/heads/main = bob charlie david
This grants:
aliceandbobfull control over feature branchesalicewrite access to mainbob,charlie, anddavidread-only access to main
Use regex patterns for flexible branch matching:
repo prod-code
RW+ refs/heads/release-.* = release-manager
RW refs/heads/main = developers
- refs/heads/main = qa-users
RW refs/heads/main = qa-users
(The deny rule - is evaluated first, so this grants qa-users read-only access despite the later RW.)
Managing User Access
Revoking Access
Remove a user’s key and update configuration:
rm keydir/alice.pub
# Update conf/gitolite.conf to remove alice from repos if needed
git add -A
git commit -m "Revoke alice"
git push
Updating a Key
When a user regenerates their SSH key:
cp /path/to/alice-new.pub keydir/alice.pub
git add keydir/alice.pub
git commit -m "Update alice SSH key"
git push
Using Groups
Define groups in conf/gitolite.conf to manage permissions at scale:
@developers = alice bob charlie
@leads = alice bob
@ops = david
repo all-projects
RW+ = @leads
RW = @developers
R = @ops
Groups can include other groups:
@backend = @developers david
@frontend = @developers eve
repo backend-code
RW+ = @backend
repo frontend-code
RW+ = @frontend
Checking Permissions
View all repositories and your access levels:
ssh $GIT_USER@$GIT_SERVER gitolite info
Output shows each repository and your permissions on it.
Check what a specific user can access:
ssh $GIT_USER@$GIT_SERVER gitolite access-info alice
Troubleshooting
“Permission denied (publickey)” when cloning:
- Verify your key filename in
keydir/matches your username (e.g.,alice.pubfor useralice) - Confirm you’re using the correct private key:
ssh-add -lto list loaded keys - Test SSH directly:
ssh -v git@$GIT_SERVERto see which key is being used
Repository doesn’t exist after pushing to gitolite-admin:
- Ensure
git pushcompleted without errors - SSH to the server and verify:
sudo -u $GIT_USER ls ~/repositories/ - Check for syntax errors in
conf/gitolite.conf:sudo -u $GIT_USER ~/bin/gitolite compile
Configuration changes not taking effect:
- Gitolite only reads config when you push to
gitolite-admin - Avoid editing files directly on the server
- Always commit and push changes from your workstation
SSH key not recognized after adding to keydir/:
- SSH caches known keys; restart SSH or add to a new key slot
- Verify the key content:
cat keydir/alice.pub(should start withssh-rsa,ssh-ed25519, etc.) - Check server-side logs:
sudo journalctl -u sshor equivalent
Advanced Features
Wild repositories allow users to create repositories matching a pattern:
repo my-project-[a-z0-9]*
C = @developers
RW+ = CREATOR
RW = @developers
Users can then push to any repository matching my-project-* on first push.
Post-receive hooks run after pushes. Create .git/hooks/post-receive in the server’s gitolite directory for notifications, CI/CD triggers, or backups.
Deploy keys allow CI/CD systems read-only access without a user account:
cp /path/to/ci-system.pub keydir/ci-deploy.pub
Then grant minimal permissions:
repo my-project
R = ci-deploy

Gitolite seems to be a lightweight Git server manage tool. It looks good. I am using GitLab, which look like a private GitHub.
GitLab is a piece of great software providing a Web interface for git repository management. Right, gitolite is only a authorization layer for git, which is strictly not a git hosting environment.
If you are interested, this post gives an introduction to how gitolite-like systems work: http://stackoverflow.com/questions/13318715/how-do-programs-like-gitolite-work/13320256#13320256
How to use Gitolite with port forwarding. For example, I use a server that is a local network and use port forwarding to login.
You can use the “Non-standard SSH port” tip on http://www.fclose.com/3358/howto-for-new-git-user/ .
Hello, I have been using this setup for installs on Centos 7. Without any problm.
Now I wanted to do the same on a new Rocky 8 server.
All goes well until I clone the testing(or gitolite-admin) repo. At this point I get a prompt asking for password.
git version 1.8 ( Centos7)
git version 2.3 (Rocky 8)
Is there a way to make that working in Rocky 8 ?
Thanks!