Vấn đề: Muốn share code mà không muốn phụ thuộc dịch vụ bên ngoài
Mình làm việc với một team 3–4 người, dự án nội bộ, code không thể đẩy lên GitHub public vì có thông tin nhạy cảm. GitHub Private thì tốn phí hoặc bị giới hạn, còn GitLab self-hosted hay Gitea thì phải cài software, cấu hình database, nginx, HTTPS — đủ thứ trước khi push được dòng code đầu tiên.
Một buổi chiều nhìn VPS đang chạy ế, mình chợt nhớ ra: Git vốn là distributed version control. Không cần web UI fancy, không cần issue tracker — chỉ cần một chỗ để push/pull code giữa các thành viên. Git bare repository qua SSH chính là câu trả lời, và mình đã dùng cách này hơn một năm mà chưa gặp vấn đề gì.
Phân tích: Tại sao team nhỏ không cần Gitea hay GitHub?
Gitea hay GitHub giải quyết nhiều bài toán lớn: web UI, pull request, code review, CI/CD integration… Nhưng nếu team chỉ 2–5 người làm việc với nhau hàng ngày, những thứ đó là overkill.
Cài Gitea yêu cầu:
- Một binary chạy nền (hoặc Docker container)
- Database — SQLite cũng được, nhưng vẫn là thêm dependency
- Nginx reverse proxy + SSL certificate
- Quản lý user qua web UI, cập nhật phần mềm định kỳ
Với Git bare repository:
- Không cần cài thêm gì — Git đã có sẵn trên hầu hết Linux distro
- Xác thực qua SSH key — cái này team nào cũng dùng rồi
- Setup xong trong 10 phút
- Không có web service expose ra ngoài, tức là ít attack surface hơn
Trade-off rõ ràng: bạn mất web UI và pull request. Nhưng với team nhỏ làm việc trực tiếp với nhau, review qua chat và git diff là đủ.
Các cách giải quyết khác
Trước khi đi vào hướng dẫn, điểm qua nhanh các option để bạn chọn đúng thứ mình cần:
- GitHub/GitLab.com — Tiện nhưng code nằm ở bên thứ ba. Không phù hợp nếu dự án có yêu cầu về data sovereignty hoặc bảo mật thông tin nội bộ.
- Gitea/Gogs self-hosted — Web UI đẹp, giống GitHub, nhưng cần cài đặt và bảo trì lâu dài. Thích hợp khi team lớn hơn hoặc cần web interface thực sự.
- Git bare repo qua SSH — Lightweight nhất, không có web UI, nhưng hoàn toàn đủ dùng cho team nhỏ. Đây là cách mình sẽ hướng dẫn chi tiết dưới đây.
Cách tốt nhất: Thiết lập Git bare repository qua SSH
Chuẩn bị
Bạn cần có:
- Một Linux server — VPS, server nội bộ, hay kể cả Raspberry Pi đều được
- SSH access vào server đó
- Git đã được cài (
sudo apt install gitnếu chưa có)
Bước 1: Tạo user git riêng trên server
Best practice là tạo một user riêng cho Git, không dùng root hay user cá nhân:
sudo adduser git
sudo mkdir -p /home/git/.ssh
sudo touch /home/git/.ssh/authorized_keys
sudo chmod 700 /home/git/.ssh
sudo chmod 600 /home/git/.ssh/authorized_keys
sudo chown -R git:git /home/git/.ssh
Bước 2: Thêm SSH public key của từng thành viên
Mỗi thành viên gửi SSH public key của họ (thường ở ~/.ssh/id_ed25519.pub). Thêm từng key vào file authorized_keys trên server:
# Chạy trên server với quyền sudo
sudo bash -c 'echo "ssh-ed25519 AAAAC3Nza... thanh_vien_1@laptop" >> /home/git/.ssh/authorized_keys'
sudo bash -c 'echo "ssh-ed25519 AAAAC3Nza... thanh_vien_2@workstation" >> /home/git/.ssh/authorized_keys'
Hoặc nếu thành viên có thể SSH tạm vào server, họ tự thêm key bằng lệnh sau từ máy của họ:
ssh-copy-id git@your-server-ip
Bước 3: Tạo bare repository
Bare repository là repo không có working tree — chỉ chứa dữ liệu Git thuần túy, tương đương thư mục .git bên trong repo bình thường. Đây là thứ bạn cần trên server.
# Trên server, switch sang user git
sudo su - git
# Tạo thư mục chứa tất cả repo
mkdir -p ~/repos
cd ~/repos
# Khởi tạo bare repository
git init --bare myproject.git
Convention: đặt tên với đuôi .git để dễ nhận biết đây là bare repo.
Bước 4: Clone từ máy của thành viên
Sau khi repo đã có trên server, từng thành viên clone về máy:
# Clone repo (thay your-server-ip bằng IP thật)
git clone git@your-server-ip:repos/myproject.git
# Nếu SSH không dùng port 22
git clone ssh://git@your-server-ip:2222/home/git/repos/myproject.git
Từ đây workflow hoàn toàn giống GitHub:
git add .
git commit -m "feat: thêm chức năng đăng nhập"
git push origin main
# Lấy code mới nhất từ đồng nghiệp
git pull origin main
Bước 5: Hạn chế quyền của user git (khuyến nghị)
User git chỉ nên dùng để thao tác Git, không cần shell đầy đủ. Dùng git-shell để giới hạn:
# Kiểm tra đường dẫn git-shell
which git-shell
# /usr/bin/git-shell
# Thêm vào /etc/shells nếu chưa có
echo $(which git-shell) | sudo tee -a /etc/shells
# Đổi login shell của user git
sudo chsh git -s $(which git-shell)
Sau đó, nếu ai SSH vào với tư cách user git mà không phải để chạy lệnh Git, họ sẽ thấy:
fatal: Interactive git shell is not enabled.
Thêm một lớp bảo mật nhỏ nhưng hữu ích.
Bước 6: Thêm repo mới khi cần
Khi có dự án mới, chỉ cần lặp lại bước 3:
sudo su - git
cd ~/repos
git init --bare project2.git
git init --bare internal-tools.git
Thành viên mới join team: chỉ cần thêm SSH key của họ vào authorized_keys — không cần tạo account, không cần cấu hình gì thêm.
Bài học đắt giá về git push –force
Mình từng mất code quan trọng vì force push nhầm branch — từ đó luôn cẩn thận với git push --force. Cụ thể là một lần rebase local branch rồi force push lên, quên mất đồng nghiệp đang có commit mới trên branch đó. Commit của họ bị overwrite hoàn toàn, phải mất 2 tiếng dùng git reflog mới khôi phục được.
Để tránh chuyện này với bare repo, cấm force push bằng server-side hook — loại hook mà không ai bypass được:
# Trên server, tạo hook trong thư mục bare repo
cat > ~/repos/myproject.git/hooks/update << 'EOF'
#!/bin/bash
refname="$1"
oldrev="$2"
newrev="$3"
# Cấm force push lên nhánh main
if [ "$refname" = "refs/heads/main" ]; then
if git merge-base --is-ancestor "$oldrev" "$newrev"; then
exit 0
else
echo "Force push vào branch main bị cấm!"
exit 1
fi
fi
exit 0
EOF
chmod +x ~/repos/myproject.git/hooks/update
Mẹo thêm để dùng thoải mái hơn
Tạo SSH alias để khỏi nhớ IP
Thêm vào ~/.ssh/config trên máy của từng thành viên:
Host gitserver
HostName your-server-ip
User git
Port 22
IdentityFile ~/.ssh/id_ed25519
Sau đó clone ngắn gọn hơn:
git clone gitserver:repos/myproject.git
Backup bare repo đơn giản
# Tạo bundle — một file duy nhất chứa toàn bộ history
git -C ~/repos/myproject.git bundle create /backup/myproject-$(date +%Y%m%d).bundle --all
Khi nào nên upgrade lên Gitea?
Git bare repo qua SSH phù hợp khi team ≤ 5 người, quen dùng terminal, không cần web UI hay pull request workflow, và muốn setup nhanh với ít maintenance.
Nên xem xét Gitea khi team lớn hơn, cần onboard member mới thường xuyên, cần code review có comment inline, hoặc thành viên không quen Git CLI.
Điểm hay là migration sau này không đau chút nào: khi cần upgrade, chỉ cần push bare repo lên Gitea là xong — toàn bộ commit history được giữ nguyên, không mất gì cả.

