Use case · Git hosting

Forgejo self-hosted on a dedicated server: install, lock down, keep

To run Forgejo self-hosted, install the signed Linux binary as a systemd service under a git user, finish the web installer through an SSH tunnel as long as the firewall still blocks port 3000, then put nginx in front on 443. Forgejo is the community-governed hard fork of Gitea, distributed under GPL-3.0-or-later since v9.0. One dedicated server carries the forge, its database and Git over SSH; the CI runner belongs on a second machine.

See the machines

What the forge asks of the machine

Forgejo's documentation publishes no RAM or core figure, so this page gives none. What it does state: install git and git-lfs beside the binary; SQLite needs no setup, and the binary guide says it is "apparently" good enough for at least 10 users; for high activity the recommendations page points to MySQL/MariaDB or PostgreSQL, and warns that moving an existing instance to another database is not trivial. Choose the database on day one.

DataWhat makes it growDefault home
Git repositoriespushes, mirrors, migrationsdata/forgejo-repositories under the work path
LFS objectslarge binaries tracked by git-lfsdata/lfs
Actions job logsevery workflow run, kept 365 days by defaultthe storage.actions_log section
Actions artifactsfiles jobs upload, kept 90 days by defaultthe storage.artifacts section
Search indexesissue search (bleve by default), code search if enableddata/indexers

Our reading: disk grows quietly, so size it for repositories, LFS and a year of job logs; memory and cores follow how many people clone, push and search at once.

Why a whole machine for a Git host

A dedicated server is one physical machine rented to one customer: every core, all the memory, the disks and the network port, with root and no other tenant on the hardware. Repository I/O never queues behind another tenant.

The port is unmetered, with no transfer allowance and no overage fee, so CI clones, mirror syncs and LFS pulls cost nothing extra. Every racked single-, dual- and quad-socket server has an out-of-band console (HPE iLO, Dell iDRAC or a Supermicro BMC), which matters on the day an sshd or ufw edit locks you out of the box that also serves Git over SSH. The machines sit on our own autonomous system, AS19624.

Matching a line to the forge

  • Moonshot cartridge: one service per machine. A small team's forge on SQLite fits here. Of the cartridges, only the m510 and m710x carry a console; the rest offer power control alone.
  • Single socket: the service page's web or application server with its database on the same box, i.e. Forgejo plus MariaDB or PostgreSQL.
  • Desktop platform (Intel Core, NVMe, a dedicated GPU): listed for build runners, so it suits forgejo-runner as the second machine.
  • Dual socket: many repositories, a package registry and a busy database side by side.

A racked machine is handed over in about 30 minutes once payment is approved; a built-to-order line takes 4 to 24 hours. Weighing Forgejo against its parent project? Our Gitea setup page covers that side; Forgejo's upgrade guide supports moving from Gitea up to v1.22, by way of Forgejo v10.0.x.

Installing the signed binary

Commands below are Ubuntu, which ships ufw. 17.0.0 was the current stable release when this was written (published 15 October 2026); take the newest from the Forgejo download page. Firewall first: setting IPV6=yes before any allow rule means ufw writes IPv6 copies of every rule, and ufw's default policy drops incoming connections, so port 3000 stays closed on both address families.

sudo sed -i 's/^IPV6=.*/IPV6=yes/' /etc/default/ufw
sudo ufw allow OpenSSH
sudo ufw --force enable
wget https://code.forgejo.org/forgejo/forgejo/releases/download/v17.0.0/forgejo-17.0.0-linux-amd64
wget https://code.forgejo.org/forgejo/forgejo/releases/download/v17.0.0/forgejo-17.0.0-linux-amd64.asc
gpg --keyserver keys.openpgp.org --recv EB114F5E6C0DC2BCDD183550A4B61A2DC5923710
gpg --verify forgejo-17.0.0-linux-amd64.asc forgejo-17.0.0-linux-amd64

Go on only if gpg reports a good signature. Then the git user, the data and config directories with the permissions from the binary guide, and the project's own systemd unit:

sudo apt install git git-lfs
sudo cp forgejo-17.0.0-linux-amd64 /usr/local/bin/forgejo
sudo chmod 755 /usr/local/bin/forgejo
sudo adduser --system --shell /bin/bash --gecos 'Git Version Control' \
  --group --disabled-password --home /home/git git
sudo mkdir /var/lib/forgejo /etc/forgejo
sudo chown git:git /var/lib/forgejo && sudo chmod 750 /var/lib/forgejo
sudo chown root:git /etc/forgejo && sudo chmod 770 /etc/forgejo
sudo wget -O /etc/systemd/system/forgejo.service https://codeberg.org/forgejo/forgejo/raw/branch/forgejo/contrib/systemd/forgejo.service
sudo systemctl daemon-reload
sudo systemctl enable --now forgejo.service

On MySQL/MariaDB or PostgreSQL, prepare the database first and uncomment the Wants= and After= lines for it in the unit.

First run: the installer, then the lock

Until the installer runs, whoever reaches port 3000 configures the instance. Reach it only through your own login:

  1. From your workstation run ssh -N -L 3000:127.0.0.1:3000 you@server and open http://localhost:3000.
  2. Pick the database, set Server Domain to your name (git.example.com) and the Base URL to https://git.example.com/, since a proxy will front it.
  3. Fill in Administrator Account Settings so the first account is yours, not the first visitor's.
  4. Press Install Forgejo. The installer writes /etc/forgejo/app.ini and closes its own page by setting INSTALL_LOCK = true under [security].

