1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
# 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, 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_<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
- ./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
|