Gitea is a lightweight, self-hosted Git service: repositories, pull requests, issues, wikis, packages and CI (Gitea Actions, compatible with GitHub Actions workflows). It runs comfortably on a small VPS — a few hundred megabytes of RAM for a team — which makes it a popular alternative to GitHub or GitLab for private code.
(Prefer a community-governed fork? Forgejo is a drop-in alternative with nearly identical setup — see installing Forgejo.)
1. Prepare
You need Docker and Compose (guide) and a domain such as git.example.com pointing to the server.
Gitea needs SSH for git clone git@…. Your server’s own SSH already uses port 22, so the simplest approach is to give Gitea’s SSH port 2222.
2. Compose file
mkdir -p ~/gitea && cd ~/gitea
compose.yaml:
services:
gitea:
image: gitea/gitea:1
container_name: gitea
restart: unless-stopped
environment:
USER_UID: "1000"
USER_GID: "1000"
GITEA__database__DB_TYPE: postgres
GITEA__database__HOST: db:5432
GITEA__database__NAME: gitea
GITEA__database__USER: gitea
GITEA__database__PASSWD: ${DB_PASSWORD}
GITEA__server__DOMAIN: git.example.com
GITEA__server__ROOT_URL: https://git.example.com/
GITEA__server__SSH_DOMAIN: git.example.com
GITEA__server__SSH_PORT: "2222"
GITEA__service__DISABLE_REGISTRATION: "true"
volumes:
- ./data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "127.0.0.1:3000:3000"
- "2222:22"
depends_on:
- db
db:
image: postgres:17
restart: unless-stopped
environment:
POSTGRES_USER: gitea
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: gitea
volumes:
- ./postgres:/var/lib/postgresql/data
echo "DB_PASSWORD=$(openssl rand -base64 24)" > .env
docker compose up -d
The GITEA__section__KEY variables write into Gitea’s app.ini. Pin a specific version tag (e.g. gitea/gitea:1.24) for predictable upgrades.
Open the SSH port:
sudo ufw allow 2222/tcp
3. HTTPS reverse proxy
server {
listen 80;
server_name git.example.com;
client_max_body_size 512M;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d git.example.com
client_max_body_size matters for pushes over HTTPS and for package/LFS uploads.
4. Initial setup
Open https://git.example.com. The installation page is prefilled from the environment variables — check the values and, at the bottom, create the administrator account. With DISABLE_REGISTRATION on, only admins can create users afterwards (Site Administration → User Accounts).
5. Use it
Add your SSH public key under Settings → SSH / GPG Keys, create a repository, then:
git clone ssh://[email protected]:2222/alice/project.git
# or HTTPS
git clone https://git.example.com/alice/project.git
Save the port in ~/.ssh/config so normal git@ URLs work:
Host git.example.com
Port 2222
User git
Migrating from GitHub/GitLab? New Migration imports repositories along with issues, pull requests, releases and wikis.
6. Gitea Actions (CI/CD)
Gitea Actions runs workflows with GitHub Actions syntax. Enable it (on by default in recent versions) and register a runner:
- Site Administration → Actions → Runners → Create new runner → copy the token.
- Run
act_runner(ideally on a separate VPS, since CI jobs run arbitrary code):
services:
runner:
image: gitea/act_runner:latest
restart: unless-stopped
environment:
GITEA_INSTANCE_URL: https://git.example.com
GITEA_RUNNER_REGISTRATION_TOKEN: ${RUNNER_TOKEN}
GITEA_RUNNER_NAME: runner-1
volumes:
- ./runner-data:/data
- /var/run/docker.sock:/var/run/docker.sock
Then add .gitea/workflows/ci.yml to a repository. See Gitea Actions.
7. Mail
Configure SMTP so users get notifications and password resets:
GITEA__mailer__ENABLED: "true"
GITEA__mailer__PROTOCOL: smtp+starttls
GITEA__mailer__SMTP_ADDR: smtp.example.com
GITEA__mailer__SMTP_PORT: "587"
GITEA__mailer__FROM: [email protected]
GITEA__mailer__USER: [email protected]
GITEA__mailer__PASSWD: ${SMTP_PASSWORD}
8. Backups
Gitea’s dump command bundles repositories, database and config:
docker exec -u git gitea gitea dump -c /data/gitea/conf/app.ini -f /data/gitea-dump-$(date +%F).zip
Copy the archive off the server regularly (or back up ./data and a pg_dump of the database). See pg_dump and automated backups.
9. Updates
docker compose pull && docker compose up -d
Read release notes for breaking changes; back up first.
Gitea vs GitLab
GitLab is a complete DevOps platform but needs 4–8 GB of RAM; Gitea does the core Git hosting, code review and CI in a fraction of the resources. For individuals and small teams on a VPS, Gitea is usually the better fit. See self-hosted Git options.
A Docker VPS with 2 GB RAM runs Gitea and PostgreSQL easily; put CI runners on a separate server.