Workload · Hosting your team's Git

Gitea self-hosted: your own Git server, set up the safe way

You can run Gitea self-hosted on a very modest machine: its documentation says two cores and one gigabyte of RAM typically do for a small team, and says a Raspberry Pi 3 copes with small workloads. That leaves the real decisions to you: which database to start with, how people will push over SSH, how to keep strangers away from the setup page, and where your builds will run. This guide walks through each one, in the order you will meet them.

The short version
  1. Small teams: 2 cores and 1 GB of memory, per the Gitea docs
  2. Choose SQLite or PostgreSQL before the first install
  3. Admin account created privately, sign-ups closed
  4. Builds run on Gitea Runner, ideally on a second server

Is Gitea the right Git server for you?

Yes, if you want repositories, pull requests, issues and a package registry without a heavyweight install. Gitea is a single program written in Go, MIT licensed, and its stated aim is the easiest way to set up a self-hosted Git service. It also brings its own CI, Gitea Actions, which aims to run GitHub-style workflows.

If your team would rather have one large suite with more built in, and you are happy to give it a lot more memory, read our guide to a self-hosted GitLab server before you decide.

How big a server does it take?

Smaller than you would guess, for Gitea itself. Officially, two processor cores and a gigabyte of memory cover a small team's projects, with Git 2.0.0 or later installed. What grows is everything you add:

  • Your repositories. Every repo, every large file stored with Git LFS and every package you publish lands on the server's disk, so plan storage around your own code, not around Gitea.
  • The database. A separate PostgreSQL or MySQL takes its own share of memory; SQLite runs inside Gitea.
  • Your builds. Compiling and testing is the heavy part. Gitea's docs suggest running build runners on a different machine so a long build cannot slow the website down for everyone else.

So for one small team, Gitea would be happy on a small virtual machine. Bare metal starts to pay off when you add CI, store container images, or want the code on hardware nobody else shares.

The server that fits

Every dedicated server we rent is a whole physical machine: all of its cores, memory and disks are yours, you log in as root, and nobody meters the port, so a busy week of clones and image pulls never adds a line to your invoice. A ready server is handed over within 30 minutes of your payment being approved.

  • Just Gitea for a small group: one of the small cartridge servers, which the catalogue suggests for one job. Gitea with SQLite is exactly one job.
  • Gitea and PostgreSQL for a growing team: an everyday single-processor server, the kind the catalogue describes for sites, apps and databases.
  • Somewhere for builds to run: a second machine. The desktop machines, with a fast processor and a graphics card of their own, are listed for build jobs.

If an update breaks the boot, rack servers and blades give you a console screen and power button through their management controller; the m510 and m710x cartridges have a console too, and the rest of the cartridges offer power control only. And if you want a clean start, the control panel reinstalls the operating system whenever you ask, with no ticket.

SQLite or PostgreSQL: decide on day one

Pick now, because changing later is the risky part. Gitea's database guide warns that converting between engines has had little testing, and that SQLite will not keep up as an instance grows.

For a handful of people who just want somewhere to push, SQLite is simplest: no second container, and the backup command packs the database file with everything else. If you expect the team or the CI traffic to grow, start on PostgreSQL 12 or newer instead; our PostgreSQL server guide covers running it well. MySQL 8.0 and MariaDB 10.4 work too, as long as the database uses utf8mb4.

Up and running in an evening

Below is the simplest setup from Gitea's Docker guide, using SQLite, with the website kept off the public internet until you have finished. If you chose PostgreSQL, use the guide's PostgreSQL example and make the same port change.

networks:
  gitea:
    external: false
services:
  server:
    image: docker.gitea.com/gitea:28.2.0
    container_name: gitea
    environment:
      - USER_UID=1000
      - USER_GID=1000
      - GITEA__database__DB_TYPE=sqlite3
      - GITEA__server__SSH_PORT=222
      - GITEA__service__DISABLE_REGISTRATION=true
    restart: always
    networks:
      - gitea
    volumes:
      - ./gitea:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "127.0.0.1:3000:3000"
      - "222:22"
  1. Install Docker with its Compose plugin on the server, make a folder called gitea, and save the file above inside it as docker-compose.yml.
  2. Inside that folder, create the data folder and give it to user and group 1000, the IDs set in the file: mkdir gitea && chown 1000:1000 gitea. Gitea's Docker guide says the volume should be owned by those IDs.
  3. Start everything with docker compose up -d. docker compose ps shows whether it is running, and docker compose logs tells you why if it is not.
  4. From your own computer, open a tunnel with ssh -L 8080:127.0.0.1:3000 root@your-server and visit http://localhost:8080. Fill in the setup form with your real web address and SSH port 222.

Why 127.0.0.1:3000 and not plain 3000:3000? Docker opens published ports in the firewall by itself, even if ufw says otherwise. Bound to 127.0.0.1, the setup page is visible only through your tunnel.

