Knowledgebase › Forgejo (and Gitea) on a LYLIX VPS — backups, CI runners, mirror workflows

Forgejo (and Gitea) on a LYLIX VPS — backups, CI runners, mirror workflows

Forgejo is a hard fork of Gitea, run by a community non-profit. Both are excellent lightweight self-hosted Git forges. This article covers Forgejo specifically (the patterns apply to Gitea too) plus the operational habits that make it sustainable.

Sizing

  • Solo developer: 1 GB RAM, 1 CPU, 20 GB disk. Plenty.
  • Small team (5-20): 2 GB RAM, 2 CPU, 50+ GB disk.
  • Larger: scale RAM with active repository count and CI runner count.

Forgejo is genuinely light. Storage is the variable — depends on repo size and how much CI artifact storage you keep.

Install

Forgejo ships as a single binary. The most reliable install:

useradd -m -s /bin/bash -d /var/lib/forgejo git
mkdir -p /etc/forgejo /var/lib/forgejo
chown git:git /var/lib/forgejo

# Download the binary
wget -O /usr/local/bin/forgejo \
    https://codeberg.org/forgejo/forgejo/releases/download/v9.0.0/forgejo-9.0.0-linux-amd64
chmod +x /usr/local/bin/forgejo

# systemd unit
cat > /etc/systemd/system/forgejo.service <<'EOF'
[Unit]
Description=Forgejo
After=network.target

[Service]
Type=simple
User=git
Group=git
WorkingDirectory=/var/lib/forgejo
ExecStart=/usr/local/bin/forgejo web --config /etc/forgejo/app.ini
Restart=always

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now forgejo

Visit http://<your-vps-ip>:3000 for the initial setup wizard. Pick:

  • Database: SQLite for solo use; PostgreSQL or MariaDB for anything else.
  • Domain and base URL.
  • Admin user (don't skip; the first registered user otherwise becomes admin).

Behind a reverse proxy

Run Forgejo behind nginx for TLS:

server {
    listen 443 ssl;
    server_name git.example.com;

    ssl_certificate /etc/letsencrypt/live/git.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/git.example.com/privkey.pem;

    client_max_body_size 1024M;   # allow large pushes

    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;
    }
}

Update Forgejo's app.ini:

[server]
DOMAIN = git.example.com
ROOT_URL = https://git.example.com/
HTTP_ADDR = 127.0.0.1
HTTP_PORT = 3000
PROTOCOL = http

SSH for Git

You want Git over SSH for push convenience. Two options:

  • Built-in SSH server on a non-22 port: set SSH_PORT = 2222 in app.ini, open it on the firewall. Users push to ssh://git@git.example.com:2222/user/repo.git.
  • System SSH: Forgejo manages keys in ~/.ssh/authorized_keys for the git user. Standard ssh on port 22. Users push to git@git.example.com:user/repo.git — cleaner URL.

System SSH is the cleaner experience. Built-in SSH is the no-firewall-changes option.

CI with Forgejo Actions

Forgejo Actions is GitHub Actions-compatible. To use it:

  1. Enable in app.ini:
    [actions]
    ENABLED = true
  2. Install a runner. Forgejo provides forgejo-runner binary. Register it against your instance with a token from the Forgejo UI.
  3. Add workflow YAMLs under .forgejo/workflows/ in your repo.

For most workflows, GitHub Actions YAML works directly.

Runner sizing: depends on what your workflows do. CPU-bound build workflows want CPU; container-build workflows want disk. Run runners on a separate VPS from the main Forgejo to isolate load.

Mirroring workflows

Common patterns:

Mirror from GitHub to Forgejo

  • In a Forgejo repo's settings → Mirror Settings → Mirror From URL.
  • Pull updates periodically. Good for keeping a local archive of upstream open-source projects.

Mirror from Forgejo to GitHub

  • Settings → Mirror Settings → Push Mirror.
  • Push changes to a public GitHub repo automatically. Useful for projects you maintain primarily on Forgejo but want to be visible on GitHub.

Mirror both directions

Don't. Race conditions. Pick one canonical home.

Backup strategy

Forgejo ships a dump command:

sudo -u git forgejo dump --config /etc/forgejo/app.ini --skip-log

Produces a .zip containing the database, repo files, attachments, and config. Schedule nightly:

# /etc/cron.daily/forgejo-backup
#!/bin/bash
cd /var/backups
sudo -u git forgejo dump \
    --config /etc/forgejo/app.ini \
    --skip-log \
    --file /var/backups/forgejo-$(date +\%F).zip
find /var/backups -name 'forgejo-*.zip' -mtime +14 -delete

Then sync the dump off-host. See Restic with B2.

Performance notes

  • SQLite is fine for solo and small-team use. Switch to PostgreSQL when you have multiple concurrent pushers or more than a few hundred repos.
  • Repo storage is dominated by largest repos. Use Git LFS for binary asset repos.
  • If you enable Forgejo Actions and run lots of CI, the artifact storage grows. Configure cleanup.

Operational patterns

  • Updates: Forgejo releases monthly. Replace the binary, restart the service. Database migrations run on startup.
  • User management: forgejo admin user subcommands for CLI-driven ops.
  • Federation: Forgejo is adding ActivityPub federation gradually. Not load-bearing yet but watch the roadmap.

Gitea differences

Forgejo and Gitea share most code. Differences as of 2026:

  • Forgejo has community governance; Gitea is steered by a commercial entity.
  • Forgejo Actions vs Gitea Actions — broadly compatible.
  • Forgejo federation work is more active.

If you're starting fresh, Forgejo is the more aligned-with- self-hosting-values choice. If you have an existing Gitea deployment, migrating is straightforward (point Forgejo at the Gitea data dir; first-launch migration handles it).

Also Read

« « Back

Powered by WHMCompleteSolution