Shrugs: A Self Hosted Git SSH Server

2 minute read

shrugs is an Apache licensed self hosted git server available as a docker container written in Erlang and Rust.

Sometimes you just want to host some local changes before publishing to the cloud, using a simple git server than can easily run on something as small as a Raspberry PI.

Quick Start

You can run shrugs in a docker container with:

docker run \
  --name shrugs \
  -d \
  -p 22022:22 \
  ghcr.io/shortishly/shrugs

The container supports both amd64 and arm64 architectures.

Authentication

Copy your authorized_keys into the container for authentication:

docker cp ~/.ssh/authorized_keys shrugs:/users

Or copy the public key of individual users:

docker cp bob.pub shrugs:/users
docker cp alice.pub shrugs:/users

New keys (“*.pub” or “authorized_keys”) in the users directory will be picked up every 5 seconds.

Push

Push a repository into shrugs with:

mkdir demo
cd demo
git init .
echo "world" > hello.txt
git add hello.txt     
git commit --message='demo'
git branch -M main
git remote add origin ssh://localhost:22022/demo
git push --set-upstream origin main

A new repository will be automatically created (with git init --bare) to receive your changes, when pushing a new repository into shrugs.

Clone

Clone the demo repository as abc:

git clone ssh://localhost:22022/demo abc

Add some more content and push to the existing repository:

cd abc
echo "God’s Own Country" > yorkshire.txt
git add yorkshire.txt
git commit --message='home'
git push origin main

ls

To list (ls) the repositories stored in shrugs:

$ ssh -p 22022 localhost ls
demo

~/.ssh/config

With the addition of a host entry for shrugs in your .ssh/config:

host shrugs
     hostname localhost
     checkhostip no
     stricthostkeychecking no
     loglevel QUIET
     port 22022

Results in a bit less typing:

$ ssh shrugs ls
demo

$ git clone ssh://shrugs/demo
Cloning into 'demo'...
remote: Enumerating objects: 6, done.
remote: Counting objects: 100% (6/6), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 6 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (6/6), 466 bytes | 155.00 KiB/s, done.

$ cd demo
$ git remote -v
origin ssh://shrugs/demo (fetch)
origin ssh://shrugs/demo (push)

compose.yaml

An example compose.yaml with volume mounts for /repos (git repository storage), /etc/ssh (shrugs ssh host key), and /users (user public keys).

---
services:
  shrugs:
    image:
      ${SHRUGS_IMAGE:-ghcr.io/shortishly/shrugs:${SHRUGS_VERSION:-latest}}
    ports:
      - 22022:22
    pull_policy:
      ${PULL_POLICY:-always}
    volumes:
      - repos:/repos
      - host_keys:/etc/ssh
      - user_keys:/users
volumes:
  repos:
    driver: local
  host_keys:
    driver: local
  user_keys:
    driver: local

With the above you can copy keys with docker compose cp rather than docker cp:

docker compose cp bob.pub shrugs:/users
docker compose cp alice.pub shrugs:/users

Environment

The following environment variables can be used for configuration:

Variable Default Description
SHRUGS_SSHD_PORT 22 Incoming SSH connections on this port
SHRUGS_AUTHENTICATION_ENABLED true “false” will disable user authentication
SHRUGS_SYSTEM_DIR /etc/ssh This directory to find the host key
SHRUGS_USER_DIR /users This directory to find authorized user keys
SHRUGS_REPO_DIR /repos This directory to store git repositories
SHRUGS_BIN_DIR /bin This directory to find the git executable
SHRUGS_WATCH_TIMEOUT 5000 Check the repo dir every 5000ms for new user keys
SHRUGS_INITIAL_BRANCH main Initial branch name used with git –init –bare

Debug

The following environment variables can be used to enable debug logging:

Variable Default Description
SHRUGS_KEY_STORE_TRACE false Enables logging options from the key store
SHRUGS_SSH_DAEMON_TRACE false Enables logging of the SSH daemon
SHRUGS_USERS_TRACE false Enables logging of the users subsystem