Forgejo: Community-Driven Gitea Fork
Soft fork of Gitea focused on community governance. Federation support and enhanced features.
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
| Aspect | Forgejo | Gitea |
|---|---|---|
| Governance | Non-profit, community-driven | For-profit company + community |
| License | MIT (committed forever) | MIT (but company can change) |
| Development | Community contributors | Company employees + community |
| Federation | Active development | Not prioritized |
| Updates | Frequent, community-paced | Slower, business priorities |
| Philosophy | User freedom first | Balanced with business needs |
| Compatibility | ~95% compatible with Gitea | N/A |
| Best For | Idealists, privacy advocates | Pragmatists, stability seekers |
Technical differences (2025):
- Federation: Forgejo is developing ActivityPub-based federation
- Privacy: More granular privacy controls
- Security: Faster CVE patches (community can act immediately)
- Features: Some experimental features land in Forgejo first
- 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
Method 1: Docker Compose (Recommended)
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:
- Stop Gitea:
docker compose down - 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 - 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/" - Update compose file volumes:
volumes:
- forgejo_data:/data # Changed from gitea_data - Start Forgejo:
docker compose up -d
# Check logs for migration messages
docker compose logs -f forgejo - 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:
- Log into Forgejo as admin
- Site Administration → Actions → Runners
- Click Create new Runner
- Copy registration token
- 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:
- Navigate to repository on another Forgejo instance
- Click Follow (if logged into your instance)
- 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:
- User Settings → Privacy
- 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:
- User Settings → Security
- Two-Factor Authentication → Enroll
- Scan QR code with authenticator app
Signed commits enforcement:
- Repository → Settings → Branches
- Select branch → Require signed commits
- 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:
- Backup Gitea
- Change Docker image to Forgejo
- Update environment variables (GITEA→ FORGEJO)
- Start Forgejo
- 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:
- Backup Forgejo thoroughly
- Disable federation features:
[federation]
ENABLED = false
[activitypub]
ENABLED = false - Stop Forgejo:
docker compose down - Update docker-compose.yml:
# Change image from:
image: codeberg.org/forgejo/forgejo:1.21
# To:
image: gitea/gitea:1.21 - Update environment variables:
# FORGEJO__ → GITEA__
- GITEA__database__DB_TYPE=postgres - Start Gitea:
docker compose up -d - 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:
- HTTPS enabled? Federation requires valid SSL
- Federation enabled in app.ini?
- Firewall allows outbound HTTPS?
- 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):
- Code: codeberg.org/forgejo/forgejo
- Issues: Report bugs, request features
- PRs: Contribute code
- Discussions: Join community conversations
Matrix Chat:
Real-time community support: #forgejo:matrix.org
Mailing Lists:
For development discussions and announcements
Contributing
Ways to contribute:
- Code: Fix bugs, add features
- Documentation: Improve guides
- Translation: Localize Forgejo
- Testing: Try experimental features
- Support: Help other users
- 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
- Deploy Forgejo in your homelab
- Migrate from Gitea if you’re already using it
- Set up Actions for CI/CD pipelines
- Experiment with federation (if you have multiple instances)
- Join the community on Codeberg and Matrix
- Contribute back to the project
Related Guides
- 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
- Official Site: forgejo.org
- Codeberg: codeberg.org/forgejo
- Documentation: forgejo.org/docs
- Matrix Chat:
#forgejo:matrix.org - Comparison: forgejo.org/compare
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!