Gitea and Forgejo are lightweight, self-hosted git services with issues, pull requests, a package registry and a web interface. They are the same idea and, for a while, were the same code, small enough to run comfortably on hardware you would not put a build server on.
Forgejo is a fork of Gitea under community governance. For a first installation the practical difference is small and the setup is close to identical; pick either, and know that instructions for one usually work for the other with the configuration prefix changed.
Close registration, and check you closed it
Out of the box, anyone who can reach the page can create an account. On a server exposed to the internet that is not a feature.
The setting to turn it off exists, and this is where copying an older tutorial bites. The short environment variable that once did the job was removed. The current form is a longer prefixed name, and the old one now does nothing at all. It does not error. It is simply ignored, and the server carries on accepting sign-ups while your compose file appears to say otherwise.
Create your admin account first, then set the current variable, restart, and then actually check by opening the sign-up page in a browser where you are not logged in. This is a case where verifying takes ten seconds and assuming has a long tail.
Take this one seriously. A self-hosted git host holds source code and often deployment credentials, and vulnerabilities in this class of software have been actively exploited.
SSH is the awkward part
Cloning over HTTPS works immediately. SSH is where the setup stops being a copy-paste job, because the server runs its own SSH daemon inside the container and your host is almost certainly already using port 22 for its own.
Two ports, one number. Something has to move, and there are three usual answers.
Publish the container's SSH on a non-standard port, and accept that clone URLs carry a port number. Move the host's own SSH to a different port and give the container 22, which is tidy for users and a decision to make carefully on a machine you administer remotely. Or forward from the host into the container, which keeps both on familiar ports at the cost of a piece of configuration that is easy to forget exists.
None is wrong. The confusion comes from guides that pick one method silently. A compose file from one article and an SSH instruction from another will conflict.
The user ID advice is contradictory because the answer depends
Some guides insist you set the user and group IDs to match your own; others say it is unnecessary. Both are right about different setups.
If the data directory is a path on the host, the container's user must be able to write to it, and the IDs have to match the owner. If the data lives in a named volume, Docker handles ownership and the setting is irrelevant.
Decide which you are using first, and the advice stops contradicting itself.
The rootless image is a different shape
There is a variant that runs without root inside the container. It is the better choice on security grounds, but it is not a drop-in substitute. The rootless image runs as a different user and listens on different ports.
A compose file written for the standard image will not work unchanged against the rootless one. If you are following a guide, check which image it uses before wondering why nothing binds.
What to do on the first day
Close registration and verify it. Take a backup of both the data directory and the database, because a git host with no backup is a single disk away from being the reason nobody has the code. And decide the SSH arrangement before anyone clones anything, since changing it later means every existing clone has a stale remote.
Where this comes from, and what will date
Composed from both projects' container documentation together with independent published setups and issue reports about the renamed configuration, cross-checked against each other on 31 August 2026. Configuration variable names often change between major versions. That is the point of the section, not an aside.
The two projects are diverging. They remain close enough that one guide covers both, and that will be less true over time. Check which one a set of instructions was written for, especially where it names a configuration variable.