Harness the Combinatoric Power of Command-Line Tools and Utilities
Run Your Own Git Remote with SSH
Published September 1, 2026
Introduction
You don’t need a hosting service to share code with your team or back up your work. A plain Linux server and SSH can do the job. Your server, your repositories, no third party in the middle. And when the big hosting providers have a rough day, which they sometimes do, your remote keeps working.
Before you start, set your expectations. This gives you a place to push and pull code. That’s it. You won’t get a website, pull requests, issues, or automated builds. If you need those, a hosted service is still the right tool. But if you just want a shared remote you control, you can set one up in a matter of minutes.
What You need
To complete this tutorial, you need:
- A Linux server you can already reach over SSH, with access to configure users and services.
- Your public SSH key on the machine you’ll push from. If you don’t have a key yet, GitHub’s guide to generating one works fine no matter where you plan to use it.
Create a git user and repositories on the remote machine
You’re going to create a dedicated git user and an empty repository on the remote machine. A remote repository should be “bare,” which means it has no working copy of the files. It only stores the history that people push and pull. Trying to push to a normal repository with a working copy causes problems, so bare is what you want on a server.
Log in to your Linux server over SSH with your regular user.
Make a dedicated account that owns the repositories. A separate user keeps your repositories tidy and limits the damage if a key ever leaks. Later, you’ll ensure that nobody can log in as the git user to poke around the system. You’ll make sure they can only push and pull.
Create the account with no password, which blocks password logins right away:
sudo adduser --disabled-password --gecos "" gitThis creates a normal user named git with a home directory at /home/git. You’ll use that home directory in the next steps.
Create a folder to hold your repositories, owned by the git user:
sudo -u git mkdir -p /home/git/reposNow create your first repository.
sudo -u git git init --bare /home/git/repos/project.gitThe .git suffix on the folder name is a common convention for bare repositories. It’s not required, but it makes them easy to spot.
Add SSH keys so people can authenticate.
People will connect using their SSH keys, so the server needs to know which keys to trust. Those go in a file called authorized_keys inside the git user’s .ssh folder.
Set up the folder and file with the right permissions. First, create the folder itsself:
sudo -u git mkdir -p /home/git/.sshThen apply permissions, giving the git user full access:
sudo -u git chmod 700 /home/git/.sshThen create the authorized_keys folder:
sudo -u git touch /home/git/.ssh/authorized_keysFinally, set permissions so the git user can read and write to the file:
sudo -u git chmod 600 /home/git/.ssh/authorized_keysSSH is picky about these permissions. If they’re too open, SSH won’t use the file, so don’t skip the chmod steps.
Now add a public key to the file. Grab the contents of your .pub key file and append it to authorized_keys. For example, if your public key is id_rsa.pub, run the following command:
cat ~/.ssh/id_rsa.pub | sudo -u git tee -a /home/git/.ssh/authorized_keysEach line in the authorized_keys file is one public key. If you want more people to connect, you’ll have to get their keys and add them.
Typing keys by hand gets old once you have a few people to add. GitHub can help here. Every GitHub user’s public keys are available at a URL based on their username. Visit https://github.com/{username}.keys in your browser, swap in a real username, and you’ll see that user’s public keys.
You can use that to script the whole thing. Start with a text file of GitHub usernames, one per line. Call it github-users.txt:
alice
bob
carol
Then create a script that reads the file, fetches each person’s keys, and writes them all to authorized_keys:
#!/usr/bin/env bash
set -euo pipefail
USER_FILE="${1:-github-users.txt}"
GIT_HOME="/home/git"
AUTH_KEYS="$GIT_HOME/.ssh/authorized_keys"
TMP="$(mktemp)"
while read -r username || [ -n "$username" ]; do
[ -z "$username" ] && continue
case "$username" in \#*) continue ;; esac
curl -fsSL "https://github.com/${username}.keys" \
| sed "s/$/ github:${username}/" >> "$TMP"
done < "$USER_FILE"
sudo install -d -m 700 -o git -g git "$GIT_HOME/.ssh"
sudo install -m 600 -o git -g git "$TMP" "$AUTH_KEYS"
rm -f "$TMP"
The script tags each key with the GitHub username it came from, so you can tell whose key is whose later. It also sets the correct permissions and ownership for you.
This script replaces authorized_keys every time it runs. The username file is now the single source of truth. Don’t hand-edit authorized_keys after this, or your changes disappear the next time you run the script. To add or remove someone, edit github-users.txt and run it again.
Lock the git Account Down with git-shell
Right now the git user can log in and get a full shell. That means anyone whose key is in authorized_keys can run any command on your server, not just Git commands. That’s more access than you want to hand out.
Git ships with a tool called git-shell that fixes this. It lets people run Git commands over SSH but blocks everything else. No real shell, no poking around.
Find where git-shell lives, add it to the list of valid login shells, and set it as the git user’s shell:
which git-shell | sudo tee -a /etc/shellssudo chsh git -s "$(which git-shell)"Now the git account can only move git data in and out.
From the machine you’ll push from, try connecting over SSH with the git user:
ssh git@serverInstead of a prompt, you’ll receive a message like the following:
fatal: Interactive git shell is not enabled.
Connection to server closed.
That message verifies you can’t log in with this user.
Push Your First Repository
To push code to your remote server, add it as a remote on your project.
Navigate to your project and set up git if you haven’t already:
cd /path/to/projectInitialize the repository:
git initAdd files to commit:
git add .Then commit the files:
git commit -m "initial commit"Now point your project at the server by adding a remote. The path is relative to the git user’s home directory, so repos/project.git finds the bare repository you created:
git remote add origin git@server:repos/project.gitPush your changes:
git push -u origin mainYour history is now on your own server. The -u flag sets it as the default remote, so from now on you can just run git push and git pull.
Clone Your Repository on Another Machine
The whole point of a remote is that more than one person, or more than one machine, can use it. Anyone with a trusted key clones the repository the same way:
git clone git@server:repos/project.gitThat pulls down a working copy they can commit to and push back.
When you have another project you want to push to your remote server, create another bare repository on the remote and push your code to it. Log in to the server with your regular account that has sudo access, and run the git init command again with a new name:
sudo -u git git init --bare /home/git/repos/another-project.gitThen push to it the same way you pushed the first one, using another-project.git as the path.
Consider backing up the repositories on your remote server. Clones on people’s machines hold the history too, but don’t count on that as a real backup plan. Set up something that copies /home/git/repos somewhere safe on a schedule.
Conclusion
Using an SSH-based Git remote has some tradeoffs. There’s no web interface, no pull requests, no issue tracking, no automated builds, and no granular user access. For a personal project or a small team that just needs a shared place to push code, this is a quick low-tech solution that works well, especially if a hosted provider is offline.