How to Use Gitea: The Beginner's Guide to Your Own Git Server
CodexFuse Team · 2026-10-31T03:57:27.257Z · 15 min read
How to Use Gitea: The Beginner's Guide to Your Own Git Server
Learning how to use Gitea is the moment a developer stops renting their code history and starts owning it. Gitea is an open-source, self-hosted Git service written in Go that gives you GitHub-like functionality — repositories, issues, pull requests, user management, and CI/CD — on a server you control. A full install needs about a gigabyte of RAM, one static binary or one Docker container, and roughly twenty minutes. This gitea for beginners guide runs the whole ladder on the current stack: binary versus Docker install, the first-run web wizard, SSH keys, your first repository and the clone-push round trip, HTTPS behind a reverse proxy, one real Gitea Actions workflow, and the backup habit that keeps a self-hosted forge safe. Run a YAML validator over every workflow file you write in the Actions section before you push it — a bad indent is the number-one reason a first workflow fails silently.
You will build in this order: pick a server, choose binary or Docker, run the installer wizard, create the admin account, add an SSH key, push your first repo, put the whole thing behind HTTPS, run one CI workflow, and schedule the backup. Nothing in this guide assumes you have run a Git server before — only that you have used Git locally. If the local commands feel new, read the Git beginner guide first; this guide starts where that one ends.
What is Gitea?
Gitea is a lightweight, self-hosted code hosting platform written in Go that provides GitHub-like functionality — repository management, issue tracking, pull requests, user management, and notifications — on your own server. It installs as a single static binary or a single Docker container, runs happily on a $5 virtual server with 1 GB of RAM, and stores its data in SQLite by default (with MySQL and PostgreSQL supported for larger teams). Because it is a single small program rather than a platform of a dozen services, beginners can understand the whole deployment: one process, one config file, one data directory.
Gitea vs GitHub vs GitLab vs Forgejo: which one is actually for you?
Every beginner asks whether they should just use GitHub instead. The honest answer depends on whose computer you want your code to live on. This is the whole decision in one table — and the row that matters most is the RAM column, because that is what decides whether Gitea fits your server.
| Gitea | GitHub | GitLab | Forgejo | |
|---|---|---|---|---|
| Where it runs | Your server | GitHub's cloud | Your server or GitLab's cloud | Your server |
| Typical RAM needed | ~1 GB | 0 (hosted) | 4–8 GB | ~1 GB |
| Install shape | Single binary or one container | Nothing to install | Omnibus package, many services | Single binary or one container |
| Actions-style CI | Gitea Actions (same workflow syntax) | GitHub Actions | GitLab CI | Forgejo Actions |
| Best for | Personal code, small teams, homelabs | Open source, collaboration | Full DevOps platform | Gitea users wanting the community fork |
Forgejo is the community fork of Gitea with its own release line — treat it as a comparison point here, not a second guide. The gitea vs forgejo question comes up in every thread because the two feel nearly identical on day one; the real difference is which project's release line you want to follow for the next five years. The rest of this gitea tutorial is the Gitea lane only. And nothing about self-hosting means abandoning GitHub: many developers keep public work on GitHub and private or experimental work on their own Gitea. Read the GitHub beginner guide to see the hosted side of that split, then come back here for the server side.
What do you need before you install Gitea?
Four things, and you probably have three of them already. First, a Linux server you can SSH into — any $5 virtual private server works; if the concept is new, start with what is VPS hosting. Second, Git installed on that server (Gitea requires Git 2.0 or newer, and the official docs tell you to check with git --version before anything else). Third, a domain name pointed at the server — optional for the first install, required once you want real HTTPS. Fourth, a decision about the database: SQLite for your first install, PostgreSQL when you outgrow it. The official binary ships with SQLite, MySQL, and PostgreSQL support built in, so you never reinstall to change databases later — but never mix the two in one arc. This guide's beginner path is SQLite from start to finish, with the Postgres branch clearly marked at the end of the install section.
How do you install Gitea: binary or Docker?
There are two beginner-friendly routes and the right one depends on your server habits. Docker is the recommended path if you already run containers: the official compose file is a few lines of YAML and upgrades are two commands. The binary is the right path if you want to see every file Gitea owns, or your server is too small for a container runtime. Decide with this table, then follow exactly one branch — the whole gitea install takes about ten minutes on the Docker path, a little longer on the binary path.
| Docker route | Binary route | |
|---|---|---|
| You should pick it if | You run other containers and know compose | You want the simplest possible moving parts |
| What you download | One compose file | One static binary from dl.gitea.com |
| Database default | SQLite inside the /data volume | SQLite file beside the binary |
| Upgrades | Edit the tag, pull, up -d | Stop, swap the binary, start |
| Backup | gitea dump inside the container | gitea dump from the shell |
Option A — the Docker route (recommended for most beginners)
The gitea docker route is the fastest way to a running forge. Create a folder, save this as docker-compose.yml, and run docker compose up -d. The image in this example pins the version the official docs used at the time of writing — 28.2.0, released October 18, 2026 — because a pinned tag upgrades on your schedule, not Docker's. If you have never written a compose file, the Docker beginner guide covers the whole runtime first.
networks:
gitea:
external: false
services:
server:
image: docker.gitea.com/gitea:28.2.0
container_name: gitea
environment:
- USER_UID=1000
- USER_GID=1000
restart: always
networks:
- gitea
volumes:
- ./gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "222:22"
Two details beginners always trip on. The 222:22 mapping puts Gitea's integrated SSH on host port 222 because the host's own SSH already owns port 22 — clone with port 222 later and this will make sense. And the USER_UID/USER_GID values must match the owner of your ./gitea folder, or the container fails to start with a permissions error. After docker compose up -d, check docker compose ps, then open http://your-server-ip:3000 for the wizard.
Option B — the binary route
Download the binary for your platform from the official downloads page, make it executable, and put it somewhere permanent. The official docs' own example pins the current release:
wget -O gitea https://dl.gitea.com/gitea/28.2.0/gitea-28.2.0-linux-amd64 chmod +x gitea sudo cp gitea /usr/local/bin/gitea gitea --version
Then create the git system user Gitea will run as, plus the directory layout the docs recommend:
sudo adduser --system --shell /bin/bash --gecos 'Git Version Control' \
--group --disabled-password --home /home/git git
sudo mkdir -p /var/lib/gitea/{custom,data,log}
sudo chown -R git:git /var/lib/gitea/
sudo chmod -R 750 /var/lib/gitea/
sudo mkdir /etc/gitea
sudo chown root:git /etc/gitea
sudo chmod 770 /etc/gitea
Run it once by hand to check for errors, then as a service with systemd (the official "Linux service" page has the full unit file):
GITEA_WORK_DIR=/var/lib/gitea/ /usr/local/bin/gitea web -c /etc/gitea/app.ini
Keep the binary's filename as plain gitea — the docs warn that renaming it with a version number breaks repository hooks on upgrade, because the hooks store the binary's path. Upgrading later is stop, swap the binary, start, then re-check. Since version 1.27 the official binaries are also sigstore-signed, so you can verify the download was not tampered with before you trust it.
How does the first-run install wizard work?
Open http://your-server-ip:3000 and Gitea shows the Install page before anything else. It looks like a lot of fields, but a beginner only needs to touch five. Set the database to SQLite3 and leave the path alone. Set the Repository Root Path to the default. Set the Application URL to the address people will actually reach — https://git.yourdomain.com once DNS is ready, the server IP for now — because Gitea bakes this URL into clone links and notification emails, and changing it later is a chore. Create the administrator account on this same page. Then click Install Gitea.
The one security step beginners skip: disable public registration immediately after install, or your forge becomes a free account farm within days. On Docker, add - GITEA__service__DISABLE_REGISTRATION=true to the environment block and recreate the container — the official docs document the GITEA__section__KEY_NAME pattern for overriding any config value. On the binary install, set DISABLE_REGISTRATION = true under [service] in /etc/gitea/app.ini and restart. When you are ready for Postgres, the production branch is a second container running postgres:18 with GITEA__database__DB_TYPE=postgres and the HOST, NAME, USER, PASSWD values pointing at it — the official Docker page documents the full compose for it.
How do you add SSH keys to Gitea?
Gitea manages SSH access itself, so you never edit authorized_keys by hand — the whole gitea ssh setup takes about two minutes. On your own computer — not the server — generate a key if you do not have one:
ssh-keygen -t ed25519 -C "[email protected]" cat ~/.ssh/id_ed25519.pub
In Gitea, click your avatar, go to Settings, then SSH / GPG Keys, and paste the public key. That is the whole procedure. Two things worth knowing: Gitea's built-in SSH server handles the connection (the official docs note you only touch authorized_keys manually if you are not using the built-in server), and the SSH clone URL shows the right port automatically — on the Docker setup above that is port 222, so a clone URL looks like ssh://git@your-server:222/you/hello.git. If a push asks for a password, the usual cause is cloning with the HTTPS URL while expecting key auth, or pasting the private key instead of the .pub file.
How do you create your first Gitea repository and push to it?
Click the plus icon, choose New Repository, name it hello, and create it empty — not with a README. Gitea shows you the exact commands for an empty repo, and the round trip that proves everything works is:
git clone ssh://git@your-server:222/you/hello.git cd hello echo "# hello" > README.md git add README.md git commit -m "First commit from my own forge" git push origin main
Watch the output of the push. The line that says where the commits went is your forge talking back, and from this moment your server is a real Git remote. Create one branch, push it, open a pull request in the web UI, and merge it there — that loop (branch, push, review, merge) is the daily rhythm Gitea exists to host, and it works identically whether the remote is your VPS or GitHub.
How do you put Gitea behind HTTPS?
Gitea listens on plain HTTP at port 3000, so a reverse proxy in front of it is the standard production shape: the proxy terminates TLS and forwards to localhost:3000. Point a DNS A record at your server first — git.yourdomain.com — then put any reverse proxy (Caddy, nginx, Traefik) in front with a proxy rule to the Gitea port. After the proxy is answering on HTTPS, update Gitea's Application URL (ROOT_URL) to the https:// address in the admin settings and restart, so clone URLs, avatars, and notification links all come out correct. Skipping the ROOT_URL update is the classic beginner bug: the site works, but every email link and clone URL still says http://server-ip:3000.
What are Gitea Actions, and how do you run your first workflow?
Gitea Actions is Gitea's built-in CI/CD system, available since version 1.19 and stable enough for production — the Gitea project runs its own repositories on it. It is similar to and mostly compatible with GitHub Actions, so a workflow you learned on GitHub transfers with small edits. Workflows live in .gitea/workflows in your repository. Gitea itself does not execute jobs; a separate program called the Gitea Runner does. The runner is a standalone Go program (a hard fork of nektos/act) that you register against your instance with a token from Site Administration, then run as its own service — one runner on the same VPS is plenty for a beginner.
Here is a first workflow that runs your tests on every push. Save it as .gitea/workflows/ci.yml, run it through a YAML validator first, then push:
name: CI
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run tests
run: echo "Tests would run here"
Open the repository's Actions tab in Gitea and watch the run go green. The security rule the official docs stress: only attach runners you trust to instances you trust. A runner executes arbitrary code from the repository, so a public forge should never share runners with repositories it does not control. For your own private instance, one local runner is the safe, simple default.
How do you back up Gitea so you never lose a repo?
A self-hosted forge is only as safe as its backup habit, and Gitea ships the habit as a single command: gitea dump saves the whole installation — repositories, database, configuration, avatars, attachments — into one timestamped ZIP file. This gitea backup takes minutes and is the single most important habit in this guide. The official backup docs insist on one rule: stop Gitea during the backup, because the database and the repositories change independently and a live backup can capture them out of sync.
sudo systemctl stop gitea sudo -u git /usr/local/bin/gitea dump -c /etc/gitea/app.ini sudo systemctl start gitea
Copy the resulting gitea-dump-<timestamp>.zip off the server — a backup that lives on the same disk as the forge is a souvenir, not a backup. On Docker the same command runs inside the container via docker exec with the container's git user and its config path. Restoring is manual (unzip, move files into place, import the SQL dump, restart), which is exactly why you rehearse it once on a throwaway server before you need it for real. Weekly dumps to off-server storage is the beginner habit; daily is the production one.
7 mistakes every Gitea beginner makes
| Mistake | What goes wrong | The fix |
|---|---|---|
| Leaving registration open | Strangers create accounts on your forge | DISABLE_REGISTRATION=true right after install |
| Wrong ROOT_URL | Clone links and emails point at an IP | Set the https:// URL in admin settings after the proxy is up |
| Cloning the HTTPS URL, expecting SSH auth | Push asks for a password | Use the ssh:// URL, or add credentials for HTTPS |
| Host-volume permission mismatch on Docker | Container exits immediately | Match USER_UID/USER_GID to the ./gitea owner |
| Renaming the binary with a version number | Git hooks break on the next upgrade | Keep the filename as plain gitea |
| Backing up while Gitea is running | Database and repos captured out of sync | Stop the service, dump, start again |
| Pasting the private key into Gitea | Key rejected, or worse, exposed | Paste only the .pub file |
Sources
Release version and date: GitHub go-gitea/gitea releases API (v28.2.0, published 2026-10-18). Install-from-binary procedure, Git 2.0 requirement, git user, directory layout, sigstore signing since v1.27, binary filename and upgrade rule: Gitea official documentation, docs.gitea.com/installation/install-from-binary (crawled 2026-10-31). Docker Compose reference, image tag, UID/GID, volume and port mappings, env-var override pattern, upgrade procedure: Gitea official documentation, docs.gitea.com/installation/install-with-docker (crawled 2026-10-31). Actions compatibility, runner architecture, production status: Gitea official documentation, docs.gitea.com/usage/actions/overview (crawled 2026-10-31). Dump command, stop-during-backup rule, ZIP contents, Docker dump caveats: Gitea official documentation, docs.gitea.com/administration/backup-and-restore (crawled 2026-10-31). Install-guide patterns and feature summary: oneuptime.com install-and-configure guide, the.hosting Windows Server guide, apalrd.net Gitea guide (search evidence, 2026-10-31).
Frequently asked questions
Is Gitea really free?
Yes. Gitea is open-source and free to run with no user limits and no paid tiers — the only cost is the server it runs on, which can be a $5 VPS. There is no "Gitea Pro" holding features hostage.
How much RAM does Gitea need?
About 1 GB is comfortable for personal use and small teams, which is why it fits the cheapest VPS tier. That is the main practical difference from GitLab, which wants 4 GB or more. If your team grows into hundreds of users, move the database to PostgreSQL on a bigger machine.
Can I migrate from GitHub to Gitea?
Yes, and it is a supported path: Gitea's migration tool imports repositories, issues, pull requests, and wikis from GitHub (and GitLab) directly from the web UI. Many teams keep public mirrors on GitHub and make Gitea the private home.
Is Gitea Actions the same as GitHub Actions?
Similar and mostly compatible, not identical. Gitea Actions uses the same workflow YAML syntax and runs many GitHub Actions steps unchanged, but the runners are separate (the Gitea Runner, a Go program) and some GitHub-specific features are absent. A simple CI workflow like the one in this guide transfers with no changes.
What is the difference between Gitea and Forgejo?
Forgejo is a community fork of Gitea with its own release line and direction. For a beginner they install and feel nearly the same; the practical difference is which project's releases you want to follow. This guide covers Gitea only.