
Gitea (Git with a cup of tea) é a forge self-hosted em Go: repositório Git, PR, issues, wiki, registry de pacotes e CI/CD no mesmo binário. Fork do Gogs em 2016, MIT, cabe num VPS de 1 GB. A versão estável em setembro de 2026 é a 1.27.3. Este texto sobe a instância com Docker Compose e MariaDB, registra o Gitea Actions Runner e instala o CLI oficial tea.
O Git em si — BitKeeper, os dez dias de Linus, o 2.55 — está em A história do Git. O cheatsheet do dia a dia, em Git simples e rápido. Aqui o assunto é a forge: o GitHub que você roda na sua máquina.
O que o Gitea é (e o que não é)
Não é GitLab CE. Não puxa Elasticsearch, não pede 8 GB de RAM para o hello world. É um binário (ou um container) + um banco. O Gitea fala com SQLite3, MySQL/MariaDB, PostgreSQL e MSSQL. SQLite vem embutido e resolve lab, Raspberry Pi e um usuário só — o arquivo fica no volume /data. Em produção com time e Actions, use MariaDB (ou MySQL: o driver no Gitea é o mesmo, DB_TYPE=mysql). Actions desde 1.19 (ligado por default desde 1.21): o YAML é o da GitHub Actions, o executor é o runner próprio. O tea é o gh dessa casa.
Forgejo é o fork comunitário (2022) com a mesma API. Se o seu objetivo é “GitHub Actions em casa, leve”, Gitea 1.27 resolve. Código: github.com/go-gitea/gitea. Docs: docs.gitea.com.
Subir com Docker Compose e MariaDB
Imagem oficial: docker.gitea.com/gitea:1.27.3. Porta 3000 na web, 222 no host mapeada no SSH interno (22 do container) para não brigar com o sshd da máquina. MariaDB 11 no mesmo compose — o Gitea trata MariaDB como MySQL na config.
mkdir -p ~/gitea && cd ~/gitea
networks:
gitea:
volumes:
gitea-data:
mariadb-data:
services:
server:
image: docker.gitea.com/gitea:1.27.3
container_name: gitea
restart: always
environment:
USER_UID: "1000"
USER_GID: "1000"
GITEA__database__DB_TYPE: mysql
GITEA__database__HOST: db:3306
GITEA__database__NAME: gitea
GITEA__database__USER: gitea
GITEA__database__PASSWD: gitea
networks:
- gitea
volumes:
- gitea-data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "222:22"
depends_on:
- db
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/"]
interval: 10s
timeout: 5s
retries: 6
start_period: 30s
db:
image: docker.io/library/mariadb:11
restart: always
environment:
MARIADB_ROOT_PASSWORD: gitea
MARIADB_DATABASE: gitea
MARIADB_USER: gitea
MARIADB_PASSWORD: gitea
networks:
- gitea
volumes:
- mariadb-data:/var/lib/mysql
command: ["--character-set-server=utf8mb4", "--collation-server=utf8mb4_bin"]
docker compose up -d
docker compose ps
docker compose logs -f server
Abra http://IP:3000 e complete o assistente. Hostname do banco: db (nome do serviço), não localhost. Tipo: MySQL (é o que a UI mostra para MariaDB). Depois do wizard o app.ini fica em /data/gitea/conf/app.ini no volume. Qualquer chave dá para sobrescrever com env no formato GITEA__secao__CHAVE.
Clone por SSH usa a porta 222:
git clone ssh://git@SEU_IP:222/usuario/repo.git
Chave pública: SSH sem senha. Em produção coloque HTTPS na frente (nginx/Caddy) e ajuste ROOT_URL no app.ini.
SQLite: um container, zero banco extra
Para testar na máquina ou num Pi, tire o serviço db e não passe GITEA__database__*. O Gitea cria sozinho um SQLite em /data/gitea/gitea.db.
services:
server:
image: docker.gitea.com/gitea:1.27.3
container_name: gitea
restart: always
environment:
USER_UID: "1000"
USER_GID: "1000"
volumes:
- ./gitea-data:/data
ports:
- "3000:3000"
- "222:22"
No assistente escolha SQLite3. Serve para um usuário e poucos repos. Com time, CI e registry, fique no MariaDB — SQLite trava o arquivo no dump concorrente e no job pesado.
Binário, se não quiser container
sudo wget -O /usr/local/bin/gitea \
https://dl.gitea.com/gitea/1.27.3/gitea-1.27.3-linux-amd64
sudo chmod +x /usr/local/bin/gitea
sudo mkdir -p /var/lib/gitea /etc/gitea
sudo adduser --system --group --home /var/lib/gitea git
GITEA_WORK_DIR=/var/lib/gitea /usr/local/bin/gitea web -c /etc/gitea/app.ini
O binário já traz SQLite. MariaDB/MySQL e Postgres entram no app.ini ([database] → DB_TYPE = mysql ou sqlite3). A partir da 1.27 os binários vêm com assinatura Sigstore. Lista e hashes: dl.gitea.com/gitea.
Gitea Actions e o Runner
O Gitea não executa o workflow sozinho. Quem puxa o job é o runner — o binário atual chama-se gitea-runner (o repositório antigo era act_runner; a imagem oficial em 2026 é docker.io/gitea/runner:3). Actions vêm ligadas por default desde 1.21. O YAML vive em .gitea/workflows/ e aceita o mesmo esquema da GitHub Actions.
Token: Site Administration → Actions → Runners → Create new runner token. Rode o runner em outra máquina se puder — ele come CPU/RAM do job, não da forge.
# no mesmo compose, ou noutro host
services:
runner:
image: docker.io/gitea/runner:3
restart: always
environment:
GITEA_INSTANCE_URL: "http://server:3000"
GITEA_RUNNER_REGISTRATION_TOKEN: "COLE_O_TOKEN"
GITEA_RUNNER_NAME: "linuxpro-1"
volumes:
- ./runner-data:/data
- /var/run/docker.sock:/var/run/docker.sock
depends_on:
server:
condition: service_healthy
O tag :3 usa o Docker do host (monte o socket). Para isolamento, gitea/runner:3-dind sobe um dockerd próprio e pede --privileged. Persistência: o volume /data guarda o arquivo de registro (.runner). Sem ele, cada recreate vira um runner novo e o token antigo fica órfão na UI.
Workflow mínimo no repositório:
# .gitea/workflows/ci.yml
name: ci
on:
push:
branches: [main]
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: echo ok && uname -a
O contexto no YAML usa gitea.sha no lugar de github.sha quando for específico da forge; a maior parte das actions públicas funciona. CI/CD no sentido de pipeline: DevOps, o que é CI/CD?.
tea CLI
tea é o cliente oficial (MIT, Go). Issues, PR, release, login em várias instâncias, tea pr checkout no repositório local. A estável em agosto de 2026 é a 0.15.1.
sudo curl -fsSL -o /usr/local/bin/tea \
https://dl.gitea.com/tea/0.15.1/tea-0.15.1-linux-amd64
sudo chmod +x /usr/local/bin/tea
tea --version
Token: Settings → Applications → Generate New Token (escopos: repo, issue, write:repository). Login:
tea login add --name casa --url http://SEU_IP:3000 --token SEU_TOKEN
tea login list
tea repos
tea issues
tea pulls
Dentro de um clone hospedado nessa instância o tea descobre o remote sozinho. Exemplos do dia:
tea issues list --state open
tea pulls checkout 12
tea pulls review 12 --approve --comment "LGTM"
tea releases create v1.0.0 --note "primeiro corte"
Desde 0.10 existe fluxo OAuth; token continua o caminho mais simples em servidor headless e em job de CI. Binários: dl.gitea.com/tea. Código: gitea.com/gitea/tea.
Backup e upgrade
docker compose exec -u git server gitea dump -c /data/gitea/conf/app.ini
# o zip cai em /data; copie para fora do volume
O dump inclui o banco (MariaDB via dump SQL, SQLite como arquivo). Upgrade: pin a tag no compose (1.27.3 → próxima), docker compose pull && docker compose up -d. Não troque rootful por rootless no mesmo volume. Não rode o dump com a instância no meio de migrate — pare, dump, suba a tag nova.
O que ficou
Gitea 1.27.3 + MariaDB 11 + runner 3 + tea 0.15.1 é uma forge completa em um VPS pequeno. SQLite para o primeiro docker compose up de tarde; MariaDB quando o time e o CI entram. O Git continua o de sempre; a camada social (PR, Actions, registry) é o que o GitHub cobrou e o Gogs não chegou a amarrar.
Mais: história do Git, cheatsheet, Gogs em 2017.