Tự Host Gitea Git Server Trên VPS 2026 — GitHub Riêng Cho Team, CI/CD Tích Hợp, Nhẹ Hơn GitLab 10 Lần
1. Tôi Đã Mất Cả Tuần Code Vì GitLab Ngốn Hết RAM VPS
Năm 2023, tôi cài GitLab CE lên con VPS 4GB RAM để làm git server cho team 3 người. GitLab khởi động xong, tôi gõ htop. 3.8GB RAM đã biến mất. Sidekiq, Puma, PostgreSQL, Redis, Gitaly, Prometheus, Grafana — GitLab CE chạy ~15 process khác nhau, mỗi cái ngốn vài trăm MB. Team tôi làm việc được 2 tuần thì VPS bắt đầu swap liên tục. Mỗi lần push code lên là CPU spike 100% trong 30 giây. Merge request mất 15 giây mới load xong. Tôi phải tắt Prometheus, tắt Grafana, tắt container registry, giảm Unicorn worker xuống 1 — vẫn ngốn 2.5GB.
Sau 1 tháng vật vã, tôi chuyển qua Gitea. Cùng 4GB RAM, Gitea dùng đúng 120MB. Không tin nổi, tôi kiểm tra lại — 120MB, bao gồm cả web UI, SSH server, git hooks, và API. Từ đó team tôi chưa phải nghĩ đến việc nâng cấp VPS vì git server nữa.
Bài viết này hướng dẫn bạn tự host Gitea trên VPS: Docker, HTTPS với Caddy, Gitea Actions (CI/CD), mirror repository từ GitHub, backup tự động ra S3, và những cái bẫy tôi đã dính phải.
2. Gitea vs GitHub vs GitLab vs Gogs — Cái Nào Cho VPS Nhỏ?
| Tiêu chí | Gitea | GitLab CE | GitHub (free) | Gogs |
|---|---|---|---|---|
| RAM tối thiểu | 128 MB | 4 GB | Không cần (cloud) | 64 MB |
| RAM thực tế (idle) | ~100-150 MB | ~2.5-3.5 GB | 0 (cloud) | ~50-80 MB |
| Binary size | ~100 MB | N/A (nhiều service) | N/A (cloud) | ~30 MB |
| CI/CD tích hợp | ✅ Gitea Actions (tương thích GitHub Actions) | ✅ GitLab CI (mạnh nhất) | ✅ GitHub Actions (2000 phút/tháng free) | ❌ Không có |
| Package Registry | ✅ (Composer, npm, PyPI, Docker, etc.) | ✅ (Đầy đủ nhất) | ✅ (GitHub Packages) | ❌ Không có |
| Code Review (PR) | ✅ Pull Request + Review | ✅ Merge Request (nhiều tính năng nhất) | ✅ Pull Request | ✅ Cơ bản |
| Wiki | ✅ (Git-based) | ✅ (Git-based) | ✅ | ✅ |
| Project Board (Kanban) | ✅ | ✅ | ✅ | ❌ |
| Webhook | ✅ | ✅ | ✅ | ✅ |
| Mirror repository | ✅ (Push + Pull) | ✅ | ❌ (chỉ import) | ✅ (Pull) |
| Cài đặt | Docker hoặc binary | Omnibus package | Không cần | Binary |
| Update | 1 lệnh (binary thay thế) | apt upgrade (lâu) | Tự động | 1 lệnh |
Verdict: Nếu bạn cần CI/CD mạnh (multi-stage pipeline, Kubernetes executor, artifact management) → GitLab. Nếu bạn chỉ cần git server nhẹ, có PR, có CI/CD cơ bản → Gitea. Gogs là "cha đẻ" của Gitea (Gitea fork từ Gogs năm 2016) nhưng phát triển chậm hơn nhiều, thiếu CI/CD, thiếu Package Registry.
3. Cài Gitea Bằng Docker Compose Trên VPS
Yêu cầu: VPS 1GB RAM, 1 vCPU, 20GB SSD. Tôi dùng TrumVPS gói 2GB RAM (160K/tháng) để dư dả cho CI/CD runner. Nếu bạn chỉ dùng git server không CI/CD, 1GB RAM là đủ cho team 10 người.
# Tạo thư mục cho Gitea
mkdir -p /opt/gitea && cd /opt/gitea
# Tạo docker-compose.yml
cat > docker-compose.yml <<'EOF'
version: "3.8"
services:
gitea:
image: gitea/gitea:1.23
container_name: gitea
restart: always
environment:
- GITEA__server__DOMAIN=git.yourdomain.com
- GITEA__server__ROOT_URL=https://git.yourdomain.com
- GITEA__server__SSH_DOMAIN=git.yourdomain.com
- GITEA__server__SSH_PORT=2222
- GITEA__server__HTTP_PORT=3000
- GITEA__database__DB_TYPE=postgres
- GITEA__database__HOST=db:5432
- GITEA__database__NAME=gitea
- GITEA__database__USER=gitea
- GITEA__database__PASSWD=gitea-secure-password
- GITEA__actions__ENABLED=true
ports:
- "2222:22"
- "3000:3000"
volumes:
- ./data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
depends_on:
db:
condition: service_healthy
db:
image: postgres:16-alpine
container_name: gitea-db
restart: always
environment:
- POSTGRES_USER=gitea
- POSTGRES_PASSWORD=gitea-secure-password
- POSTGRES_DB=gitea
volumes:
- ./postgres:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U gitea"]
interval: 5s
timeout: 5s
retries: 5
caddy:
image: caddy:2-alpine
container_name: gitea-caddy
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- ./caddy_data:/data
depends_on:
- gitea
EOF
# Tạo Caddyfile cho HTTPS tự động
cat > Caddyfile <<'EOF'
git.yourdomain.com {
reverse_proxy gitea:3000
}
EOF
# Khởi động
docker compose up -d
# Kiểm tra
docker compose ps
# Tất cả 3 service phải "Up" và "healthy"
ssh://git@git.yourdomain.com:2222/user/repo.git thay vì git@git.yourdomain.com:user/repo.git. Khó chịu. Solution: dùng SSH Host alias trong ~/.ssh/config.# Trên máy client, thêm vào ~/.ssh/config
Host git.yourdomain.com
HostName git.yourdomain.com
Port 2222
User git
IdentityFile ~/.ssh/id_ed25519
# Giờ clone như bình thường
git clone git@git.yourdomain.com:username/repo.git
4. Thiết Lập Gitea Lần Đầu — 5 Phút Là Xong
Mở trình duyệt, vào https://git.yourdomain.com. Gitea sẽ hiện trang installer. Điền các thông tin:
- Database: PostgreSQL (đã cấu hình qua biến môi trường ở trên nên auto-fill)
- Site Title: "Git Server Của Team Tôi" (tùy ý)
- Domain: git.yourdomain.com
- Base URL: https://git.yourdomain.com
- Disable Self-Registration: TICK (chỉ admin mới tạo được user)
- Admin Account: tạo user đầu tiên — user này tự động là admin
Nhấn "Install Gitea" → chờ 5 giây → redirect về trang login. Đăng nhập bằng admin account vừa tạo.
ENABLE_CAPTCHA = true. Set MIN_PASSWORD_LENGTH = 12. Nếu team làm remote, bắt buộc 2FA (mỗi user tự bật trong Settings).5. Gitea Actions — CI/CD Như GitHub Actions, Nhưng Chạy Trên VPS Của Bạn
Đây là tính năng tôi thích nhất của Gitea. Từ version 1.19 (2023), Gitea tích hợp Actions — tương thích cú pháp với GitHub Actions. Bạn có thể copy-paste workflow từ GitHub sang Gitea mà hầu như không cần sửa gì. Điểm khác biệt: GitHub Actions chạy trên server của Microsoft (free 2000 phút/tháng), Gitea Actions chạy trên chính VPS của bạn — không giới hạn phút, không queue chờ.
# Tạo Gitea Actions Runner
# Trên VPS, tạo thư mục và docker-compose cho runner
mkdir -p /opt/gitea-runner && cd /opt/gitea-runner
# Lấy registration token từ Gitea UI:
# Site Admin → Actions → Runners → Create new Runner → Copy token
cat > docker-compose.yml <<'EOF'
version: "3.8"
services:
runner:
image: gitea/act_runner:0.2.11
container_name: gitea-runner
restart: always
environment:
- GITEA_INSTANCE_URL=https://git.yourdomain.com
- GITEA_RUNNER_REGISTRATION_TOKEN=your-registration-token-here
- GITEA_RUNNER_NAME=vps-runner
- GITEA_RUNNER_LABELS=ubuntu-latest:docker://node:20-bookworm,ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./data:/data
EOF
docker compose up -d
Giờ tạo workflow CI/CD trong repo (file .gitea/workflows/build.yml):
name: Build and Test
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Build Docker image
if: github.ref == 'refs/heads/main'
run: |
docker build -t registry.yourdomain.com/app:latest .
# Push to private registry
env:
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
/var/run/docker.sock — cách này hoạt động nhưng là security risk (container có toàn quyền điều khiển Docker host). Production nên dùng rootless Docker hoặc Kaniko thay vì Docker-in-Docker.6. Mirror Repository Từ GitHub Về Gitea
Bạn muốn có bản backup của repo quan trọng trên GitHub, hoặc muốn migrate từ từ? Gitea có tính năng mirror cực kỳ hay:
# Tạo mirror pull từ GitHub (đồng bộ 1 chiều, tự động cập nhật mỗi 8h)
# Vào New Migration → chọn "GitHub" → paste URL repo
# Tick "This repository will be a mirror"
# Gitea sẽ tự fetch mọi thứ: code, issues, PRs, releases, wiki
# Hoặc push mirror: code chính ở Gitea, tự động push sang GitHub làm backup
# Vào repo Settings → Mirror Settings → Add Push Mirror
# URL: https://github.com/username/repo.git
# Authorization: dùng GitHub Personal Access Token
Tôi dùng mirror push để backup toàn bộ code sang GitHub private repo. Gitea là primary, GitHub là hot standby. Nếu VPS die, tôi chỉ mất 30 phút để clone lại từ GitHub.
7. Backup Gitea — Đừng Để Mất Code Vì VPS Crash
Gitea lưu repository dưới dạng git bare repo trong /data/git/repositories/. Database (user, issues, PRs, settings) nằm trong PostgreSQL. Backup cần backup cả hai.
# Script backup tự động
cat > /opt/scripts/backup-gitea.sh <<'SCRIPT'
#!/bin/bash
BACKUP_DIR="/opt/backups/gitea"
RETENTION_DAYS=14
DATE=$(date +%Y%m%d-%H%M%S)
mkdir -p $BACKUP_DIR
# 1. Dump PostgreSQL
docker exec gitea-db pg_dump -U gitea gitea | gzip > $BACKUP_DIR/db-$DATE.sql.gz
# 2. Backup git repositories
tar czf $BACKUP_DIR/repos-$DATE.tar.gz -C /opt/gitea/data git
# 3. Backup Gitea config
cp /opt/gitea/data/gitea/conf/app.ini $BACKUP_DIR/app-$DATE.ini
# 4. Upload lên S3/Backblaze B2
aws s3 sync $BACKUP_DIR s3://my-backups/gitea/ --delete
# 5. Xóa backup cũ (>14 ngày)
find $BACKUP_DIR -mtime +$RETENTION_DAYS -delete
echo "$(date): Backup completed"
SCRIPT
chmod +x /opt/scripts/backup-gitea.sh
# Cron chạy 3AM mỗi ngày
(crontab -l 2>/dev/null; echo "0 3 * * * /opt/scripts/backup-gitea.sh >> /var/log/gitea-backup.log 2>&1") | crontab -
gitea dump command — nó lock repo trong lúc backup.# Cách backup an toàn hơn
docker exec gitea gitea dump --config /data/gitea/conf/app.ini \
--file /tmp/gitea-backup.zip \
--type zip
# Copy ra ngoài
docker cp gitea:/tmp/gitea-backup.zip $BACKUP_DIR/gitea-full-$DATE.zip
8. Tối Ưu Hiệu Năng Gitea Trên VPS
Sau 6 tháng chạy Gitea production cho team 5 người với ~200 repos, đây là những tuning thực tế tôi đã làm:
# Trong app.ini
[repository]
DEFAULT_PUSH_CREATE_PRIVATE = true # Repo mới mặc định private
MAX_CREATION_LIMIT = -1 # Không giới hạn số repo
PREFERRED_LICENSES = MIT,Apache-2.0,GPL-3.0
ENABLE_PUSH_CREATE_USER = true # Push tạo user tự động
[git]
MAX_GIT_DIFF_LINES = 10000 # Giới hạn số dòng diff
GC_ARGS = --aggressive --auto # Git garbage collection
TIMEOUT_MIGRATE = 600 # Timeout migration (giây)
[cache]
ENABLED = true
ADAPTER = memory
INTERVAL = 60
HOST =
[session]
PROVIDER = memory
PROVIDER_CONFIG =
[indexer]
REPO_INDEXER_ENABLED = true # Tìm kiếm code trong repo
MAX_FILE_SIZE = 1048576 # Max 1MB/file để index
[metrics]
ENABLED = false # Tắt Prometheus metrics nếu không dùng
Sau khi áp dụng, Gitea của tôi chạy ổn định 120-180MB RAM, CPU idle <1%, phục vụ team 5 người với khoảng 50-100 thao tác git/ngày.
9. So Sánh Chi Phí: Tự Host Gitea vs GitHub Team
| Giải pháp | Chi phí/tháng | Repo private | CI/CD | Thành viên | Storage |
|---|---|---|---|---|---|
| Gitea trên VPS 2GB | ~160K VND | Không giới hạn | Không giới hạn phút | Không giới hạn | 20-50GB SSD VPS |
| GitHub Free | 0 VND | Không giới hạn | 2000 phút/tháng | Không giới hạn | Không giới hạn |
| GitHub Team | $4/user (~100K/user) | Không giới hạn | 3000 phút/tháng | Không giới hạn | 2GB Packages |
| GitLab SaaS (Premium) | $29/user (~730K/user) | Không giới hạn | 10000 phút/tháng | Không giới hạn | 10GB/ repo |
| GitLab Self-hosted (CE) | Miễn phí + VPS 8GB (~700K) | Không giới hạn | Không giới hạn | Không giới hạn | SSD VPS |
Với team 5 người: GitHub Team = 5 × $4 = $20/tháng (~500K). Gitea = 160K VND/tháng. Tiết kiệm 68%. Nhưng lưu ý: bạn phải tự maintain server, backup, update. Trade-off là tiền đổi lấy thời gian.
🚀 Cần VPS Để Tự Host Gitea?
TrumVPS có VPS KVM từ 80K/tháng, 1-4GB RAM, SSD NVMe — đủ sức chạy Gitea + CI/CD runner cho team 5-10 người. Cài Docker Compose là chạy ngay.
Thuê VPS TrumVPS Ngay →