Development beginner ⏱ 30 minutes

Forgejo: Community-Driven Gitea Fork

Soft fork of Gitea focused on community governance. Federation support and enhanced features.

By homelabbing.io • 2025-12-17
#forgejo#git#federation#self-hosted#docker

Overview

In 2022, the Gitea project made a controversial decision to create a for-profit company behind the open-source project. The community’s response was swift: Forgejo (pronounced for-hey-oh) emerged as a hard fork, committed to remaining 100% community-driven, non-profit, and focused on user freedom rather than commercial interests.

Today in 2025, Forgejo has evolved beyond a simple fork. It’s pushing boundaries that Gitea won’t touch: federation (imagine Git repositories that talk to each other like email), aggressive privacy features, and a steadfast commitment to open governance. While maintaining near-complete compatibility with Gitea, Forgejo charts its own course focused on user sovereignty and decentralization.

For homelabbers, Forgejo represents an ideological choice as much as a technical one. If you believe in community-driven development, sustainable open source, and decentralized infrastructure, Forgejo is your Git service. And the best part? It’s still just as lightweight and easy to self-host as Gitea, running smoothly on 512MB of RAM.

What you’ll learn:

  • Understanding Forgejo vs. Gitea differences
  • Installing Forgejo with Docker
  • Migrating from Gitea to Forgejo
  • Setting up Forgejo Actions (CI/CD)
  • Federation features and future roadmap
  • Security and privacy enhancements
  • When to choose Forgejo over Gitea

Why Forgejo for your homelab?

Support community-driven software. Get federation features for decentralized Git hosting. Enjoy enhanced privacy controls. Benefit from faster security updates. Join a movement toward sustainable open source. All while keeping the lightweight, self-hostable nature you need for homelab deployments.


Prerequisites

Before starting, ensure you have:

  • Linux server with Docker installed (512MB+ RAM, 1-2GB recommended)
  • Docker and Docker Compose installed and working
  • Storage: 10GB+ for repositories and data
  • Network: Ports 3000 (web UI) and 22 or 2222 (SSH)
  • Basic Git knowledge (commits, pushes, pulls)

Optional but helpful:

  • Existing Gitea installation (for migration)
  • Domain name for HTTPS access
  • Reverse proxy experience
  • Understanding of federation concepts (ActivityPub, Fediverse)

Understanding Forgejo

What is Forgejo?

Forgejo (meaning “forge” in Esperanto) is a hard fork of Gitea, created and maintained by Codeberg e.V., a non-profit organization dedicated to free software. It’s not just Gitea with a different name—it’s a reimagining of what community-driven Git hosting should be.

Core philosophy:

  • Community-first: Decisions made by contributors, not a company
  • Federation: Repositories that can interact across instances
  • Privacy: Enhanced user controls and data sovereignty
  • Sustainability: Non-profit model focused on long-term viability
  • Freedom: Committed to remaining 100% free software

Key features:

  • All Gitea features (repositories, issues, PRs, wikis)
  • Forgejo Actions (GitHub Actions-compatible CI/CD)
  • Repository federation (experimental)
  • Enhanced privacy controls
  • Faster security updates
  • Community governance
  • Lighter resource usage optimizations

Forgejo vs. Gitea: The Real Differences

AspectForgejoGitea
GovernanceNon-profit, community-drivenFor-profit company + community
LicenseMIT (committed forever)MIT (but company can change)
DevelopmentCommunity contributorsCompany employees + community
FederationActive developmentNot prioritized
UpdatesFrequent, community-pacedSlower, business priorities
PhilosophyUser freedom firstBalanced with business needs
Compatibility~95% compatible with GiteaN/A
Best ForIdealists, privacy advocatesPragmatists, stability seekers

Technical differences (2025):

  1. Federation: Forgejo is developing ActivityPub-based federation
  2. Privacy: More granular privacy controls
  3. Security: Faster CVE patches (community can act immediately)
  4. Features: Some experimental features land in Forgejo first
  5. Dependencies: Slightly different dependency management

