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.
Installation
Gitea needs a database. PostgreSQL is the recommended choice for anything beyond minimal use.
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 — 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.
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.