Stop the service, make the config read-only for Forgejo with sudo chmod 750 /etc/forgejo && sudo chmod 640 /etc/forgejo/app.ini, and as root set these keys in app.ini, keeping whatever else the installer wrote:

[server]
HTTP_ADDR = 127.0.0.1
DOMAIN = git.example.com
SSH_DOMAIN = git.example.com
ROOT_URL = https://git.example.com/

[service]
DISABLE_REGISTRATION = true

[security]
INSTALL_LOCK = true

Start it again, put nginx in front with proxy_pass http://127.0.0.1:3000 as in Forgejo's reverse-proxy guide, add a certificate, and run sudo ufw allow 80,443/tcp. With sign-ups closed, accounts come from the CLI: sudo -u git forgejo -w /var/lib/forgejo -c /etc/forgejo/app.ini admin user create --username alice --email alice@example.com --random-password prints a generated password, so none sits in shell history or ps, which is where the --password flag would leave it. Add --admin for a second administrator.

app.ini holds SECRET_KEY and INTERNAL_TOKEN. Lose SECRET_KEY and data encrypted with it, such as 2FA secrets, can no longer be decrypted. Keep the file at 640 root:git and in every backup.

Git over SSH: host sshd or built-in

  • Host OpenSSH, the git user (default, and Forgejo's recommended practice): Forgejo maintains ~git/.ssh/authorized_keys, clone URLs read git@git.example.com:org/repo.git on port 22. Add a Match User git block with AcceptEnv GIT_PROTOCOL to sshd_config for Git's wire protocol v2. With many users, AuthorizedKeysCommand calling forgejo keys avoids sshd reading one large file on every login.
  • Built-in server: START_SSH_SERVER = true runs Forgejo's own SSH listener on SSH_LISTEN_PORT, while SSH_PORT sets the port printed in clone URLs. Open that port in ufw, and back up the files named by SSH_SERVER_HOST_KEYS or clients will see host-key errors after a restore.

Forgejo Actions and the runner

Forgejo schedules workflows from .forgejo/workflows but does not run them; the separate Forgejo Runner fetches and executes jobs. It ships as a binary, an OCI image and distribution packages. Its docs call it what it is, remote code execution, and a job with the host label has no isolation at all: one job can permanently destroy the host. Keep the runner off the forge's machine.

Register it at the tightest scope that works: a repository, a user or organisation, or the whole instance at /admin/actions/runners. The UUID and token Forgejo shows go into the runner's config file under server.connections; that file is now a credential, so chmod 600 it. Labels pick the job environment: Docker, LXC or the bare host. If you run runners for GitHub too, our GitHub Actions runner page covers that agent; for pipelines that live outside the forge, see Jenkins on its own server.

Backups, upgrades and release lines

Forgejo's backup guide strongly recommends stopping Forgejo while you back up, because repositories on disk and the database must match. forgejo dump packs repositories, database and config into one archive. Create a private directory once with sudo install -d -m 700 -o git -g git /var/backups/forgejo, then: sudo systemctl stop forgejo, sudo -u git forgejo -w /var/lib/forgejo -c /etc/forgejo/app.ini dump --file /var/backups/forgejo/forgejo-$(date +%F).zip, sudo systemctl start forgejo. The archive includes app.ini and its secrets; copy it off this machine yourself.

Release lines are compared in the FAQ below. As of writing, 17.0 is stable until 28 January 2027 and 15.0 LTS until 15 July 2027. A full backup is required before a major jump (v17.0 to v18.0). The order: forgejo manager flush-queues while the service still runs, stop it and back up, replace the binary, start it, then forgejo doctor check --all. Run both commands as git with the same -w and -c flags as the dump.

Licence, history and when to choose otherwise

Forgejo began in October 2022 after Gitea's domains and trademark moved to a for-profit company; its domains are held by the non-profit Codeberg e.V. It became a hard fork early in 2024. Versions up to v8.0 are MIT; v9.0 and later are GPL v3 or later. The project's licence notice says anyone running its official binaries or images is very unlikely to be affected and may sell hosting; redistributing a build obliges you to provide its full source, modifications included, under the same terms.

Windows is out: the project dropped Windows support in 2024, so this is a Linux job. If you want one product with integrated CI/CD, a container registry and a heavier admin surface, compare our GitLab server page.

Questions

Can an existing Gitea instance move to Forgejo?

Yes, within limits. Forgejo's upgrade guide supports Gitea up to and including v1.22: upgrade it to Forgejo v10.0.x first, then to any later Forgejo release. A Gitea newer than that is not guaranteed to migrate, because the two projects no longer share a codebase.

Which release line belongs on a production forge?

The yearly LTS if you want few upgrades: it gets critical and security fixes for 15 months. The quarterly stable line gets full support for three months plus a two-week overlap, so it means four major upgrades a year.

Does Forgejo run on Windows Server?

No. Forgejo dropped Windows support in 2024 and publishes Linux binaries and container images. Install a Linux image from the control panel; Linux images carry no licence charge.

Can the runner share the forge's server?

It can, but the runner executes whatever a workflow says, and with the host label nothing is isolated. A second machine keeps a hostile or broken job away from your repositories and app.ini secrets.

Size the machine for your forge

Compare every dedicated line by processor, memory, disks and port, then configure one for Forgejo and, if you want it, a second for the runner.

See the machines

Related on Server Room

Other use cases