# Gitfish Welcome to **gitfish** — a simple, fast, memory-friendly, and secure GIT-over-SSH server for your repositories. The goal of this project is to provide a **minimal Git server** with no unnecessary features or management overhead. It’s designed for everyone who doesn’t need or want a fancy GUI or advanced functionality beyond the essentials. As a result, it’s **small, secure, fast**, and uses **under 10 MB of memory**, so it runs easily even on less powerful hardware like a **Raspberry Pi**. --- ## Features - 🐳 **Dockerized** - ⚙️ **Simple configuration** via command line or Docker Compose - 🚀 **Fast & secure**, with minimal dependencies: Git, SSH, Fish, Tini, Sudo - 👥 **Built-in user and repository management** - 🔐 **Basic ACL system** with per-user read/write permissions - 📜 **Logging** of all Git operations --- ## Security Keeping your repositories safe from unauthorized access is a top priority. This server applies multiple hardening and sandboxing measures, such as: - Minimal Alpine base image with only essential tools installed - Only **public-key authentication** (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 - Per-user **ACL file** checks permissions for each operation - **Root and “git” user logins are disabled** --- ## Examples ### Command Line ```sh docker run --rm -p "2222:22" jarlucmat/gitfish -u "user1:ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbm lzdHAyNTYAAABBBPsl91WPAT8aWwZ6y5WAfXU9PoHzxJ3YG9uFgSmlGQr2HwV+gL/XaTBJ4Brj+pa+R7tfYEBMi+7Navx/ZsEmr9E= mj@xps15" -r "/repo1.git;user1:w" ``` ### Docker Compose Docker Compose: ```yaml services: gitfish: image: jarlucmat/gitfish 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_=: - 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_=;:[;:;...] # 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 - ./log:/var/log ``` ## Notes You can use any SSH key type supported by Git and your base system. Logs are written to /var/log/git-run by default. ACL files and repository definitions are recreated automatically on container restart. ## License GPLv3 © 2025 Matthias Jaros