The reality: For most users, Forgejo and Gitea are nearly identical in day-to-day use. The differences are philosophical and forward-looking.

Why Forgejo Exists: The Backstory

October 2022: Gitea Ltd. was formed as a for-profit company with the ability to change Gitea’s license or create proprietary versions.

Community concerns:

  • Would Gitea remain truly open source?
  • Would community voices be heard over business interests?
  • What happens to user freedom if the company changes direction?

The fork: Rather than trust in corporate promises, the community forked Gitea to ensure:

  • Permanent commitment to free software
  • Community control over direction
  • Non-profit, sustainable development model
  • No possibility of proprietary features or license changes

Today: Both projects coexist. Gitea focuses on stability and business use cases. Forgejo experiments with federation and user sovereignty. Many Gitea changes flow into Forgejo and vice versa.

Federation: The Future of Git Hosting

Forgejo’s killer feature is federation (experimental in 2025).

The vision:

[Your Forgejo Instance]     [Friend's Forgejo]     [Codeberg.org]
         ↓                           ↓                      ↓
    [ActivityPub Federation Protocol]
         ↓
   Repositories, issues, and PRs work across instances
   Like email: [email protected] can interact with [email protected]

What federation enables:

  • Follow repositories across instances (like following people on Mastodon)
  • Submit PRs to repositories on other Forgejo instances
  • Cross-instance collaboration without centralized services
  • Decentralized GitHub alternative with no single point of control
  • Data sovereignty while maintaining interconnectedness

Current status (2025): Basic federation implemented, active development ongoing. Not production-ready for critical workflows yet, but functional for experimentation.


Installing Forgejo

Create directory structure:

mkdir -p ~/forgejo && cd ~/forgejo

Create docker-compose.yml:

version: '3.8'

services:
  forgejo:
    image: codeberg.org/forgejo/forgejo:1.21
    container_name: forgejo
    restart: unless-stopped
    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=${DB_PASSWORD}
      - FORGEJO__server__DOMAIN=${FORGEJO_DOMAIN}
      - FORGEJO__server__SSH_DOMAIN=${FORGEJO_DOMAIN}
      - FORGEJO__server__ROOT_URL=https://${FORGEJO_DOMAIN}
      - FORGEJO__server__HTTP_PORT=3000
      - FORGEJO__server__SSH_PORT=22
      - FORGEJO__server__START_SSH_SERVER=true
      - FORGEJO__service__DISABLE_REGISTRATION=false
      # Federation (experimental)
      - FORGEJO__federation__ENABLED=true
    ports:
      - "3000:3000"
      - "2222:22"
    volumes:
      - forgejo_data:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    networks:
      - forgejo
    depends_on:
      - db

  db:
    image: postgres:15-alpine
    container_name: forgejo-db
    restart: unless-stopped
    environment:
      - POSTGRES_USER=forgejo
      - POSTGRES_PASSWORD=${DB_PASSWORD}
      - POSTGRES_DB=forgejo
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - forgejo
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U forgejo"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  forgejo_data:
    driver: local
  postgres_data:
    driver: local

networks:
  forgejo:
    driver: bridge

Create .env file:

nano .env
# Database password
DB_PASSWORD=your_secure_password_here

# Your domain
FORGEJO_DOMAIN=git.homelab.local

Deploy Forgejo:

# Start services
docker compose up -d

# Check logs
docker compose logs -f forgejo

# Verify running
docker compose ps

Access Forgejo:

Navigate to http://YOUR-SERVER-IP:3000

Method 2: Migrate Existing Gitea to Forgejo

Forgejo is designed for easy migration from Gitea.

Important: Backup everything first!

# Backup Gitea
cd ~/gitea
docker exec gitea-db pg_dump -U gitea gitea > gitea_backup.sql
tar czf gitea_data_backup.tar.gz gitea_data/

Migration steps:

  1. Stop Gitea:
docker compose down
  1. Update docker-compose.yml:
# Change image from:
image: gitea/gitea:1.21

# To:
image: codeberg.org/forgejo/forgejo:1.21

# Change container name from:
container_name: gitea

# To:
container_name: forgejo

# Update environment variables (GITEA__ → FORGEJO__)
# Example:
- FORGEJO__database__DB_TYPE=postgres
  1. Rename data volume (optional but clean):
# If you want clean naming
docker volume create forgejo_data
docker run --rm -v gitea_data:/source -v forgejo_data:/dest alpine   sh -c "cp -av /source/. /dest/"
  1. Update compose file volumes:
volumes:
  - forgejo_data:/data  # Changed from gitea_data
  1. Start Forgejo:
docker compose up -d

# Check logs for migration messages
docker compose logs -f forgejo
  1. Verify:
  • Log in with existing Gitea credentials
  • Check repositories are accessible
  • Test Git operations (clone, push, pull)
  • Verify SSH keys still work

Rollback if needed:

docker compose down
# Restore original docker-compose.yml
# Restore data volume
docker compose up -d

That’s it! Forgejo automatically migrates the Gitea database schema.

Method 3: Binary Installation

Download Forgejo:

# Download latest release
wget https://codeberg.org/forgejo/forgejo/releases/download/v1.21.x/forgejo-1.21.x-linux-amd64

# Make executable
chmod +x forgejo-1.21.x-linux-amd64
sudo mv forgejo-1.21.x-linux-amd64 /usr/local/bin/forgejo

Create user and directories:

sudo adduser --system --shell /bin/bash --group --disabled-password --home /home/git git

sudo mkdir -p /var/lib/forgejo/{custom,data,log}
sudo chown -R git:git /var/lib/forgejo/
sudo chmod -R 750 /var/lib/forgejo/

Create systemd service:

# /etc/systemd/system/forgejo.service
[Unit]
Description=Forgejo
After=network.target

[Service]
Type=simple
User=git
Group=git
WorkingDirectory=/var/lib/forgejo/
ExecStart=/usr/local/bin/forgejo web --config /etc/forgejo/app.ini
Restart=always
Environment=USER=git HOME=/home/git FORGEJO_WORK_DIR=/var/lib/forgejo

[Install]
WantedBy=multi-user.target

Start Forgejo:

sudo systemctl daemon-reload
sudo systemctl enable forgejo
sudo systemctl start forgejo
sudo systemctl status forgejo

Forgejo Actions: CI/CD

Forgejo Actions is GitHub Actions-compatible CI/CD built into Forgejo (same as Gitea Actions).

Enabling Actions

Edit app.ini (Docker: in forgejo_data/forgejo/conf/app.ini):

[actions]
ENABLED = true
DEFAULT_ACTIONS_URL = https://code.forgejo.org

Why code.forgejo.org?

Forgejo hosts its own Actions marketplace, separate from GitHub. It includes:

  • Forks of popular GitHub Actions
  • Forgejo-specific actions
  • Privacy-respecting alternatives

Restart Forgejo:

docker compose restart forgejo

Setting Up Runners

Forgejo uses the same runner as Gitea (act_runner).

Add runner to docker-compose.yml:

# Add to existing docker-compose.yml
  runner:
    image: code.gitea.io/gitea/act_runner:latest
    container_name: forgejo-runner
    restart: unless-stopped
    environment:
      - GITEA_INSTANCE_URL=http://forgejo:3000
      - GITEA_RUNNER_REGISTRATION_TOKEN=${RUNNER_TOKEN}
      - GITEA_RUNNER_NAME=docker-runner-01
    volumes:
      - ./runner-data:/data
      - /var/run/docker.sock:/var/run/docker.sock
    depends_on:
      - forgejo
    networks:
      - forgejo

Get registration token:

  1. Log into Forgejo as admin
  2. Site Administration → Actions → Runners
  3. Click Create new Runner
  4. Copy registration token
  5. Add to .env file:
echo "RUNNER_TOKEN=your-token-here" >> .env

Start runner:

docker compose up -d runner
docker compose logs -f runner

Verify runner:

Forgejo UI → Site Admin → Actions → Runners → Should show “Idle”

Example Workflow

Create .forgejo/workflows/build.yml in your repository:

name: Build and Test

on:
  push:
    branches:
      - main
  pull_request:

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup 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

      - name: Upload artifacts
        uses: actions/upload-artifact@v4
        with:
          name: build-output
          path: dist/

Workflow compatibility:

  • Uses .forgejo/workflows/ directory (Forgejo-specific)
  • Also checks .github/workflows/ (GitHub compatibility)
  • Most GitHub Actions work (fetched from code.forgejo.org)

Key difference from Gitea Actions:

Forgejo defaults to its own Actions marketplace for privacy and independence from Microsoft’s infrastructure.


Federation Features

Federation is Forgejo’s most ambitious feature—making Git hosting decentralized.

Current Federation Capabilities (2025)

What works:

  • Follow repositories from other Forgejo instances
  • Federated stars (star a repo on another instance)
  • User discovery across instances via ActivityPub
  • Cross-instance notifications

What’s coming:

  • Federated pull requests (submit PR to repo on another instance)
  • Federated issues
  • Cross-instance CI/CD (trigger builds on collaborator instances)
  • Decentralized authentication (sign in with your instance, access others)

Enabling Federation

In app.ini:

[federation]
ENABLED = true
SHARE_USER_STATS = true

[activitypub]
ENABLED = true

Restart Forgejo:

docker compose restart forgejo

Federation requires HTTPS (for ActivityPub signing). Set up a reverse proxy with Let’s Encrypt.

Following Remote Repositories

Via UI:

  1. Navigate to repository on another Forgejo instance
  2. Click Follow (if logged into your instance)
  3. Receive notifications about new releases, stars, etc.

Via ActivityPub:

Your instance broadcasts activities:

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "type": "Follow",
  "actor": "https://your-forgejo.com/users/alice",
  "object": "https://other-forgejo.com/repos/bob/cool-project"
}

