{"id":502,"date":"2026-09-06T00:11:12","date_gmt":"2026-09-06T03:11:12","guid":{"rendered":"https:\/\/www.linuxpro.com.br\/2026\/09\/gitea-git-self-hosted-runner-tea\/"},"modified":"2026-09-08T10:05:34","modified_gmt":"2026-09-08T13:05:34","slug":"gitea-git-self-hosted-runner-tea","status":"publish","type":"post","link":"https:\/\/www.linuxpro.com.br\/es\/2026\/09\/gitea-git-self-hosted-runner-tea\/","title":{"rendered":"Gitea: Git self-hosted com Actions, runner e tea CLI"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" alt=\"Mascote do LinuxPro operando o reposit\u00f3rio Git no notebook, com a caneca de ch\u00e1 do Gitea e o servidor pr\u00f3prio ao lado\" src=\"\/wp-content\/uploads\/2026\/09\/gitea-v3.webp\" width=\"1486\" height=\"856\" \/><\/p>\n<p><strong>Gitea<\/strong> (<em>Git with a cup of tea<\/em>) \u00e9 a forge self-hosted em Go: reposit\u00f3rio Git, PR, issues, wiki, registry de pacotes e CI\/CD no mesmo bin\u00e1rio. Fork do <a href=\"\/2017\/04\/instalando-gogs-no-ubuntu\/\">Gogs<\/a> em 2016, MIT, cabe num VPS de 1 GB. A vers\u00e3o est\u00e1vel em setembro de 2026 \u00e9 a <strong>1.27.3<\/strong>. Este texto sobe a inst\u00e2ncia com Docker Compose e <strong>MariaDB<\/strong>, registra o <strong>Gitea Actions Runner<\/strong> e instala o CLI oficial <strong>tea<\/strong>.<\/p>\n<p><!-- more --><\/p>\n<p>O Git em si \u2014 BitKeeper, os dez dias de Linus, o 2.55 \u2014 est\u00e1 em <a href=\"\/2026\/09\/a-historia-do-git\/\">A hist\u00f3ria do Git<\/a>. O cheatsheet do dia a dia, em <a href=\"\/2017\/04\/git-simples-e-rapido\/\">Git simples e r\u00e1pido<\/a>. Aqui o assunto \u00e9 a forge: o GitHub que voc\u00ea roda na sua m\u00e1quina.<\/p>\n<h2>O que o Gitea \u00e9 (e o que n\u00e3o \u00e9)<\/h2>\n<p>N\u00e3o \u00e9 GitLab CE. N\u00e3o puxa Elasticsearch, n\u00e3o pede 8 GB de RAM para o hello world. \u00c9 um bin\u00e1rio (ou um container) + um banco. O Gitea fala com SQLite3, MySQL\/MariaDB, PostgreSQL e MSSQL. <strong>SQLite<\/strong> vem embutido e resolve lab, Raspberry Pi e um usu\u00e1rio s\u00f3 \u2014 o arquivo fica no volume <code>\/data<\/code>. Em produ\u00e7\u00e3o com time e Actions, use <strong>MariaDB<\/strong> (ou MySQL: o driver no Gitea \u00e9 o mesmo, <code>DB_TYPE=mysql<\/code>). Actions desde 1.19 (ligado por default desde 1.21): o YAML \u00e9 o da GitHub Actions, o executor \u00e9 o runner pr\u00f3prio. O <code>tea<\/code> \u00e9 o <code>gh<\/code> dessa casa.<\/p>\n<p>Forgejo \u00e9 o fork comunit\u00e1rio (2022) com a mesma API. Se o seu objetivo \u00e9 \u201cGitHub Actions em casa, leve\u201d, Gitea 1.27 resolve. C\u00f3digo: <a href=\"https:\/\/github.com\/go-gitea\/gitea\">github.com\/go-gitea\/gitea<\/a>. Docs: <a href=\"https:\/\/docs.gitea.com\/\">docs.gitea.com<\/a>.<\/p>\n<h2>Subir com Docker Compose e MariaDB<\/h2>\n<p>Imagem oficial: <code>docker.gitea.com\/gitea:1.27.3<\/code>. Porta 3000 na web, 222 no host mapeada no SSH interno (22 do container) para n\u00e3o brigar com o sshd da m\u00e1quina. MariaDB 11 no mesmo compose \u2014 o Gitea trata MariaDB como MySQL na config.<\/p>\n<pre><code class=\"language-bash\">mkdir -p ~\/gitea &amp;&amp; cd ~\/gitea<\/code><\/pre>\n<pre><code class=\"language-yaml\">networks:\n  gitea:\n\nvolumes:\n  gitea-data:\n  mariadb-data:\n\nservices:\n  server:\n    image: docker.gitea.com\/gitea:1.27.3\n    container_name: gitea\n    restart: always\n    environment:\n      USER_UID: \"1000\"\n      USER_GID: \"1000\"\n      GITEA__database__DB_TYPE: mysql\n      GITEA__database__HOST: db:3306\n      GITEA__database__NAME: gitea\n      GITEA__database__USER: gitea\n      GITEA__database__PASSWD: gitea\n    networks:\n      - gitea\n    volumes:\n      - gitea-data:\/data\n      - \/etc\/timezone:\/etc\/timezone:ro\n      - \/etc\/localtime:\/etc\/localtime:ro\n    ports:\n      - \"3000:3000\"\n      - \"222:22\"\n    depends_on:\n      - db\n    healthcheck:\n      test: [\"CMD\", \"curl\", \"-f\", \"http:\/\/localhost:3000\/\"]\n      interval: 10s\n      timeout: 5s\n      retries: 6\n      start_period: 30s\n\n  db:\n    image: docker.io\/library\/mariadb:11\n    restart: always\n    environment:\n      MARIADB_ROOT_PASSWORD: gitea\n      MARIADB_DATABASE: gitea\n      MARIADB_USER: gitea\n      MARIADB_PASSWORD: gitea\n    networks:\n      - gitea\n    volumes:\n      - mariadb-data:\/var\/lib\/mysql\n    command: [\"--character-set-server=utf8mb4\", \"--collation-server=utf8mb4_bin\"]<\/code><\/pre>\n<pre><code class=\"language-bash\">docker compose up -d\ndocker compose ps\ndocker compose logs -f server<\/code><\/pre>\n<p>Abra <code>http:\/\/IP:3000<\/code> e complete o assistente. Hostname do banco: <code>db<\/code> (nome do servi\u00e7o), n\u00e3o localhost. Tipo: <strong>MySQL<\/strong> (\u00e9 o que a UI mostra para MariaDB). Depois do wizard o <code>app.ini<\/code> fica em <code>\/data\/gitea\/conf\/app.ini<\/code> no volume. Qualquer chave d\u00e1 para sobrescrever com env no formato <code>GITEA__secao__CHAVE<\/code>.<\/p>\n<p>Clone por SSH usa a porta 222:<\/p>\n<pre><code class=\"language-bash\">git clone ssh:\/\/git@SEU_IP:222\/usuario\/repo.git<\/code><\/pre>\n<p>Chave p\u00fablica: <a href=\"\/2017\/04\/ssh-sem-senha\/\">SSH sem senha<\/a>. Em produ\u00e7\u00e3o coloque HTTPS na frente (nginx\/Caddy) e ajuste <code>ROOT_URL<\/code> no <code>app.ini<\/code>.<\/p>\n<h2>SQLite: um container, zero banco extra<\/h2>\n<p>Para testar na m\u00e1quina ou num Pi, tire o servi\u00e7o <code>db<\/code> e n\u00e3o passe <code>GITEA__database__*<\/code>. O Gitea cria sozinho um SQLite em <code>\/data\/gitea\/gitea.db<\/code>.<\/p>\n<pre><code class=\"language-yaml\">services:\n  server:\n    image: docker.gitea.com\/gitea:1.27.3\n    container_name: gitea\n    restart: always\n    environment:\n      USER_UID: \"1000\"\n      USER_GID: \"1000\"\n    volumes:\n      - .\/gitea-data:\/data\n    ports:\n      - \"3000:3000\"\n      - \"222:22\"<\/code><\/pre>\n<p>No assistente escolha <strong>SQLite3<\/strong>. Serve para um usu\u00e1rio e poucos repos. Com time, CI e registry, fique no MariaDB \u2014 SQLite trava o arquivo no dump concorrente e no job pesado.<\/p>\n<h2>Bin\u00e1rio, se n\u00e3o quiser container<\/h2>\n<pre><code class=\"language-bash\">sudo wget -O \/usr\/local\/bin\/gitea \n  https:\/\/dl.gitea.com\/gitea\/1.27.3\/gitea-1.27.3-linux-amd64\nsudo chmod +x \/usr\/local\/bin\/gitea\nsudo mkdir -p \/var\/lib\/gitea \/etc\/gitea\nsudo adduser --system --group --home \/var\/lib\/gitea git\nGITEA_WORK_DIR=\/var\/lib\/gitea \/usr\/local\/bin\/gitea web -c \/etc\/gitea\/app.ini<\/code><\/pre>\n<p>O bin\u00e1rio j\u00e1 traz SQLite. MariaDB\/MySQL e Postgres entram no <code>app.ini<\/code> (<code>[database]<\/code> \u2192 <code>DB_TYPE = mysql<\/code> ou <code>sqlite3<\/code>). A partir da 1.27 os bin\u00e1rios v\u00eam com assinatura Sigstore. Lista e hashes: <a href=\"https:\/\/dl.gitea.com\/gitea\/\">dl.gitea.com\/gitea<\/a>.<\/p>\n<h2>Gitea Actions e o Runner<\/h2>\n<p>O Gitea n\u00e3o executa o workflow sozinho. Quem puxa o job \u00e9 o <strong>runner<\/strong> \u2014 o bin\u00e1rio atual chama-se <code>gitea-runner<\/code> (o reposit\u00f3rio antigo era <code>act_runner<\/code>; a imagem oficial em 2026 \u00e9 <code>docker.io\/gitea\/runner:3<\/code>). Actions v\u00eam ligadas por default desde 1.21. O YAML vive em <code>.gitea\/workflows\/<\/code> e aceita o mesmo esquema da GitHub Actions.<\/p>\n<p>Token: Site Administration \u2192 Actions \u2192 Runners \u2192 Create new runner token. Rode o runner em outra m\u00e1quina se puder \u2014 ele come CPU\/RAM do job, n\u00e3o da forge.<\/p>\n<pre><code class=\"language-yaml\"># no mesmo compose, ou noutro host\nservices:\n  runner:\n    image: docker.io\/gitea\/runner:3\n    restart: always\n    environment:\n      GITEA_INSTANCE_URL: \"http:\/\/server:3000\"\n      GITEA_RUNNER_REGISTRATION_TOKEN: \"COLE_O_TOKEN\"\n      GITEA_RUNNER_NAME: \"linuxpro-1\"\n    volumes:\n      - .\/runner-data:\/data\n      - \/var\/run\/docker.sock:\/var\/run\/docker.sock\n    depends_on:\n      server:\n        condition: service_healthy<\/code><\/pre>\n<p>O tag <code>:3<\/code> usa o Docker do host (monte o socket). Para isolamento, <code>gitea\/runner:3-dind<\/code> sobe um dockerd pr\u00f3prio e pede <code>--privileged<\/code>. Persist\u00eancia: o volume <code>\/data<\/code> guarda o arquivo de registro (<code>.runner<\/code>). Sem ele, cada recreate vira um runner novo e o token antigo fica \u00f3rf\u00e3o na UI.<\/p>\n<p>Workflow m\u00ednimo no reposit\u00f3rio:<\/p>\n<pre><code class=\"language-yaml\"># .gitea\/workflows\/ci.yml\nname: ci\non:\n  push:\n    branches: [main]\n  pull_request:\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\/checkout@v4\n      - run: echo ok &amp;&amp; uname -a<\/code><\/pre>\n<p>O contexto no YAML usa <code>gitea.sha<\/code> no lugar de <code>github.sha<\/code> quando for espec\u00edfico da forge; a maior parte das actions p\u00fablicas funciona. CI\/CD no sentido de pipeline: <a href=\"\/2019\/12\/devops-ci-cd\/\">DevOps, o que \u00e9 CI\/CD?<\/a>.<\/p>\n<h2>tea CLI<\/h2>\n<p><code>tea<\/code> \u00e9 o cliente oficial (MIT, Go). Issues, PR, release, login em v\u00e1rias inst\u00e2ncias, <code>tea pr checkout<\/code> no reposit\u00f3rio local. A est\u00e1vel em agosto de 2026 \u00e9 a <strong>0.15.1<\/strong>.<\/p>\n<pre><code class=\"language-bash\">sudo curl -fsSL -o \/usr\/local\/bin\/tea \n  https:\/\/dl.gitea.com\/tea\/0.15.1\/tea-0.15.1-linux-amd64\nsudo chmod +x \/usr\/local\/bin\/tea\ntea --version<\/code><\/pre>\n<p>Token: Settings \u2192 Applications \u2192 Generate New Token (escopos: repo, issue, write:repository). Login:<\/p>\n<pre><code class=\"language-bash\">tea login add --name casa --url http:\/\/SEU_IP:3000 --token SEU_TOKEN\ntea login list\ntea repos\ntea issues\ntea pulls<\/code><\/pre>\n<p>Dentro de um clone hospedado nessa inst\u00e2ncia o <code>tea<\/code> descobre o remote sozinho. Exemplos do dia:<\/p>\n<pre><code class=\"language-bash\">tea issues list --state open\ntea pulls checkout 12\ntea pulls review 12 --approve --comment \"LGTM\"\ntea releases create v1.0.0 --note \"primeiro corte\"<\/code><\/pre>\n<p>Desde 0.10 existe fluxo OAuth; token continua o caminho mais simples em servidor headless e em job de CI. Bin\u00e1rios: <a href=\"https:\/\/dl.gitea.com\/tea\/\">dl.gitea.com\/tea<\/a>. C\u00f3digo: <a href=\"https:\/\/gitea.com\/gitea\/tea\">gitea.com\/gitea\/tea<\/a>.<\/p>\n<h2>Backup e upgrade<\/h2>\n<pre><code class=\"language-bash\">docker compose exec -u git server gitea dump -c \/data\/gitea\/conf\/app.ini\n# o zip cai em \/data; copie para fora do volume<\/code><\/pre>\n<p>O dump inclui o banco (MariaDB via dump SQL, SQLite como arquivo). Upgrade: pin a tag no compose (<code>1.27.3<\/code> \u2192 pr\u00f3xima), <code>docker compose pull &amp;&amp; docker compose up -d<\/code>. N\u00e3o troque rootful por rootless no mesmo volume. N\u00e3o rode o dump com a inst\u00e2ncia no meio de migrate \u2014 pare, dump, suba a tag nova.<\/p>\n<h2>O que ficou<\/h2>\n<p>Gitea 1.27.3 + MariaDB 11 + runner 3 + tea 0.15.1 \u00e9 uma forge completa em um VPS pequeno. SQLite para o primeiro <code>docker compose up<\/code> de tarde; MariaDB quando o time e o CI entram. O Git continua o de sempre; a camada social (PR, Actions, registry) \u00e9 o que o GitHub cobrou e o Gogs n\u00e3o chegou a amarrar.<\/p>\n<p>Mais: <a href=\"\/2026\/09\/a-historia-do-git\/\">hist\u00f3ria do Git<\/a>, <a href=\"\/2017\/04\/git-simples-e-rapido\/\">cheatsheet<\/a>, <a href=\"\/2017\/04\/instalando-gogs-no-ubuntu\/\">Gogs em 2017<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Gitea (Git with a cup of tea) \u00e9 a forge self-hosted em Go: reposit\u00f3rio Git, PR, issues, wiki, registry de pacotes e CI\/CD no mesmo bin\u00e1rio. Fork do Gogs em 2016, MIT, cabe num VPS de 1 GB. A vers\u00e3o est\u00e1vel em setembro de 2026 \u00e9 a 1.27.3. Este texto sobe a inst\u00e2ncia com Docker &#8230; <a title=\"Gitea: Git self-hosted com Actions, runner e tea CLI\" class=\"read-more\" href=\"https:\/\/www.linuxpro.com.br\/es\/2026\/09\/gitea-git-self-hosted-runner-tea\/\" aria-label=\"Read more about Gitea: Git self-hosted com Actions, runner e tea CLI\">Read more<\/a><\/p>","protected":false},"author":0,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[45,46,2,111,120],"tags":[105,156,48,201,204,203,202],"class_list":["post-502","post","type-post","status-publish","format-standard","hentry","category-desenv","category-devops","category-linux","category-opensource","category-servidores","tag-ci-cd","tag-docker","tag-git","tag-gitea","tag-runner","tag-self-hosted","tag-tea"],"_links":{"self":[{"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/posts\/502","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/comments?post=502"}],"version-history":[{"count":4,"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/posts\/502\/revisions"}],"predecessor-version":[{"id":1306,"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/posts\/502\/revisions\/1306"}],"wp:attachment":[{"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/media?parent=502"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/categories?post=502"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/tags?post=502"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}