GitHub and GitLab run on centralized infrastructure. Your repositories live on their servers, subject to their pricing, policies, and availability. Forgejo is a self-hosted alternative—you run the Git server on your own hardware.
This isn’t inherently better or worse. It’s a different set of tradeoffs: swap SaaS convenience for control, predictability, and (usually) lower costs as you scale.
What Forgejo Provides
Forgejo started as a soft fork of Gitea in 2022 over governance concerns. In February 2024, it became a hard fork under Codeberg e.V., achieving full independence from its upstream. The latest stable release is v13.0 (October 2025), bringing WebAuthn support and 15% memory optimizations.
Core functionality:
Git repository hosting
Pull request and code review workflow
Issue tracking with labels and milestones
Built-in CI/CD (Forgejo Actions)
Package registry (Docker, npm, Maven, PyPI)
Git LFS support
OAuth/LDAP/SAML authentication
Federation for multi-instance collaboration
AI code suggestions (opt-in plugins)
The interface resembles GitHub. Teams familiar with GitHub’s workflow navigate Forgejo without training.
Cost Structure
GitHub Teams: $5/user/month ($60/year per user) GitLab Premium: $32/user/month ($384/year per user)
For 10 users:
GitHub: $600/year
GitLab: $3,840/year
Forgejo on a VPS:
Hetzner CX21: €4.85/month (~$52/year)
Digital Ocean Droplet (2GB): $12/month ($144/year)
These VPS prices work for 10 users or 100 users. No per-seat scaling.
Hidden costs:
Setup time: 4-6 hours
Ongoing maintenance: 2-4 hours/month
Backup storage: $1-5/month
Technical Requirements
Minimum specs:
1GB RAM (tight, but usable)
2 CPU cores
20GB storage + repository sizes
Linux server (Ubuntu, Debian)
Recommended for production:
2GB RAM
2-4 CPU cores
Storage: 50GB base + 1.3x repository sizes
SSD strongly recommended
Database options:
SQLite: Simple, single file. Works until concurrent operations slow down (10-20 active users).
PostgreSQL: Better concurrency. Migrate when SQLite bottlenecks.
Installation
Docker Compose setup with health checks:
services:
forgejo:
image: codeberg.org/forgejo/forgejo:9-rootless
container_name: forgejo
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=your_password_here
- FORGEJO__server__ROOT_URL=https://git.yourdomain.com
- FORGEJO__server__SSH_PORT=222
volumes:
- ./data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "222:22"
depends_on:
db:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000"]
interval: 30s
timeout: 10s
retries: 3
restart: unless-stopped
db:
image: postgres:17-alpine
environment:
- POSTGRES_USER=forgejo
- POSTGRES_PASSWORD=your_password_here
- POSTGRES_DB=forgejo
volumes:
- ./postgres:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U forgejo"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
Notes:
Rootless image for simpler permissions
SSH on port 222 avoids host conflicts
Health checks ensure service readiness
PostgreSQL 17 for latest performance improvements
Start: docker-compose up -d
First run launches web installer at
http://your-server:3000
. Configure admin credentials, server URL, and email settings.
Reverse Proxy and SSL
Forgejo serves HTTP on port 3000. Production needs HTTPS.
Caddy (automatic SSL):
git.yourdomain.com {
reverse_proxy forgejo:3000
}
Nginx:
server {
listen 443 ssl http2;
server_name git.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/git.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/git.yourdomain.com/privkey.pem;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Get certificates: certbot --nginx -d git.yourdomain.com
Basic Usage
Repositories:
Organizations group repositories and manage team permissions. Create organizations for team projects, user accounts for personal repos.
Clone with custom SSH port:
git clone ssh://git@git.yourdomain.com:222/org/repo.git
Pull Requests:
Standard GitHub workflow:
Branch or fork
Push changes
Open pull request
Inline code review
Merge when approved
Issues:
Support Markdown, labels, milestones, assignees, attachments. Reference commits: fixes #123 creates automatic links.
Webhooks:
POST JSON to external endpoints on push, PR, issue, or release events. Configure in repository settings for CI/CD triggers.
Federation:
Connect multiple Forgejo instances for cross-instance collaboration. Users on one instance can interact with repositories on another. Enable in admin settings.
CI/CD: Forgejo Actions
GitHub Actions-compatible. Run your own runners.
Runner Setup:
services:
runner:
image: code.forgejo.org/forgejo/runner:3.3.0
environment:
- FORGEJO_INSTANCE_URL=https://git.yourdomain.com
- FORGEJO_RUNNER_REGISTRATION_TOKEN=your_token
volumes:
- /var/run/docker.sock:/var/run/docker.sock
restart: unless-stopped
Token from: Site Administration → Actions → Runners
Workflow Example:
.forgejo/workflows/test.yml:
name: Test
on: [push, pull_request]
jobs:
test:
runs-on: docker
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: '3.11'
- run: pip install -r requirements.txt
- run: pytest
Most GitHub Actions work without modification.
AI Code Suggestions
V13 introduces opt-in AI plugins for code completion and suggestions. Configure via admin panel. Integrates with OpenAI API or self-hosted models. Privacy-focused: code never leaves your infrastructure if using local models.
Enable in: Site Administration → AI Settings
Backup Strategy
Critical data:
Repositories (
./datavolume)PostgreSQL database
Configuration (
app.ini)
Daily Backup:
#!/bin/bash
BACKUP_DIR="/backups/forgejo"
DATE=$(date +%Y%m%d_%H%M%S)
# Database backup (no downtime)
docker-compose exec -T db pg_dump -U forgejo forgejo | gzip > $BACKUP_DIR/db_$DATE.sql.gz
# Repository backup
tar -czf $BACKUP_DIR/data_$DATE.tar.gz ./data
# Retention: 7 days
find $BACKUP_DIR -mtime +7 -delete
Off-site:
rclone sync /backups/forgejo s3:bucket-name/forgejo
Test restores regularly.
Updates
Updates every 4-8 weeks.
docker-compose pull
docker-compose up -d
docker-compose logs -f forgejo
Downtime: 30-60 seconds.
Security:
Enable 2FA for admins
SSH key-based auth only
Strong database passwords
Keep host OS updated
When to Self-Host
Good fit:
You manage servers already
Stable team size
Data sovereignty requirements
Infrastructure control preference
Poor fit:
No operational expertise
Rapid unpredictable growth
Critical uptime without HA capability
Small teams focused on product
Getting Started
Evaluation:
Deploy local instance
Create test repository
Try workflows (clone, commit, PR)
Test Actions
Practice backup/restore
Resources:
Docs: forgejo.org/docs
Forum: codeberg.org/forgejo/discussions
Matrix: #forgejo:matrix.org
Video: Forgejo Tutorial by Awesome Open Source
Bottom Line
Forgejo trades SaaS convenience for infrastructure control. You eliminate per-seat costs and external dependencies at the cost of operational responsibility.
The software is stable. Choose based on whether managing it aligns with your team’s capabilities, not ideology.