Other Forgejo instances (and Mastodon!) can subscribe.

Federation Use Cases

Decentralized collaboration:

Alice's Forgejo (homelab)
    ↓ Follows
Bob's Forgejo (VPS)
    ↓ Forks
Codeberg.org (public instance)

Alice and Bob collaborate on a project federated across three instances, no central authority required.

Privacy-preserving discovery:

Your private instance can interact with public instances without hosting public repositories.

Resilience:

If one instance goes down, forks and mirrors on other instances remain accessible.


Privacy and Security Enhancements

Forgejo prioritizes privacy beyond what Gitea offers.

Privacy Features

Disable telemetry (always):

[metrics]
ENABLED = false

[log]
LEVEL = Warn  # Less verbose logging

Enhanced user privacy controls:

  1. User Settings → Privacy
  2. Configure:
    • Hide email from everyone
    • Hide activity from non-followers
    • Disable user discovery
    • Private profile

Repository visibility options:

  • Public
  • Private
  • Limited (followers-only)
  • Organization-only

Security Hardening

Regular security updates:

Forgejo releases security patches faster than Gitea (community can act immediately without company approval).

Security headers:

[server]
ENABLE_HSTS = true
HSTS_MAX_AGE = 31536000

[security]
INSTALL_LOCK = true
SECRET_KEY = generate-with-forgejo-generate-secret