Keep the keys to the front door

Make yourself the administrator while the site is still private. Running this on the server creates the account and prints a random password, so no password is left behind in your shell history:

docker exec -u git gitea gitea admin user create --admin \
  --username yourname --email you@example.com --random-password

# afterwards, check gitea/gitea/conf/app.ini contains:
# [security]   INSTALL_LOCK = true
# [service]    DISABLE_REGISTRATION = true

Gitea asks you to choose a new password at first sign-in. INSTALL_LOCK = true closes the setup page for good, and with registration disabled only an admin can add accounts, so you invite your team instead of anyone signing up. The app.ini file also holds Gitea's secret keys: keep it readable only by its owner and group (chmod 640), and copy it into your backups.

Now make it public. Put a web server such as Nginx in front with an HTTPS certificate, forward requests to http://localhost:3000 as Gitea's reverse-proxy guide shows, and allow bigger uploads than the default so large pushes do not fail.

Letting your team push over SSH

Inside the container, Gitea brings its own SSH service on port 22. The file above maps it to port 222 on the server, which leaves the normal port 22 free for you to log in and manage the machine. Because SSH_PORT is 222, the copy-to-clipboard clone address in Gitea already includes the right port, so nobody has to remember it. Allow port 222 through your firewall.

Want clone addresses without a port number? Gitea's Docker guide describes giving the container its own IP address so both services can use port 22. That means an additional IPv4 address on your server, which is priced per server on the order page.

Adding builds with Gitea Actions

Gitea Actions has been on by default since version 1.21, but each repository keeps it off until you tick Enable Repository Actions in its settings. Workflows live in .gitea/workflows/ and are written the way GitHub Actions workflows are. If your code stays on GitHub and you only want your own build machine, that is a different setup, covered in our GitHub Actions runner guide.

The work itself is done by a separate program, Gitea Runner (gitea-runner; older guides call it act_runner). Copy a registration token from the runners page in Site Administration, then start the official image on your second server. Put the address and token in a file rather than on the command line, where they would show up in your shell history:

# runner.env  (chmod 600)
GITEA_INSTANCE_URL=https://git.example.com
GITEA_RUNNER_REGISTRATION_TOKEN=paste-the-token-here

docker run -d --name gitea-runner --restart always --privileged \
  --env-file ./runner.env \
  -v ./data:/data \
  -v runner-docker:/var/lib/docker \
  docker.io/gitea/runner:5-dind

This image runs its own private Docker for your jobs, so a build never touches the server's main Docker, which would be as good as root access. It does need --privileged, which gives the runner container wide access to its host. That is one more reason to keep it on a second server and only let it build repositories you trust. Keep the data folder: it holds the runner's registration, and without it the runner signs up again as a new one.

Looking after it

  • Backups: Gitea's backup guide says Gitea must be stopped for a consistent backup. With this setup that is simple: docker compose stop, archive the data folder (tar czf gitea-$(date +%F).tar.gz gitea), then docker compose start, and copy the archive to another machine. gitea dump (docker exec -u git -w /data gitea gitea dump) packs everything into one ZIP in the gitea folder while Gitea is live, so treat it as a second-best copy taken at a quiet hour.
  • Updates: change the version tag in the file, then docker compose pull and docker compose up -d. Your data stays in the gitea folder on the server.
  • Secrets: never lose SECRET_KEY. Gitea uses it to encrypt things like two-factor secrets, and without it they cannot be read back.

Questions people ask

Is Gitea free to self-host?
Yes. Gitea is open source under the MIT licence, and running it on your own server costs nothing beyond the server. Its documentation lists paid commercial support and an Enterprise edition, but you do not need either to run it.
Can I run Gitea and its builds on the same server?
You can, but Gitea's documentation recommends putting runners on separate machines so heavy builds do not slow down the Gitea website. For a tiny team with short builds, one server works. Once builds take minutes, a second server keeps everyone's browsing and pushing quick.
Do my existing GitHub workflow files work?
Gitea aims to match GitHub's workflow format as closely as it can, so many files carry over once moved into .gitea/workflows/. A few actions, including actions/checkout, can fail in repositories that use SHA256 or when Gitea is served from a sub-path. Test each workflow before you rely on it.
What happens if someone finds my setup page first?
Until setup is finished and locked, the installation page is open to whoever reaches it. That is why this guide keeps port 3000 on 127.0.0.1 and has you reach it through an SSH tunnel. Once INSTALL_LOCK = true is set, the page is closed.
Can I move to PostgreSQL later if I start on SQLite?
It is possible, but Gitea's own guide cautions that changing engines after the fact has had little testing and can go wrong. If there is any chance your team will grow, it is easier to start on PostgreSQL from the first install.

Give your code a home of its own

Choose a server for Gitea, and another for your builds if you want one. No contract, and the port is never metered.

Get a server for your Git host

Read next