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

📅 26/06/2026 · ⏱ 15 phút đọc · 🏷 DevOps · Self-host · Git

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íGiteaGitLab CEGitHub (free)Gogs
RAM tối thiểu128 MB4 GBKhông cần (cloud)64 MB
RAM thực tế (idle)~100-150 MB~2.5-3.5 GB0 (cloud)~50-80 MB
Binary size~100 MBN/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 đặtDocker hoặc binaryOmnibus packageKhông cầnBinary
Update1 lệnh (binary thay thế)apt upgrade (lâu)Tự động1 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.

💡 Sự thật thú vị: Gitea được viết bằng Go — cùng ngôn ngữ với Docker, Kubernetes, Caddy, Traefik. Đây là một trong những lý do nó nhẹ và nhanh: Go biên dịch ra single binary, không cần runtime như Ruby (GitLab) hay Java. Khởi động trong <1 giây, serve request trong ~10ms.

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"
⚠️ Bẫy #1 — SSH port mặc định 22 bị conflict với host: Gitea chạy SSH server trong container. Nếu map port 22:22, nó sẽ đụng với SSH của host. Tôi map port 2222 (host) → 22 (container). Nhưng khi clone qua SSH, bạn phải dùng 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:

Nhấn "Install Gitea" → chờ 5 giây → redirect về trang login. Đăng nhập bằng admin account vừa tạo.

🔒 Bảo mật cơ bản: Sau khi cài xong, vào Site Administration → Configuration. Bật 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 }}
⚠️ Bẫy #2 — Runner chạy trong Docker cần privileged mode: Nếu CI/CD của bạn cần build Docker image (Docker-in-Docker), runner phải có access đến Docker socket của host. Cấu hình ở trên mount /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 -
⚠️ Bẫy #3 — Backup git repo bằng cách copy file có thể corrupt nếu đang có push: Git repo là file system, nếu bạn copy trong khi ai đó đang push, bare repo có thể bị corrupt (pack file không toàn vẹn). Solution: dùng 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ápChi phí/thángRepo privateCI/CDThành viênStorage
Gitea trên VPS 2GB~160K VNDKhông giới hạnKhông giới hạn phútKhông giới hạn20-50GB SSD VPS
GitHub Free0 VNDKhông giới hạn2000 phút/thángKhông giới hạnKhông giới hạn
GitHub Team$4/user (~100K/user)Không giới hạn3000 phút/thángKhông giới hạn2GB Packages
GitLab SaaS (Premium)$29/user (~730K/user)Không giới hạn10000 phút/thángKhông giới hạn10GB/ repo
GitLab Self-hosted (CE)Miễn phí + VPS 8GB (~700K)Không giới hạnKhông giới hạnKhông giới hạnSSD 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 →