Two-factor authentication:

  1. User Settings → Security
  2. Two-Factor Authentication → Enroll
  3. Scan QR code with authenticator app

Signed commits enforcement:

  1. Repository → Settings → Branches
  2. Select branch → Require signed commits
  3. Users must GPG-sign all commits

SSH key security:

# Force Ed25519 keys (most secure)
# In app.ini:
[ssh.minimum_key_sizes]
ED25519 = 256
RSA = 3072
ECDSA = 256

Advanced Configuration

Custom Branding

Logo and name:

[ui]
DEFAULT_THEME = forgejo-auto
THEMES = forgejo-auto,forgejo-light,forgejo-dark

[branding]
CUSTOM_LOGO_URL = /img/logo.png
CUSTOM_FOOTER_TEXT = Powered by Forgejo - Community-Driven Git

Custom CSS:

# Create custom CSS
mkdir -p forgejo_data/forgejo/public/css
nano forgejo_data/forgejo/public/css/custom.css
/* Custom theme colors */
:root {
  --primary-color: #ff6b35;
  --secondary-color: #004e89;
}

Email Configuration

SMTP setup:

[mailer]
ENABLED = true
FROM = [email protected]
PROTOCOL = smtp
SMTP_ADDR = smtp.gmail.com
SMTP_PORT = 587
USER = [email protected]
PASSWD = app-password-here

