← All articles

Self-Hosting Git with Gitea: A Lightweight GitHub Alternative

2026-02-08 · Development gitea git github development

GitHub is free for public repositories and generous with private ones. GitLab offers a complete DevOps platform. So why would anyone self-host their own Git forge?

Gitea is a lightweight, self-hosted Git service that runs on minimal resources while providing the features most developers actually use: repositories, pull requests, issues, CI/CD, and package registries.

This guide covers when self-hosted Git makes sense, how Gitea compares to the alternatives, and how to set it up properly.

Why Self-Host Git?

Let's be honest about the trade-offs upfront:

Good reasons to self-host

Bad reasons to self-host

Gitea vs. the Competition

Feature Gitea Forgejo GitLab CE GitHub
Resource usage ~100 MB RAM ~100 MB RAM 4+ GB RAM N/A (SaaS)
Setup time 5 minutes 5 minutes 30-60 minutes N/A
Built-in CI/CD Yes (Actions) Yes (Actions) Yes (powerful) Yes (Actions)
Package registry Yes Yes Yes Yes
Issue tracking Basic Basic Advanced Advanced
Code review Good Good Excellent Excellent
Container registry Yes Yes Yes Yes
License MIT GPL MIT (CE) Proprietary

Gitea vs. Forgejo: Forgejo is a Gitea fork created after governance concerns. They're functionally identical for most users. Forgejo is community-governed; Gitea is backed by a company. Pick whichever you prefer — the setup is the same.

Gitea vs. GitLab CE: GitLab is far more feature-rich (built-in CI/CD pipelines, security scanning, project management) but requires 10-40x more resources. If you need GitLab's features, use GitLab. If you want something lightweight, use Gitea.

Installation

Gitea is a single binary with an embedded database option, but Docker is the easiest path for production:

# docker-compose.yml
services:
  gitea:
    image: gitea/gitea:1.22
    restart: unless-stopped
    ports:
      - "3000:3000"  # Web
      - "2222:22"     # SSH
    volumes:
      - gitea_data:/data
    environment:
      GITEA__database__DB_TYPE: sqlite3
      GITEA__server__ROOT_URL: https://git.example.com/
      GITEA__server__SSH_DOMAIN: git.example.com
      GITEA__server__SSH_PORT: 2222

volumes:
  gitea_data:

That's it. Run docker compose up -d, visit port 3000, and complete the setup wizard.

For teams of 10+ or if you need better performance, switch to PostgreSQL:

services:
  gitea:
    image: gitea/gitea:1.22
    restart: unless-stopped
    ports:
      - "3000:3000"
      - "2222:22"
    volumes:
      - gitea_data:/data
    environment:
      GITEA__database__DB_TYPE: postgres
      GITEA__database__HOST: db:5432
      GITEA__database__NAME: gitea
      GITEA__database__USER: gitea
      GITEA__database__PASSWD: ${DB_PASSWORD}
    depends_on:
      - db

  db:
    image: postgres:16-alpine
    restart: unless-stopped
    volumes:
      - db_data:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: gitea
      POSTGRES_USER: gitea
      POSTGRES_PASSWORD: ${DB_PASSWORD}

volumes:
  gitea_data:
  db_data:

Gitea Actions: CI/CD

Gitea Actions is compatible with GitHub Actions workflow syntax. Most simple GitHub Actions workflows run on Gitea without modification.

Enable it in app.ini:

[actions]
ENABLED = true

Then register a runner:

docker run -d \
  --name gitea-runner \
  -e GITEA_INSTANCE_URL=https://git.example.com \
  -e GITEA_RUNNER_REGISTRATION_TOKEN=<token> \
  -v /var/run/docker.sock:/var/run/docker.sock \
  gitea/act_runner:latest

Your .gitea/workflows/ci.yml (or .github/workflows/ci.yml) files work the same way:

name: CI
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm install
      - run: npm test

Note: Complex GitHub Actions that use GitHub-specific APIs (like actions/cache with GitHub's cache service) won't work without modification.

Migrating from GitHub

Gitea has a built-in migration tool that imports:

Go to New Migration → GitHub, enter a personal access token, and select the repositories to import. It handles the rest.

For bulk migration, use the API:

curl -X POST "https://git.example.com/api/v1/repos/migrate" \
  -H "Authorization: token YOUR_GITEA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "clone_addr": "https://github.com/owner/repo",
    "auth_token": "GITHUB_PAT",
    "repo_name": "repo",
    "mirror": true,
    "service": "github"
  }'

Set "mirror": true to keep the Gitea copy in sync with GitHub — useful during transition periods.

Resource Usage

This is where Gitea really shines:

Metric Gitea GitLab CE
Idle RAM 80-150 MB 3-6 GB
Disk (empty) ~100 MB ~2 GB
Cold start 2-3 seconds 2-5 minutes
Min VPS $5/month (1 GB) $20+/month (4 GB)

Gitea runs comfortably on a Raspberry Pi. GitLab requires a proper server.

Backup

Gitea includes a built-in backup command:

docker exec gitea gitea dump -c /data/gitea/conf/app.ini

This creates a zip archive containing the database, repositories, and configuration. Store it off-site.

For continuous backups, the Git repositories in /data/git/repositories/ can be incrementally backed up with rsync or restic.

The Bottom Line

Self-hosting Git makes sense in specific scenarios: compliance requirements, large teams where per-user costs add up, or environments where cloud access is restricted. For most individual developers and small teams, GitHub Free is hard to beat.

If you do decide to self-host, Gitea is the best balance of features and resource efficiency. It won't give you GitHub's ecosystem of integrations and community, but it gives you a fast, reliable Git forge that you control completely.