Project guide

Gitea

A lightweight Git forge for small teams that want repositories, issues and code review without a large footprint.

Complexity: Moderate Single binary application with optional external database

What it is

  • Gitea is a self-hosted Git service with repositories, pull requests, issues and basic package workflows.
  • It is often the point where a small operations stack becomes a real internal platform.

When it is a good fit

  • You need private repositories and a clean web UI without running a heavy forge.
  • You want one place for code, issue tracking and release notes for a small team.
  • You are comfortable backing up repository data and keeping a little more state than a simple dashboard requires.

When it is not the best choice

  • You need the full ecosystem and scale expectations of a larger forge platform.
  • Your team depends on complex enterprise workflows or large CI pipelines from the same product.

Minimum VPS requirements

  • 2 vCPU helps during repository operations and upgrades.
  • 2 GB RAM is a sensible baseline.
  • Disk sizing depends on repository growth and binary attachments, not only on the application itself.

Starter install

  • The official Gitea Docker guide uses a very small Compose setup: the container, a persistent `/data` mount, and explicit UID/GID values so the files on disk stay manageable.
  • That is the route I would take first. SQLite is acceptable for a small team, and it lets you get the service online before deciding whether a separate database is worth the extra moving part.
services:
  gitea:
    image: docker.gitea.com/gitea:1
    restart: unless-stopped
    environment:
      USER_UID: "1000"
      USER_GID: "1000"
    ports:
      - "127.0.0.1:3000:3000"
      - "2222:22"
    volumes:
      - ./data:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
  • Create the service directory, make sure the mounted data path has ownership that matches the UID and GID passed to the container, then start it with `docker compose up -d`.
  • Open the first-run wizard through nginx and set the external URL carefully. Clone links become annoying to clean up if this is wrong on day one.
  • If you do not need SSH clone access immediately, you can keep the web UI online first and add the SSH listener once the rest of the setup is settled.
  • Before inviting other users, create a test repository and verify clone, push and issue creation from a clean client.

Deployment notes

  • Decide early whether SQLite is enough or whether you already want PostgreSQL or MariaDB for the long term.
  • Keep the SSH and HTTP access plan clear from the start so URLs do not need to be rewritten later.
  • Treat repository storage as the primary state and plan backups before inviting more users.

Reverse proxy / nginx notes

  • Use nginx for TLS termination and pass the web interface to the container over the local network.
  • Set the external URL correctly so clone links and callback URLs stay stable.
  • If you only expose HTTP through nginx, document separately how SSH clone access is handled.

Data, volumes and backups

  • Back up repositories, attachments, configuration and the selected database together.
  • Repository integrity matters more than convenience exports, so test restores occasionally.
  • Before larger upgrades, take a named snapshot of both volumes and the Compose definition.

Updates and maintenance

  • Review disk growth and user-generated artifacts monthly.
  • Keep upgrade windows predictable because migrations and repository checks can take time.
  • Test clone, push and web login after each update instead of checking only the landing page.

Common pitfalls

  • A forge accumulates critical state quickly, so ad hoc backup habits become risky fast.
  • Changing external URLs later creates cleanup work across remotes, hooks and user habits.
  • It is easy to underestimate how much disk attachments and package data will consume.

Alternatives

  • Forgejo if you prefer that fork and ecosystem direction.
  • cgit if you only need read-only repository browsing.