Test email:

# Site Admin → Configuration → Send Test Email

Database Optimization

PostgreSQL tuning:

# docker-compose.yml
  db:
    environment:
      - POSTGRES_INITDB_ARGS="-E UTF8 --locale=en_US.UTF-8"
    command: >
      -c shared_buffers=256MB
      -c effective_cache_size=1GB
      -c maintenance_work_mem=64MB
      -c checkpoint_completion_target=0.9
      -c wal_buffers=16MB
      -c default_statistics_target=100

Repository Limits

Prevent abuse:

[repository]
MAX_CREATION_LIMIT = 50
MAX_SIZE = 100  # MB
DISABLE_HTTP_GIT = false

Comparison: When to Choose What

Choose Forgejo if:

✅ Community governance matters to you

  • You want to support non-profit, community-driven software
  • You value transparency in development decisions
  • You want to influence project direction

✅ You care about federation

  • You want decentralized Git hosting
  • You’re building Fediverse-compatible infrastructure
  • You believe in reducing dependency on centralized platforms

✅ Privacy is a priority

  • Enhanced privacy controls matter
  • You want faster security patches
  • You prefer non-corporate software

✅ You’re willing to be on the cutting edge

  • Experimental features excite you
  • You can handle occasional breaking changes
  • You want to contribute to the project’s future

Choose Gitea if:

✅ Stability is paramount

  • You need proven, battle-tested software
  • Breaking changes are unacceptable
  • You prefer slower, more conservative updates

✅ Commercial support might be needed

  • You may want paid support options
  • Business compliance requires vendor backing
  • You need a company behind the project

✅ You don’t care about governance

  • Technical features matter more than politics
  • You’re pragmatic about corporate involvement
  • Community vs. company doesn’t affect your choice

They’re both great if:

  • You need lightweight self-hosted Git
  • Resource efficiency matters (both use ~512MB RAM)
  • GitHub Actions compatibility is required
  • You want familiar GitHub-like workflows

The truth: For 95% of users, Forgejo and Gitea are functionally identical. The choice is philosophical, not technical.


Migration Between Gitea and Forgejo

Gitea → Forgejo (Easy)

Already covered above. Summary:

  1. Backup Gitea
  2. Change Docker image to Forgejo
  3. Update environment variables (GITEA→ FORGEJO)
  4. Start Forgejo
  5. Automatic migration on first run

Compatibility: ~99% seamless

Forgejo → Gitea (Harder)

Why harder? Forgejo includes features Gitea doesn’t have (federation). Downgrading loses those features.

Process:

  1. Backup Forgejo thoroughly
  2. Disable federation features:
[federation]
ENABLED = false

[activitypub]
ENABLED = false
  1. Stop Forgejo:
docker compose down
  1. Update docker-compose.yml:
# Change image from:
image: codeberg.org/forgejo/forgejo:1.21

