Want to host your own code without relying on GitHub or GitLab? Forgejo is a community-driven fork of Gitea — lightweight, fast, and designed to stay free forever. It’s everything you need for private repos, CI/CD, and team collaboration on your own hardware.
Why Forgejo Over Gitea?
Forgejo forked from Gitea in 2022 after governance concerns. The key differences:
- Community-governed — no single company controls it
- Guaranteed free — committed to staying FOSS, no enterprise bait-and-switch
- Federation support — working toward ActivityPub integration (follow repos across instances)
- Same codebase — if you know Gitea, you know Forgejo
- Drop-in replacement — migrate from Gitea with zero data loss
Prerequisites
- Docker and Docker Compose
- ~256MB RAM (runs great on a Pi)
- A domain (optional but recommended)
Step 1: Setup
mkdir -p ~/forgejo && cd ~/forgejo
Step 2: Docker Compose
Create docker-compose.yml:
services:
forgejo:
image: codeberg/forgejo:9
container_name: forgejo
environment:
- USER_UID=1000
- USER_GID=1000
- FORGEJO__server__ROOT_URL=http://localhost:3000
- FORGEJO__database__DB_TYPE=sqlite3
- FORGEJO__service__DISABLE_REGISTRATION=false
volumes:
- ./data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "2222:22"
restart: unless-stopped
Step 3: Launch
docker compose up -d
Open http://your-server-ip:3000. The first-run wizard appears:
- Database: SQLite is fine for personal use (PostgreSQL for teams)
- Site Title: Your instance name
- Admin Account: Create your admin user
- Click Install Forgejo
Step 4: Create Your First Repository
- Click + → New Repository
- Name it, add a description, choose visibility
- Initialize with a README if starting fresh
Push Existing Code
cd ~/my-project
git remote add forgejo http://your-server-ip:3000/username/my-project.git
git push -u forgejo main
SSH Access
Add your public key at Settings → SSH/GPG Keys, then:
git remote add forgejo ssh://git@your-server-ip:2222/username/my-project.git
Step 5: Mirror GitHub Repos
Forgejo can mirror your GitHub repos automatically:
- New Migration → GitHub
- Enter the GitHub repo URL
- Check Mirror Repository
- Set sync interval
Your Forgejo instance stays in sync with GitHub — perfect as a backup or for moving off GitHub gradually.
Step 6: Built-in CI/CD (Forgejo Actions)
Forgejo has GitHub Actions-compatible CI/CD built in:
Enable Actions
Add to your compose environment:
environment:
- FORGEJO__actions__ENABLED=true
Add a Runner
runner:
image: code.forgejo.org/forgejo/runner:6
container_name: forgejo-runner
depends_on:
- forgejo
environment:
- FORGEJO_INSTANCE_URL=http://forgejo:3000
- FORGEJO_RUNNER_REGISTRATION_TOKEN=your-token
volumes:
- /var/run/docker.sock:/var/run/docker.sock
restart: unless-stopped
Get the registration token from Site Administration → Runners.
Create a Workflow
Create .forgejo/workflows/ci.yml in your repo:
on: [push]
jobs:
test:
runs-on: docker
steps:
- uses: actions/checkout@v4
- run: echo "Hello from Forgejo CI!"
- run: npm test
Yes — it uses the same syntax as GitHub Actions. Most GitHub Actions work unmodified.
Step 7: Package Registry
Forgejo includes a built-in package registry for Docker images, npm, PyPI, and more:
# Push a Docker image to Forgejo
docker login your-server-ip:3000
docker tag myapp your-server-ip:3000/username/myapp:latest
docker push your-server-ip:3000/username/myapp:latest
# Publish an npm package
npm config set registry http://your-server-ip:3000/api/packages/username/npm/
npm publish
Step 8: Reverse Proxy
For production with HTTPS:
Caddy:
Update the ROOT_URL in your compose:
- FORGEJO__server__ROOT_URL=https://git.yourdomain.com
Restart after changing:
docker compose down && docker compose up -d
Step 9: Backups
# Forgejo has a built-in backup command
docker exec forgejo forgejo dump -c /data/gitea/conf/app.ini
# Or just backup the data directory
tar -czf ~/backups/forgejo-$(date +%Y%m%d).tar.gz -C ~/forgejo data/
Migrating from Gitea
Since Forgejo is a fork, migration is seamless:
- Stop Gitea
- Copy your Gitea
data/directory - Replace the Gitea image with
codeberg/forgejo:9 - Start Forgejo — it reads the same data format
# Literally just change the image
sed -i 's|gitea/gitea:latest|codeberg/forgejo:9|' docker-compose.yml
docker compose up -d
Forgejo vs Alternatives
| Feature | Forgejo | Gitea | GitLab | GitHub |
|---|---|---|---|---|
| Self-hosted | ✅ | ✅ | ✅ | ❌ |
| RAM usage | ~100MB | ~100MB | ~4GB | N/A |
| CI/CD | ✅ | ✅ | ✅ | ✅ |
| Package registry | ✅ | ✅ | ✅ | ✅ |
| Federation | 🔜 | ❌ | ❌ | ❌ |
| License | GPL | MIT* | Partial | Proprietary |
| Governance | Community | Company | Company | Company |
*Gitea changed to a company-controlled model, which prompted the Forgejo fork.
Troubleshooting
Can’t push via SSH
- Verify port 2222 is mapped and open
- Check your SSH key is added in Forgejo settings
- Test:
ssh -T git@your-server-ip -p 2222
Actions not running
- Ensure
FORGEJO__actions__ENABLED=trueis set - Check runner is registered: Admin → Runners
- View runner logs:
docker compose logs runner
Slow on large repos
- Switch from SQLite to PostgreSQL for better concurrent access
- Enable Git LFS for large files
- Increase container memory limit
Resource Usage
| Metric | Usage |
|---|---|
| RAM | ~100-150MB |
| CPU | Minimal |
| Disk | ~200MB + repos |
| Image size | ~100MB |
Conclusion
Forgejo gives you everything GitHub does — repos, issues, PRs, CI/CD, packages — on your own server for free. It’s lightweight enough for a Raspberry Pi, powerful enough for a team, and committed to staying open source forever.
If you’re already self-hosting anything, there’s no reason your code shouldn’t be self-hosted too. Forgejo makes it easy.