Gitea: Self-Hosted Git Server on Docker
Set up Gitea on Docker for a self-hosted GitHub alternative: code hosting, issue tracking, pull requests, and CI/CD pipelines on your own server.
Gitea is a self-hosted Git service: your own GitHub, running on your homelab. It handles repositories, issues, pull requests, code review, and (with Gitea Actions) CI/CD pipelines. The interface is familiar if you’ve used GitHub, and it runs in a single lightweight container.
Reasons to self-host your Git repos: privacy for personal projects, keeping code off third-party servers, having a backup of all your GitHub repos, or just wanting to run your own infrastructure. Gitea is the right tool for all of these.
Gitea’s built-in wiki is fine for a README-sized amount of documentation. Once you’re writing more than that, it’s worth looking at a dedicated tool instead: BookStack vs Outline vs Wiki.js compares the three on what they actually cost you in dependencies and RAM.
Installation
Gitea needs a database. PostgreSQL is the recommended choice for anything beyond minimal use. That makes this a two-container stack rather than a single service, so it’s a step up from the simplest deployments (Docker Compose basics if depends_on and named services are new to you).
mkdir -p /opt/gitea
Create /opt/gitea/docker-compose.yml:
services:
gitea:
image: gitea/gitea:latest
container_name: gitea
environment:
- USER_UID=1000
- USER_GID=1000
- GITEA__database__DB_TYPE=postgres
- GITEA__database__HOST=gitea-db:5432
- GITEA__database__NAME=gitea
- GITEA__database__USER=gitea
- GITEA__database__PASSWD=changeme
volumes:
- /opt/gitea/data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "222:22"
depends_on:
- gitea-db
restart: unless-stopped
gitea-db:
image: postgres:16-alpine
container_name: gitea-db
environment:
- POSTGRES_USER=gitea
- POSTGRES_PASSWORD=changeme
- POSTGRES_DB=gitea
volumes:
- /opt/gitea/pgdata:/var/lib/postgresql/data
restart: unless-stopped
USER_UID and USER_GID: Run Gitea as your regular user. Check your UID with id -u and GID with id -g.
Port 222: SSH for Git operations. Maps to a non-standard port because port 22 is usually used by the host’s SSH. You’ll configure Git clients to use this port for SSH operations.
changeme: Update the database password in both the gitea and gitea-db environment sections.
Start Gitea
cd /opt/gitea
docker compose up -d
Access the setup page at http://YOUR_SERVER_IP:3000. The first time you open Gitea, it shows an installation wizard.
Initial Configuration
The install wizard pre-fills most settings from your environment variables. Verify and adjust:
Database settings: should be pre-filled from your compose env vars.
General settings:
- Site Title: Whatever you want to call your instance
- Repository Root Path:
/data/gitea/repositories: leave as default - Git LFS Root Path:
/data/git/lfs: leave as default - Server Domain: Your server IP or domain name
- SSH Server Port:
222: match what you mapped in compose - Gitea HTTP Listen Port:
3000 - Gitea Base URL:
http://YOUR_SERVER_IP:3000(or your domain if using a reverse proxy)
Admin account: Create your admin user at the bottom of the page.
Click Install Gitea.
Creating Your First Repository
After logging in:
- Click + > New Repository
- Fill in name, description, visibility
- Initialize with a README if it’s a new project
You can clone via HTTPS or SSH.
HTTPS clone:
git clone http://YOUR_SERVER_IP:3000/username/repo-name.git
SSH clone (requires SSH key setup, see below):
git clone ssh://git@YOUR_SERVER_IP:222/username/repo-name.git
SSH Key Setup
For SSH access, add your public key to Gitea:
Settings > SSH / GPG Keys > Add Key
Paste your public key (~/.ssh/id_ed25519.pub or ~/.ssh/id_rsa.pub).
Then configure SSH to use port 222 for your Gitea server. Add to ~/.ssh/config on your local machine:
Host your-server-ip
Port 222
User git
Test it:
ssh -T git@your-server-ip -p 222
You should see a message confirming you’re authenticated as your Gitea user.
Mirroring from GitHub
Gitea can mirror GitHub repositories, which is useful for keeping local copies of all your GitHub repos.
Create repository > Settings > enable “Mirror”, then set the source URL.
For bulk mirroring, Gitea has a migration wizard:
- + > Migrate
- Choose GitHub as the source
- Enter your GitHub access token and username
- Gitea lists all your repositories; select which to mirror
Mirrored repos sync automatically on a schedule you configure.
Gitea Actions (CI/CD)
Gitea Actions is compatible with GitHub Actions syntax. your existing .github/workflows/ files work with minor changes. To use it:
- Enable Actions in Gitea admin settings
- Deploy a Gitea Actions runner (a separate container that actually runs the workflows)
Create /opt/gitea-runner/docker-compose.yml:
services:
gitea-runner:
image: gitea/act_runner:latest
container_name: gitea-runner
environment:
- GITEA_INSTANCE_URL=http://YOUR_SERVER_IP:3000
- GITEA_RUNNER_REGISTRATION_TOKEN=
volumes:
- /opt/gitea-runner/data:/data
- /var/run/docker.sock:/var/run/docker.sock
restart: unless-stopped
Get the registration token from Gitea admin panel > Settings > Actions > Runners > Create new Runner. Add it to GITEA_RUNNER_REGISTRATION_TOKEN.
Backups
Back up both the data directory and database:
# Database dump
docker exec gitea-db pg_dump -U gitea gitea > /backup/gitea-db-$(date +%Y%m%d).sql
# Data directory (repositories, config, attachments)
tar -czf /backup/gitea-data-$(date +%Y%m%d).tar.gz /opt/gitea/data/
The data directory contains all your repositories in bare Git format. A proper backup includes both the database (issues, users, pull requests) and the repository files.
This is a case where a half-backup looks complete and isn’t: restore only the data directory and you get every commit back with none of the issues or pull requests. Test the pair together before you rely on it, which is what the homelab disaster recovery guide walks through for exactly this kind of app-plus-database service.
Updating
cd /opt/gitea
docker compose pull
docker compose up -d
Gitea handles database migrations automatically on startup. Check the release notes before major version updates. They occasionally include manual steps for significant migrations.