# To:
image: gitea/gitea:1.21
  1. Update environment variables:
# FORGEJO__ → GITEA__
- GITEA__database__DB_TYPE=postgres
  1. Start Gitea:
docker compose up -d
  1. Verify:
  • Check logs for errors
  • Test repository access
  • Verify SSH keys work

Expect: Some Forgejo-specific features won’t work in Gitea (federation, certain privacy settings).


Troubleshooting

Migration Issues

Problem: Forgejo won’t start after migration from Gitea

# Check logs
docker compose logs forgejo

# Common issue: Database migration failure
# Solution: Ensure database backup exists, try with fresh DB
docker compose down
docker volume rm forgejo_postgres_data
docker volume create forgejo_postgres_data
# Restore backup

Federation Not Working

Problem: Can’t follow remote repositories

Checklist:

  1. HTTPS enabled? Federation requires valid SSL
  2. Federation enabled in app.ini?
  3. Firewall allows outbound HTTPS?
  4. Remote instance supports federation? (Check their instance info)

Debug:

# Check ActivityPub endpoint
curl https://your-forgejo.com/.well-known/webfinger?resource=acct:[email protected]

# Should return ActivityPub actor info

Actions Runner Issues

Problem: Runner not picking up jobs

# Check runner logs
docker logs forgejo-runner

# Verify registration
# Forgejo UI → Admin → Actions → Runners

# Re-register runner
docker exec -it forgejo-runner /bin/bash
act_runner register --instance http://forgejo:3000 --token NEW_TOKEN

Performance Degradation

Problem: Forgejo slowing down over time

Solutions:

# Clean up old logs
docker exec forgejo rm -rf /data/forgejo/log/*.log.gz

# Optimize database
docker exec forgejo-db vacuumdb -U forgejo -d forgejo -f --analyze

# Check resource usage
docker stats forgejo forgejo-db

Community and Contribution

Getting Involved

Codeberg.org:

Forgejo’s development happens on Codeberg (a public Forgejo instance):

Matrix Chat:

Real-time community support: #forgejo:matrix.org

Mailing Lists:

For development discussions and announcements

Contributing

Ways to contribute:

  1. Code: Fix bugs, add features
  2. Documentation: Improve guides
  3. Translation: Localize Forgejo
  4. Testing: Try experimental features
  5. Support: Help other users
  6. Donate: Support Codeberg e.V. (non-profit)

Philosophy: Forgejo welcomes all contributors. Decisions made collaboratively, not by a company.


Conclusion

Forgejo represents the future of community-driven Git hosting. You’ve learned:

  • The ideological and technical differences from Gitea
  • Installing and migrating to Forgejo
  • Setting up Forgejo Actions for CI/CD
  • Exploring federation features
  • Security and privacy enhancements
  • When to choose Forgejo vs. Gitea

Key Takeaways

  • Community-driven: Non-profit, transparent governance
  • Federation: Working toward decentralized Git hosting
  • Privacy-focused: Enhanced controls and faster security patches
  • Gitea-compatible: Easy migration, familiar workflows
  • Lightweight: Same efficiency as Gitea (512MB RAM)

Next Steps

  1. Deploy Forgejo in your homelab
  2. Migrate from Gitea if you’re already using it
  3. Set up Actions for CI/CD pipelines
  4. Experiment with federation (if you have multiple instances)
  5. Join the community on Codeberg and Matrix
  6. Contribute back to the project
  • Gitea - The original, Forgejo’s parent
  • Gitea Actions - Detailed CI/CD setup
  • code-server - Browser-based development
  • Woodpecker CI - Alternative CI/CD for Forgejo
  • Nginx Proxy Manager - HTTPS for federation

Resources


Document Version: 1.0 Last Updated: December 16, 2025 Based on: Forgejo 1.21+ Estimated Completion Time: 45 minutes

“Forged by the community, for the community.”

Happy self-hosting with freedom!