Self-Hosted Git: Forgejo, Gitea, GitLab — Workflow, CI, Backup
Published 2026-06-17 · Updated 2026-08-21 · 22 min read · By Ben Liu
Run a personal forge without overbuilding: Forgejo/Gitea/GitLab fit, repos, issues, CI runners, auth, backup, and migration — practical operator guidance.
Why host your own forge
Privacy, air-gapped networks, large LFS, or refusing a single SaaS for every repo. Mirror critical repos off-site anyway — a basement forge is not a backup by itself.
Right-size: Forgejo vs Gitea vs GitLab CE
| Axis | Forgejo / Gitea | GitLab CE |
|---|---|---|
| Fit | Personal + small team | CI/registry-heavy workflows |
| Resources | Modest VM | Higher RAM floor |
| Issues/PRs | Yes | Yes + broader product surface |
| CI | Optional Actions/runners | Integrated CI deeply |
| Upgrade pain | Usually lighter | Plan snapshots; longer windows |
Forgejo and Gitea are the same lightweight class; day-to-day UI is similar — choose the release/security stream you trust. GitLab CE earns weight when pipelines and registry are daily needs, not because the installer looks serious.
Repository hosting baseline
services:
forgejo:
image: codeberg.org/forgejo/forgejo:9.0.3
environment:
USER_UID: "1000"
USER_GID: "1000"
volumes:
- ./forgejo:/data
networks: [internal]
restart: unless-stopped
db:
image: postgres:16-alpine
volumes: [pgdata:/var/lib/postgresql/data]
networks: [internal]
restart: unless-stoppedTerminate TLS at your reverse proxy. Disable open registration. SSH on a deliberate port or VPN-only.
Lab notes pending — replace with measured values before publishing claims.
[Add real environment data here]
Forge (Forgejo/Gitea/GitLab) + version:
DB:
Public clone URL pattern:
SSH path:
Runner host (if any):Issues and permissions
Use orgs to separate homelab infra from personal projects. Protect default branches on important repos. Prefer SSH keys; disable password git auth.
CI and runners
Optional Actions/runners for linting compose or small builds. Isolate runners; assume a malicious workflow can read secrets exported to that runner. Store CI secrets in the forge secret store — not in plaintext workflow files.
Household forges often disable public signup and outside PRs — boring and sufficient until you invite collaborators.
Authentication
Local users + MFA for admins is enough to start. OIDC (Authentik/Keycloak/Authelia ecosystem) when you outgrow local accounts — document a break-glass local admin before SSO-only login.
Backup
Backup DB + `/data` (repos, wiki, attachments, packages) together. Bare `git bundle` is not the whole product.
# pattern — adjust names
docker compose exec -T db pg_dump -U git git > backup-$(date +%F).sql
tar czf forge-data-$(date +%F).tgz -C /srv/compose/forge dataTest restore on scratch compose: clone one repo and open one issue attachment.
Migration
Trial import with labels/milestones/LFS before switching laptop remotes. Keep old remotes read-only for a while. Inventory CI variables before exposure changes; rotate tokens after migration.
Related reading
See Docker Compose hardening, Automatic SSL certificates, Restore drill playbook, Secure remote access, and Open-source licenses quick guide.
Explore more
Related guides
- Self-Hosted RSS: Feed Readers, Sync, and OPML Hygiene
When to self-host FreshRSS or Miniflux, how to keep OPML portable, and fetch habits that respect publishers without turning RSS into another inbox.
- Self-Hosted Wiki for Households and Tiny Teams
Pick BookStack vs Wiki.js vs Outline for the job, structure pages people will actually use, and back up content before the wiki becomes the only copy.
- Ollama on a Homelab: Local LLMs Without Melting the Rack
Operator guide to running Ollama at home — install paths, Docker, model disk gravity, GPU vs CPU, API exposure, and a sane first weekend with Open WebUI.
- Reverse Proxy and Automatic TLS for Homelabs
One ops guide for reverse proxy + ACME: what a proxy solves, Caddy/Traefik/Nginx fit, certificate renewal, Docker wiring, failure modes, and troubleshooting — without three overlapping primers.