aboutsummaryrefslogtreecommitdiff

gitreef

A minimal Git over SSH server implemented in Fish shell.

gitreef is designed for people who do not need a full Git hosting platform — no GUI, no databases, no management overhead. It provides only the essentials: SSH access, user and repository management, and basic access control.

As a result, it is small, secure, and fast, using under 10 MB of RAM, so it runs comfortably on modest hardware such as a Raspberry Pi.

Features

  • Dockerized and easy to deploy
  • Simple configuration via command line or Docker Compose
  • Minimal dependencies: Git, SSH, Fish, Tini, Sudo
  • Built-in user and repository management
  • Basic ACL system with per-user read/write permissions
  • Logging

Security

Protecting repositories from unauthorized access is a top priority. The server applies several hardening and sandboxing measures:

  • Minimal Alpine base image with only essential tools installed
  • Public-key authentication only (no passwords)
  • No TTY and no interactive shell logins
  • All Git commands are sanitized and validated
  • Repositories are stored under /srv/repos and cannot access paths outside that directory
  • A per-user ACL file checks permissions for each operation
  • Logins for root and the git user are disabled

Examples

Command Line

docker run --rm -p "2222:22" jarlucmat/gitreef \
  -u "user1:ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbm
lzdHAyNTYAAABBBPsl91WPAT8aWwZ6y5WAfXU9PoHzxJ3YG9uFgSmlGQr2HwV+gL/XaTBJ4Brj+pa+R7tfYEBMi+7Navx/ZsEmr9E= mj@xps15" \
  -r "/repo1.git;user1:w"

Docker Compose

services:
  gitreef:
    image: jarlucmat/gitreef
    ports:
      - "2222:22"
    environment:
      # Note: variable names cannot contain dashes, but values can.
      # UID/GID of the user that owns all repositories
      - GIT_UID=1000
      - GIT_GID=1000

      # Users in the form USER_<id>=<username>:<ssh-public-key>
      - USER_user1=user1:ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPsl91WPAT8aWwZ6y5WAfXU9PoHzxJ3YG9uFgSmlGQr2HwV+gL/XaTBJ4Brj+pa+R7tfYEBMi+7Navx/ZsEmr9E= mj@xps15
      - USER_user2=user2:ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPsl91WPAT8aWwZ6y5WAfXU9PoHzxJ3YG9uFgSmlGQr2HwV+gL/XaTBJ4Brj+pa+R7tfYEBMi+7Navx/ZsEmr9E= mj@xps15

      # Repositories in the form REPO_<id>=<path>;<user>:<perm>[;<user2>:<perm>;...]
      # Permissions:
      #   r = read
      #   w = write
      # A user without a permission flag has read access by default.
      - REPO_repo1=/repo1.git;user1
      - REPO_repo2=/repo2.git;user2:w
      - REPO_repo3=/repo3.git;user1:r;user2:w

    volumes:
      # Basic volumes that should be mapped
      - ./ssh:/var/ssh
      - ./repos:/srv/repos

Notes

Any SSH key type supported by Git and your base system can be used. ACL files and repository definitions are recreated automatically on container restart.

License

GPLv3 — © 2026 Matthias Jaros