Forgejo on a VPS: Community-Owned Git Forge as GitHub and GitLab Alternative

Forgejo on a VPS: Community-Owned Git Forge as GitHub and GitLab Alternative

Forgejo is a community-owned fork of Gitea created when Gitea’s development became controlled by a single company. Forgejo maintains the same GitHub-like interface and API but with community governance, no corporate ownership, and stronger commitments to open-source principles. It supports federation (ActivityPub) allowing repositories to be discovered across Forgejo instances, and includes Forgejo Actions for CI/CD with GitHub Actions-compatible syntax.

Forgejo vs Gitea: Key Differences

  • Governance: Forgejo is governed by a community organization (Codeberg e.V.); Gitea Inc. controls Gitea
  • Federation: Forgejo is implementing ActivityPub federation — follow repos/users across instances
  • License commitment: Forgejo has committed to remaining MIT licensed
  • Compatibility: Fully API-compatible with Gitea — same clients, same Gitea Apps work
  • Migration: Upgrade from Gitea to Forgejo is a drop-in (same database format)

Step 1: Docker Compose Setup

<code">mkdir -p /opt/forgejo && cd /opt/forgejo
nano docker-compose.yml
<code">version: '3.8'

services:
  forgejo:
    image: codeberg.org/forgejo/forgejo:9
    container_name: forgejo
    restart: always
    ports:
      - "127.0.0.1:3000:3000"
      - "0.0.0.0:2222:22"     # SSH for git push
    environment:
      - USER_UID=1000
      - USER_GID=1000
      - FORGEJO__database__DB_TYPE=postgres
      - FORGEJO__database__HOST=forgejo-db:5432
      - FORGEJO__database__NAME=forgejo
      - FORGEJO__database__USER=forgejo
      - FORGEJO__database__PASSWD=${POSTGRES_PASSWORD}
      - FORGEJO__server__DOMAIN=git.yourdomain.com
      - FORGEJO__server__ROOT_URL=https://git.yourdomain.com/
      - FORGEJO__server__SSH_DOMAIN=git.yourdomain.com
      - FORGEJO__server__SSH_PORT=2222
      - FORGEJO__actions__ENABLED=true
      - FORGEJO__federation__ENABLED=true
    volumes:
      - forgejo_data:/data

  forgejo-db:
    image: postgres:16-alpine
    restart: always
    environment:
      POSTGRES_DB: forgejo
      POSTGRES_USER: forgejo
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - forgejo_db:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U forgejo"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  forgejo_data:
  forgejo_db:
<code">echo "POSTGRES_PASSWORD=StrongForgejoDbPassword!" > .env
chmod 600 .env
docker compose up -d

Step 2: Nginx Reverse Proxy

<code">sudo nano /etc/nginx/sites-available/forgejo
<code">server {
    listen 80;
    server_name git.yourdomain.com;
    return 301 https://$host$request_uri;
}

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;

    client_max_body_size 200M;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        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;
    }
}
<code">sudo certbot --nginx -d git.yourdomain.com
sudo systemctl reload nginx

Step 3: Migrate from GitHub

<code"># Method A: Forgejo UI migration (recommended)
# + → Migrate Repository → GitHub
# Enter: repository URL, GitHub PAT
# Options: migrate issues, labels, milestones, releases, wiki

# Method B: Bulk migration via API
FORGEJO_TOKEN="your_admin_token"
GITHUB_TOKEN="your_github_token"

# List GitHub repos and migrate each:
for repo in $(curl -s -H "Authorization: token $GITHUB_TOKEN" \
    https://api.github.com/user/repos | jq -r '.[].full_name'); do
    
    curl -X POST https://git.yourdomain.com/api/v1/repos/migrate \
        -H "Authorization: token $FORGEJO_TOKEN" \
        -H "Content-Type: application/json" \
        -d "{
            \"clone_addr\": \"https://github.com/$repo\",
            \"auth_token\": \"$GITHUB_TOKEN\",
            \"uid\": 1,
            \"repo_name\": \"$(basename $repo)\"
        }"
done

Step 4: Forgejo Actions CI/CD

<code"># Install act runner for Forgejo Actions:
wget https://code.forgejo.org/forgejo/act_runner/releases/download/v0.2.11/act_runner-0.2.11-linux-amd64 \
    -O /usr/local/bin/act_runner
chmod +x /usr/local/bin/act_runner

# Register runner (get token from admin panel):
# Forgejo → Site Administration → Actions → Runners → Create Runner
act_runner register \
    --instance https://git.yourdomain.com \
    --token YOUR_RUNNER_TOKEN \
    --name vps-runner \
    --labels ubuntu-latest:docker://node:20

# Forgejo Actions workflow (GitHub Actions compatible):
# .forgejo/workflows/ci.yml (same syntax as .github/workflows/)

Step 5: Federation (Cross-Instance Following)

<code"># Forgejo federation allows users on different instances to interact
# Enable federation in app.ini (done via env var above):
# FORGEJO__federation__ENABLED=true

# ActivityPub endpoint created automatically:
# https://git.yourdomain.com/user/alice -> WebFinger discovery
# https://git.yourdomain.com/@alice -> Actor profile

# Star a repository from another Forgejo instance:
# @[email protected] can star git.yourdomain.com/bob/myproject

# Follow a user across instances via ActivityPub (future feature)

Step 6: Packages (Container Registry)

<code"># Forgejo includes a package registry (OCI container, npm, pip, etc.)
# Enable: FORGEJO__packages__ENABLED=true (default: true)

# Push Docker images:
docker login git.yourdomain.com
docker tag myapp:latest git.yourdomain.com/myorg/myapp:latest
docker push git.yourdomain.com/myorg/myapp:latest

# Pull:
docker pull git.yourdomain.com/myorg/myapp:latest

# npm packages:
npm publish --registry https://git.yourdomain.com/api/packages/myorg/npm/

Getting Started

Forgejo with PostgreSQL uses 200–400 MB RAM. A 2 GB Ubuntu VPS at VPS.DO runs Forgejo comfortably for teams up to 50 developers. For organizations that previously self-hosted Gitea, migrating to Forgejo is a direct upgrade with the same database format — just change the Docker image. The community governance model ensures the project won’t be acquired, relicensed, or sunset.

Conclusion

Forgejo provides a complete, community-owned Git forge — code hosting, issue tracking, pull requests, Forgejo Actions CI/CD, container registry, and ActivityPub federation — under MIT license with community governance. For organizations self-hosting their code, Forgejo’s commitment to open-source governance and planned federation make it the most future-proof choice. The API is fully Gitea-compatible, so any tool or integration built for Gitea works identically with Forgejo.

4 Comments

  • Checkout bloodprills.com
    October 20, 2026

    Great overview of hair and nail care.

  • Essential amino acids
    October 20, 2026

    This is a valuable addition to the discussion.

  • Memory loss causes
    October 20, 2026

    Very informative and relevant.

  • Ringing in ears causes
    October 20, 2026

    This is a practical and readable resource.

Post Your Comment

Fast • Reliable • Affordable VPS - DO It Now!

Get top VPS hosting with VPS.DO’s fast, low-cost plans. Try risk-free with our 7-day no-questions-asked refund and start today!