Hands-On: Gitea and Forgejo

Updated

October 30, 2026

Hands-On: Gitea and Forgejo

Bring up Forgejo 15 on Linux, push desk-api, tear it down, then read the Gitea file as the same lab with one image line changed.

Examples were checked against the Forgejo 15 LTS docs and Gitea 1.27. You need Docker, or Podman with podman compose. The commands below say docker compose. On Podman, substitute podman compose. Do not point this lab at a Forgejo you already use.

Forgejo

Host port 3000 is HTTP. Host port 2222 is Git SSH, so the lab does not take the machine’s own sshd on port 22. If either host port is already taken, stop. Another forge is probably there.

mkdir -p ~/desk/forgejo-lab
cd ~/desk/forgejo-lab
mkdir -p data
cat > compose.yml <<'EOF'
services:
  server:
    image: codeberg.org/forgejo/forgejo:15
    environment:
      USER_UID: "1000"
      USER_GID: "1000"
      FORGEJO__server__DOMAIN: localhost
      FORGEJO__server__ROOT_URL: http://localhost:3000/
      FORGEJO__server__SSH_PORT: "2222"
      FORGEJO__server__HTTP_PORT: "3000"
    restart: unless-stopped
    volumes:
      - ./data:/data
    ports:
      - "3000:3000"
      - "2222:22"
EOF
docker compose up -d
docker compose ps

USER_UID should be your numeric id (id -u) if 1000 is not you, or the data directory will be owned by the wrong account. Wait until the HTTP port answers:

curl -fsS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3000/

A 200 or a 303 is enough. Open http://localhost:3000/ in a browser. The installation page asks for the administrator. Create that account. Leave the database on SQLite. Submit, then sign in.

Create a repository named desk-api. Empty is fine. The UI shows two clone URLs. The SSH one should contain :2222. If it says port 22, SSH_PORT did not land in app.ini and the compose environment block needs another look.

Push desk-api

~/desk/desk-api is the project from chapter 3. Add this forge as a second remote (chapter 11). Use the HTTP URL from the UI if you have not loaded an SSH key into the forge yet.

cd ~/desk/desk-api
git remote add forgejo http://127.0.0.1:3000/ADMIN/desk-api.git
git push -u forgejo main

Replace ADMIN with the username you just created. The password is the one from the installation page. After the push, the file list in the browser matches git log --oneline locally.

SSH, once the UI has your public key:

git remote set-url forgejo ssh://git@127.0.0.1:2222/ADMIN/desk-api.git

Tear it down

cd ~/desk/forgejo-lab
docker compose down

./data is still on disk. docker compose down does not delete that directory. Delete ~/desk/forgejo-lab when you are finished with the lab. Leave ~/desk/desk-api in place, and remove the remote if you do not want it:

cd ~/desk/desk-api
git remote remove forgejo

The Gitea file

Do not start this while the Forgejo container is still bound to 3000 and 2222. Same lab, other project:

mkdir -p ~/desk/gitea-lab/data
cd ~/desk/gitea-lab
cat > compose.yml <<'EOF'
services:
  server:
    image: docker.io/gitea/gitea:1.27
    environment:
      USER_UID: "1000"
      USER_GID: "1000"
      GITEA__server__DOMAIN: localhost
      GITEA__server__ROOT_URL: http://localhost:3000/
      GITEA__server__SSH_PORT: "2222"
      GITEA__server__HTTP_PORT: "3000"
    restart: unless-stopped
    volumes:
      - ./data:/data
    ports:
      - "3000:3000"
      - "2222:22"
EOF

docker compose up -d, the same installation page, a repository, a push, docker compose down. The screen is Gitea’s. The Git remote is still just a URL.

Done when

  • Forgejo’s UI showed desk-api after git push
  • the SSH clone URL contained port 2222
  • both compose projects are down, and ~/desk/desk-api still has its history
  • you can point at the one line that differs between the two files (the image, and FORGEJO__ versus GITEA__)