# Self-hosted Git with Gitea

Running your own Git forge: the server, repositories, and the API the rest of the platform automates against.

# Why self-host Git

Git is distributed, but teams still need a central place to push to, open pull requests, and trigger automation. You could use a SaaS forge — or you could run your own. This lab runs **Gitea** (`GIT-Server`, `10.100.100.2`), a lightweight open-source Git forge.

The reasons fit the lab's goals:

- **It's the hub of the platform.** Code, CI workflows, and (with Gitea Actions) the build pipeline all live here. Owning it keeps the whole software-delivery loop inside one network.
- **It's light.** Gitea is a single Go binary with a small database — it runs comfortably in a tiny VM, unlike heavier forges.
- **It teaches the whole shape** of a forge — repos, users, tokens, webhooks, CI — without a SaaS hiding the moving parts.

> **Why we use this:** self-hosting the forge is what makes the rest of the platform a closed loop you can explain end to end: push here, build on your runner, store in your registry, deploy to your cluster. No step leaves the building.

# The server

Gitea here is a straightforward binary install: the `gitea` service listening on port `3000`, a lightweight database behind it, and its config in one file (`app.ini`). HAProxy at the edge publishes it as `https://git.example.com`.

```
GIT-Server (10.100.100.2)
  gitea  (systemd service, :3000)
  config: /etc/gitea/app.ini
  fronted by HAProxy -> https://git.example.com
```

It's deliberately modest — a single service, a single config file, a single port. That simplicity is a feature: when something needs checking, there's one process and one log to look at (and that log ships to the central store like everything else).

The Gitea **Actions** feature (its built-in CI, compatible with GitHub Actions syntax) is enabled here, with the actual job execution handled by a separate runner VM — that whole story is in *CI/CD & the Container Registry* over in the platform shelf.

> **Why we use this:** a Git forge doesn't need to be heavy to be useful. One binary, one config, one port covers an astonishing amount — repos, users, the API, and CI — for a footprint a 2 GiB VM doesn't notice.

# The API: where automation hooks in

A forge earns its keep through its **API**. Gitea exposes a full REST API, authenticated with a token, and that's how the rest of the platform automates against it: creating repos, managing CI secrets, reading workflow status, even creating the registration token a new CI runner needs.

```
curl -H "Authorization: token <REDACTED>" https://git.example.com/api/v1/...
```

That same API is what makes "infrastructure as code" reach all the way up to the forge itself — repos and their settings can be created and configured programmatically rather than clicked into existence. The CI runner registers through it; build pipelines authenticate through it.

> **Why we use this:** anything with a good API can be automated, version-controlled, and reproduced. The day you want to recreate the whole lab from scratch, "the Git server has an API" is what lets the recreation script set up its own repositories instead of stopping to ask a human to click around.

# Lessons on the Git server

- **Owning the forge closes the loop.** Code → CI → registry → cluster, all in one network you control.
- **Light is fine.** A single Go binary forge is plenty for a lab (and many small teams), and it's a joy to operate.
- **Lean on the API.** It's the seam where automation plugs in — runner registration, repo creation, CI secrets. Treat the forge as something you script, not just click.
- **It still ships logs centrally.** Even the Git server's logs land in Loki, so it's observable like every other box.