Forgejo is a lightweight, self-hosted Git forge: repositories, pull requests, issues, wikis, a package and container registry, and Forgejo Actions for CI/CD. It’s a community-governed fork of Gitea, stewarded by the non-profit Codeberg e.V., and it powers Codeberg.org. It runs comfortably on a small VPS.

Choosing between options? See self-hosted Git compared.

Requirements

  • 1–2 vCPU and 1–2 GB RAM for a small team (more if CI runners run on the same host, which isn’t recommended).
  • Docker and Docker Compose. See install Docker.
  • A domain, e.g. git.example.com.

Docker Compose with PostgreSQL

# /opt/forgejo/compose.yaml
services:
  forgejo:
    image: codeberg.org/forgejo/forgejo:11       # pin a major version
    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: change-me-db
      FORGEJO__server__DOMAIN: git.example.com
      FORGEJO__server__ROOT_URL: https://git.example.com/
      FORGEJO__server__SSH_DOMAIN: git.example.com
      FORGEJO__server__SSH_PORT: 2222
      FORGEJO__service__DISABLE_REGISTRATION: "true"
    ports:
      - "127.0.0.1:3000:3000"
      - "2222:22"
    volumes:
      - ./data:/data
    depends_on: [db]

  db:
    image: postgres:16
    restart: unless-stopped
    environment:
      POSTGRES_DB: forgejo
      POSTGRES_USER: forgejo
      POSTGRES_PASSWORD: change-me-db
    volumes:
      - ./postgres:/var/lib/postgresql/data
cd /opt/forgejo && docker compose up -d

Use the current major version tag. Environment variables in the form FORGEJO__section__KEY map to app.ini settings.

SSH for Git

The compose file exposes Forgejo’s built-in SSH on port 2222, so the host’s own SSH stays on 22. Clone URLs look like ssh://[email protected]:2222/team/app.git. Open the port:

sudo ufw allow 2222/tcp

Want [email protected]:team/app.git on port 22? Either move the host’s admin SSH to another port, or set up SSH passthrough (the host’s sshd forwards the git user to the container), as described in the Forgejo docs. See change the SSH port.

HTTPS with Nginx

server {
    server_name git.example.com;
    client_max_body_size 512M;          # large pushes, LFS, packages
    location / {
        proxy_pass http://127.0.0.1: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;
    }
    # listen 443 ssl; certbot --nginx -d git.example.com
}

See Let’s Encrypt.

First setup

Open https://git.example.com. The installation page shows the pre-filled settings. Create the administrator account there. Registration is disabled via the environment, so create other users as admin, or enable OAuth or OIDC login. Turn on 2FA for admins.

Forgejo Actions (CI/CD)

Actions use GitHub Actions-compatible workflows in .forgejo/workflows/. Run the Forgejo Runner on a separate VPS:

  1. In Site Administration → Actions → Runners, create a registration token.
  2. On the runner host:
docker run --rm -it -v $PWD/runner:/data code.forgejo.org/forgejo/runner:6 \
  forgejo-runner register --instance https://git.example.com --token <token> --name runner-1 --no-interactive
  1. Run the runner as a service (Docker Compose), with Docker access for jobs.

Workflow syntax and security considerations are the same as Gitea’s. See Gitea Actions.

Migrate repositories

New Migration imports from GitHub, GitLab, Gitea and others, including issues, pull requests, releases and labels with a token. Pull mirrors keep a repository synced from elsewhere. Moving from Gitea: Forgejo supports upgrading from compatible Gitea versions. Check the version compatibility notes first.

Backups and upgrades

  • Backup: stop or quiesce the container, then back up ./data (repositories, LFS, attachments, config) and the PostgreSQL database:
docker compose exec -T db pg_dump -U forgejo forgejo > /backups/forgejo-$(date +%F).sql
tar -czf /backups/forgejo-data-$(date +%F).tar.gz -C /opt/forgejo data

forgejo dump inside the container also creates a full archive. Copy everything off-server. See backup strategy.

  • Upgrades: read the release notes, back up, change the image tag, then docker compose pull && docker compose up -d. See updating self-hosted apps.

Quick reference

Task Command / setting
Start docker compose up -d
Web port 3000 behind Nginx
Git SSH port 2222 (or passthrough on 22)
Settings via env FORGEJO__section__KEY
Disable signups FORGEJO__service__DISABLE_REGISTRATION=true
Workflows .forgejo/workflows/*.yml

Related: Gitea and CI/CD explained.

  • Git
  • Self-Hosting
  • DevOps