Skip to main content

Gitea vs Forgejo: Lightweight Self-Hosted Git 2026

·OSSAlt Team
giteaforgejogitself-hostingdockerci-cd2026

TL;DR

Gitea (MIT, ~44K GitHub stars, Go) and Forgejo (GPL 3.0, ~10K stars, Go) are both lightweight self-hosted Git services. Forgejo is a community-governed fork of Gitea, created in 2022 after concerns about Gitea Ltd's commercialization direction. They're functionally nearly identical today, but the choice between them is increasingly important: Forgejo has more active community governance and stronger federation plans; Gitea has more third-party integrations and a larger ecosystem. Both run in under 200MB RAM with full GitHub-like features.

Key Takeaways

  • Gitea: MIT, ~44K stars, Go — original project, largest ecosystem, commercial-friendly
  • Forgejo: GPL 3.0, ~10K stars, Go — community fork, stronger copyleft, federation (ActivityPub) roadmap
  • Both include: Actions CI/CD, container registry, issue tracker, wikis, webhooks, API
  • RAM: ~100–200MB — vastly lighter than GitLab (~4GB)
  • Migration: Trivial to migrate between them (same codebase fork)
  • Choose Gitea: Better third-party tool support (VS Code extensions, bots, CI integrations)
  • Choose Forgejo: Community governance, copyleft license, federation plans

Gitea vs Forgejo vs GitLab CE

FeatureGiteaForgejoGitLab CE
LicenseMITGPL 3.0MIT
GitHub Stars~44K~10K~24K
RAM (idle)~100MB~100MB~4GB+
CI/CDGitea ActionsForgejo ActionsGitLab CI
Container RegistryYesYesYes
PagesYesYesYes
FederationPlannedIn progressNo
LDAP/OIDC SSOYesYesYes
PostgreSQL supportYesYesYes
Self-hosted runnersYesYesYes

Part 1: Gitea Docker Setup

# docker-compose.yml
services:
  gitea:
    image: gitea/gitea:latest
    container_name: gitea
    restart: unless-stopped
    ports:
      - "3000:3000"
      - "2222:22"    # SSH for git push
    volumes:
      - gitea_data:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    environment:
      USER_UID: "1000"
      USER_GID: "1000"
      GITEA__database__DB_TYPE: postgres
      GITEA__database__HOST: db:5432
      GITEA__database__NAME: gitea
      GITEA__database__USER: gitea
      GITEA__database__PASSWD: "${POSTGRES_PASSWORD}"
      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__service__DISABLE_REGISTRATION: "true"
    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: "${POSTGRES_PASSWORD}"

volumes:
  gitea_data:
  db_data:

Part 2: Forgejo Docker Setup

Forgejo uses the same config format as Gitea — just change the image:

services:
  forgejo:
    image: codeberg.org/forgejo/forgejo:latest
    container_name: forgejo
    restart: unless-stopped
    ports:
      - "3000:3000"
      - "2222:22"
    volumes:
      - forgejo_data:/data
    environment:
      USER_UID: "1000"
      USER_GID: "1000"
      FORGEJO__database__DB_TYPE: postgres
      FORGEJO__database__HOST: db:5432
      FORGEJO__database__NAME: forgejo
      FORGEJO__database__USER: forgejo
      FORGEJO__database__PASSWD: "${POSTGRES_PASSWORD}"
      FORGEJO__server__DOMAIN: "git.yourdomain.com"
      FORGEJO__server__ROOT_URL: "https://git.yourdomain.com/"
      FORGEJO__service__DISABLE_REGISTRATION: "true"
    depends_on:
      - db
docker compose up -d

Part 3: HTTPS with Caddy

git.yourdomain.com {
    reverse_proxy localhost:3000
}

SSH clone: Users clone via SSH using port 2222:

git clone ssh://git@git.yourdomain.com:2222/username/repo.git

Part 4: Initial Setup

  1. Visit https://git.yourdomain.com
  2. Installation wizard → verify database settings
  3. Create admin account
  4. Register additional users (or invite via email if registration disabled)

Add your SSH key:

# User settings → SSH/GPG Keys → Add Key
cat ~/.ssh/id_ed25519.pub

Part 5: Actions CI/CD

Both Gitea and Forgejo support GitHub Actions-compatible workflows (using .gitea/workflows/ or .forgejo/workflows/).

Set Up a Runner

# On a separate host or same host:
services:
  gitea-runner:    # or forgejo-runner
    image: gitea/act_runner:latest
    container_name: gitea-runner
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - runner_data:/data
    environment:
      GITEA_INSTANCE_URL: "https://git.yourdomain.com"
      GITEA_RUNNER_REGISTRATION_TOKEN: "${RUNNER_TOKEN}"
      GITEA_RUNNER_NAME: "docker-runner"
      CONFIG_FILE: /data/config.yaml

Get the registration token: Admin Panel → Runners → Create new runner.

Example Workflow

# .gitea/workflows/ci.yml  (or .forgejo/workflows/ci.yml)
name: CI

on:
  push:
    branches: [main]
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "20"
          
      - name: Install dependencies
        run: npm ci
        
      - name: Run tests
        run: npm test
        
      - name: Build
        run: npm run build

Part 6: Container Registry

Both Gitea and Forgejo include a built-in container registry:

# Log in:
docker login git.yourdomain.com

# Tag and push:
docker tag myapp git.yourdomain.com/username/myapp:latest
docker push git.yourdomain.com/username/myapp:latest

# Pull:
docker pull git.yourdomain.com/username/myapp:latest

In your Actions workflow:

- name: Build and push Docker image
  run: |
    echo "${{ secrets.GITEA_TOKEN }}" | docker login git.yourdomain.com -u ${{ gitea.actor }} --password-stdin
    docker build -t git.yourdomain.com/${{ gitea.repository }}:${{ gitea.sha }} .
    docker push git.yourdomain.com/${{ gitea.repository }}:${{ gitea.sha }}

Part 7: Migrate Between Gitea and Forgejo

Since Forgejo is a fork of Gitea, migration is trivial:

Gitea → Forgejo

# 1. Stop Gitea:
docker compose down

# 2. Back up data:
tar -czf gitea-backup.tar.gz $(docker volume inspect gitea_gitea_data --format '{{.Mountpoint}}')

# 3. Change image in docker-compose.yml:
#    gitea/gitea:latest → codeberg.org/forgejo/forgejo:latest

# 4. Update env var prefixes (optional — Gitea vars work in Forgejo too):
#    GITEA__ → FORGEJO__ (in new configs)

# 5. Start:
docker compose up -d

Forgejo reads Gitea's data directory natively — no data migration needed.


Part 8: OIDC / SSO Integration

Connect to Authentik, Keycloak, or other OIDC providers:

In Admin Panel → Authentication Sources → Add OAuth2:

  • Provider: OpenID Connect
  • Client ID: from your OIDC provider
  • Client Secret: from your OIDC provider
  • OpenID Connect Auto Discovery URL: https://auth.yourdomain.com/application/o/gitea/.well-known/openid-configuration

Users can now log in via SSO.


When to Choose Gitea vs Forgejo

Choose Gitea if:

  • You need maximum third-party ecosystem support (VS Code extensions, bots, integrations)
  • You want MIT license (more permissive for commercial use)
  • You're following a specific tutorial that uses Gitea
  • You have existing Gitea users/scripts

Choose Forgejo if:

  • You prefer community governance over corporate-influenced development
  • GPL 3.0 license aligns with your values
  • You're excited about ActivityPub federation (repos federated across Forgejo instances)
  • You're hosted on Codeberg or similar Forgejo-native platforms

Maintenance

# Update:
docker compose pull
docker compose up -d

# Backup via built-in tool:
docker exec gitea gitea admin dump -c /data/gitea/conf/app.ini

# Or direct volume backup:
tar -czf gitea-backup-$(date +%Y%m%d).tar.gz \
  $(docker volume inspect gitea_gitea_data --format '{{.Mountpoint}}')

# Logs:
docker compose logs -f gitea

See all open source developer tools at OSSAlt.com/categories/developer-tools.

Comments