
Instalare Gitea cu Docker: server Git propriu, SSH si CI
De fiecare data cand scrii git push, codul tau ajunge pe calculatorul altcuiva. Pentru proiecte open source, asta e tocmai ideea, dar pentru proiecte de clienti, unelte interne, scripturi de infrastructura sau orice e acoperit de un contract ori de GDPR, merita sa te intrebi daca o singura platforma de pe alt continent trebuie sa tina singura copie remote. Vestea buna e ca un VPS mic poate rula o platforma Git completa: interfata web, pull request-uri, issues, acces SSH, mirror automat al repo-urilor de pe GitHub si chiar pipeline-uri de CI, totul pe hardware pe care il controlezi tu si mai ieftin decat cateva licente platite.
In ghidul asta facem un gitea docker install complet, pe un VPS proaspat cu Debian 13 sau Ubuntu 24.04. Gitea este un serviciu Git self-hosted, usor, scris in Go si publicat sub licenta MIT. Proiectul e pe gitea.com , iar codul sursa pe github.com/go-gitea/gitea . La final vei avea Gitea functional cu baza de date PostgreSQL, servit prin HTTPS, cu Git prin SSH pe portul 2222 in timp ce login-ul tau obisnuit ramane pe portul 22, cu mirror programat al repo-urilor de pe GitHub si cu joburi simple de CI prin Gitea Actions.
Ce este Gitea si de ce il folosim cu PostgreSQL
Gitea iti ofera aproape tot ce folosesc oamenii de fapt pe GitHub: repo-uri cu browser de cod in interfata web, branch-uri si tag-uri, pull request-uri cu review, issues si milestones, wiki, release-uri, organizatii si echipe, un registry de pachete si, din versiunea 1.19, un sistem de CI care intelege workflow-uri in stilul GitHub Actions. E un singur program scris in Go, porneste in cateva secunde si se multumeste cu o fractiune din memoria de care au nevoie platformele mai grele.
In spate, Gitea pastreaza doua tipuri de date. Repo-urile sunt stocate ca repo-uri Git bare obisnuite pe disc, exact ce ar crea git init --bare. Restul, adica utilizatori, permisiuni, issues, comentarii din pull request-uri, programarea mirror-urilor si istoricul rularilor CI, sta intr-o baza de date.
Gitea poate folosi SQLite, o baza de date care e doar un fisier, si pentru o singura persoana merge perfect. Imediat ce mai multi oameni fac push in acelasi timp, un runner de CI interogheaza API-ul la cateva secunde si mirror-urile se sincronizeaza in fundal, PostgreSQL devine alegerea mai buna: gestioneaza scrieri concurente fara probleme, iti da backup-uri curate si consistente cu pg_dump si face migrarile ulterioare nedureroase. Costul e de aproximativ 50 pana la 80 MB de RAM in plus, un schimb bun.
Vocabularul, in doua minute
Daca Docker e nou pentru tine, astea sunt singurii termeni de care ai nevoie in ghid:
- Imagine: un sablon impachetat, read-only, al unei aplicatii, cu tot ce ii trebuie ca sa ruleze, de exemplu
gitea/gitea:1.25. - Container: o instanta care ruleaza dintr-o imagine, izolata de restul sistemului. Il poti sterge si recrea oricand fara sa-ti atingi datele, atata timp cat datele stau intr-un volum.
- Volum: un folder de pe VPS montat in interiorul containerului. Repo-urile, configuratia si fisierele bazei de date stau acolo, deci supravietuiesc update-urilor si restarturilor.
- Port: un numar care identifica un serviciu de retea pe o masina. SSH foloseste de obicei 22, HTTP 80 si HTTPS 443. Doua programe nu pot asculta pe acelasi port simultan, de aceea serverul SSH al lui Gitea va folosi 2222.
- Docker Compose: un utilitar care citeste un singur fisier YAML ce descrie mai multe containere si le porneste impreuna cu
docker compose up -d. - Reverse proxy: un server web care sta in fata aplicatiei, obtine certificatele HTTPS si trimite cererile catre aplicatie pe un port privat. Folosim Caddy, pentru ca se ocupa singur de certificate.
De ce ai nevoie
- Un VPS KVM cu cel putin 1 vCPU si 1 GB RAM doar pentru Gitea, sau 2 vCPU si 2 GB RAM daca vrei sa rulezi joburi de CI. Planifica 20 GB de disc sau mai mult, in functie de marimea repo-urilor.
- Debian 13 sau Ubuntu 24.04, instalat proaspat, si un utilizator cu drepturi
sudocu care te poti loga prin SSH. - Un domeniu sau subdomeniu pe care il controlezi, de exemplu
git.example.com, cu o inregistrareA(siAAAAdaca folosesti IPv6) catre IP-ul VPS-ului. - O pereche de chei SSH pe calculatorul tau (o cream in pasul 6 daca nu ai deja).
- Optional, un personal access token de GitHub daca vrei mirror pentru repo-uri private.
- Cam 45 de minute.
O nota despre containere in containere: ghidul presupune un VPS KVM. Docker intr-un container LXC neprivilegiat functioneaza doar daca este activat nesting pentru acel container, iar UFW s-ar putea sa nu-si poata incarca regulile acolo. Daca esti pe un plan LXC, cere suportului sa activeze nesting inainte, sau alege un VPS KVM pentru proiectul asta.
In tot articolul folosim git.example.com. Inlocuieste-l peste tot cu domeniul tau real, inclusiv in fisierele pe care le cream.
Cum se leaga componentele intre ele
Inainte sa scriem vreo comanda, ajuta sa vedem pe unde trece fiecare cerere. Browserul vorbeste cu Caddy pe portul 443. Caddy tine certificatul TLS si trimite cererea mai departe catre Gitea pe portul 3000, pe care il legam doar de 127.0.0.1, deci nu e niciodata accesibil direct din internet. Git prin SSH merge pe alt drum: portul 2222 al VPS-ului este mapat direct catre serverul SSH care ruleaza in containerul Gitea. Serverul SSH al gazdei, de pe portul 22, nu e atins deloc, deci login-ul tau de administrare functioneaza exact ca inainte.
Procedura pe scurt
Impartim munca in opt pasi. Fiecare se incheie cu o verificare, ca sa stii exact unde sa te uiti daca ceva nu merge.
Pasul 1: Pregatim VPS-ul
Incepem cu actualizarea sistemului, ca sa nu construim peste pachete vechi:
sudo apt update && sudo apt upgrade -y
Daca upgrade-ul a instalat un kernel nou, da un reboot inainte sa mergi mai departe. Aici Debian si Ubuntu se comporta diferit: Ubuntu creeaza fisierul /var/run/reboot-required cand un update are nevoie de restart, deci il poti verifica cu comanda de mai jos. Debian nu creeaza implicit acest fisier, asa ca pe Debian fa pur si simplu reboot daca ai vazut un pachet linux-image nou in output-ul upgrade-ului.
[ -f /var/run/reboot-required ] && echo "Reboot necesar" || echo "Niciun semnal de reboot"
Apoi instalam Docker Engine si plugin-ul Compose v2 din repository-ul oficial Docker. Ambele distributii au propriile pachete Docker, dar repository-ul upstream iti da versiuni actuale de docker compose. Blocul de mai jos merge pe ambele sisteme, pentru ca citeste numele distributiei (debian sau ubuntu) si numele de cod (trixie sau noble) din /etc/os-release:
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
. /etc/os-release
sudo curl -fsSL "https://download.docker.com/linux/${ID}/gpg" -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/${ID} ${VERSION_CODENAME} stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Verificam ca totul functioneaza. Prima comanda descarca o imagine mica de test si ar trebui sa afiseze un mesaj care incepe cu “Hello from Docker!”. A doua ar trebui sa afiseze ceva de genul Docker Compose version v2.x.y:
sudo docker run --rm hello-world
docker compose version
Acum confirma ca domeniul indica deja spre VPS. Comanda trebuie sa afiseze IP-ul public al serverului. Daca nu afiseaza nimic, asteapta propagarea DNS inainte de pasul 4, pentru ca Caddy nu poate obtine certificat pentru un nume care inca nu se rezolva:
getent hosts git.example.com
La final, firewall-ul. Ubuntu vine cu UFW preinstalat dar inactiv, in timp ce Debian nu il instaleaza deloc, asa ca prima linie e necesara doar pe Debian (pe Ubuntu nu strica). Permitem SSH primul, altfel activarea firewall-ului te poate bloca afara:
sudo apt install -y ufw
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 2222/tcp
sudo ufw enable
sudo ufw status
Daca serverul tau SSH asculta pe alt port decat 22, permite acel port in loc. Output-ul de status trebuie sa listeze cele patru porturi cu ALLOW.
Pasul 2: Cream proiectul Compose
Tinem tot ce tine de Gitea intr-un singur folder, /opt/gitea, detinut de utilizatorul tau. In el, trei subfoldere vor pastra datele persistente:
sudo mkdir -p /opt/gitea
sudo chown "$USER":"$USER" /opt/gitea
cd /opt/gitea
mkdir -p gitea postgres runner
id -u; id -g
Ultima comanda afiseaza ID-ul numeric al utilizatorului si al grupului tau. Pe un VPS nou cu un singur utilizator sudo, de obicei sunt 1000 si 1000. Daca vezi alte numere, foloseste-le pentru USER_UID si USER_GID in fisierul de mai jos, ca fisierele repo-urilor de pe disc sa iti apartina tie si nu unui ID oarecare.
Parolele nu se scriu niciodata direct in compose.yaml. In schimb, generam o parola aleatoare puternica si o punem intr-un fisier .env, pe care Docker Compose il citeste automat. chmod 600 il face lizibil doar pentru tine:
cat > .env <<EOF
POSTGRES_PASSWORD=$(openssl rand -hex 24)
RUNNER_TOKEN=
EOF
chmod 600 .env
cat .env
RUNNER_TOKEN ramane gol deocamdata, il completam in pasul 8. Acum creeaza fisierul Compose cu nano compose.yaml si lipeste:
services:
server:
image: gitea/gitea:1.25
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=${POSTGRES_PASSWORD}
- GITEA__server__DOMAIN=git.example.com
- GITEA__server__SSH_DOMAIN=git.example.com
- GITEA__server__ROOT_URL=https://git.example.com/
- GITEA__server__SSH_PORT=2222
- GITEA__service__DISABLE_REGISTRATION=true
volumes:
- ./gitea:/data
- /etc/localtime:/etc/localtime:ro
ports:
- "127.0.0.1:3000:3000"
- "2222:22"
depends_on:
db:
condition: service_healthy
db:
image: postgres:17
container_name: gitea-db
restart: unless-stopped
environment:
- POSTGRES_USER=gitea
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=gitea
volumes:
- ./postgres:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U gitea -d gitea"]
interval: 10s
timeout: 5s
retries: 5
Daca nu vrei sa editezi domeniul de mana, il poti inlocui dintr-o data (pune domeniul tau in comanda):
sed -i 's/git\.example\.com/git.domeniultau.ro/g' compose.yaml
Ce face fisierul, bucata cu bucata:
- Variabilele
GITEA__sectiune__CHEIEsunt scrise in fisierul de configurare al lui Gitea (app.ini) la fiecare pornire. E cel mai curat mod de a configura Gitea in Docker, pentru ca setarile stau langa restul stack-ului. SSH_PORT=2222nu schimba portul pe care asculta SSH in container (ramane 22). Ii spune lui Gitea ce port sa afiseze in URL-urile de clonare, si trebuie sa corespunda cu portul publicat2222:22.127.0.0.1:3000:3000publica interfata web doar pe interfata loopback. Doar Caddy, care ruleaza pe acelasi VPS, ajunge la ea.depends_oncuservice_healthyil face pe Gitea sa astepte pana cand PostgreSQL accepta efectiv conexiuni, in loc sa se opreasca cu eroare la prima pornire.- Fara cheia
version:: Docker Compose actual o ignora, asa ca o lasam deoparte.
Despre tag-urile imaginilor: gitea/gitea:1.25 urmareste linia de versiuni 1.25, deci un pull ulterior aduce bug fix-uri, dar niciodata un upgrade major surpriza. Verifica pagina de release-uri Gitea si foloseste cea mai noua linie 1.x disponibila cand citesti asta. Pentru baza de date fixam intentionat postgres:17. Cu :latest ai trage la un moment dat o versiune majora noua, iar upgrade-urile majore de PostgreSQL cer dump si restore. Imaginea postgres:18 a schimbat si locul in care stau datele in container, deci nu schimba pur si simplu tag-ul pe o instalare existenta.
Pasul 3: Pornim Gitea si PostgreSQL
Din /opt/gitea, pornim ambele containere in fundal:
sudo docker compose up -d
sudo docker compose ps
Prima rulare descarca imaginile, dureaza cam un minut. Dupa aceea, ps ar trebui sa arate cam asa:
NAME IMAGE SERVICE STATUS
gitea gitea/gitea:1.25 server Up 20 seconds
gitea-db postgres:17 db Up 31 seconds (healthy)
Uita-te in log-urile lui Gitea ca sa te asiguri ca a gasit baza de date si si-a pornit serverul web. Apasa Ctrl+C ca sa iesi din urmarirea log-ului:
sudo docker compose logs -f server
Cauti o linie care contine Starting new Web server: tcp:0.0.0.0:3000. Apoi testeaza portul web local. Raspunsul trebuie sa fie HTTP/1.1 200 OK, adica pagina de instalare care te asteapta:
curl -sI http://127.0.0.1:3000 | head -n 1
Pasul 4: Adaugam HTTPS cu Caddy
Caddy este un server web care cere si reinnoieste singur certificate Let’s Encrypt. Exista ca pachet atat in Debian 13, cat si in Ubuntu 24.04, cu acelasi nume de serviciu (caddy) si acelasi fisier de configurare (/etc/caddy/Caddyfile). Il instalam si inlocuim configuratia implicita:
sudo apt install -y caddy
sudo tee /etc/caddy/Caddyfile > /dev/null <<'EOF'
git.example.com {
reverse_proxy 127.0.0.1:3000
}
EOF
sudo systemctl reload caddy
Nu uita sa pui domeniul tau in locul lui git.example.com. In cateva secunde, Caddy contacteaza Let’s Encrypt, demonstreaza prin portul 80 ca detine domeniul si instaleaza certificatul. Verifica:
curl -sI https://git.example.com | head -n 1
O linie de tipul HTTP/2 200 inseamna ca HTTPS functioneaza. Daca primesti o eroare, citeste log-urile Caddy cu sudo journalctl -u caddy --no-pager -n 50, cauza e aproape mereu DNS-ul sau portul 80 inchis.
De ce Caddy si nu Nginx aici? Pe langa certificatele automate, Caddy nu are o limita implicita pentru marimea cererilor. Nginx limiteaza corpul cererilor la 1 MB daca nu cresti client_max_body_size, ceea ce strica push-urile mai mari prin HTTPS, o surpriza clasica din prima zi.
Pasul 5: Rulam instalatorul web
Fa acest pas imediat dupa pasul 4: pana cand termini instalarea, oricine deschide domeniul tau ar putea completa formularul. Deschide https://git.example.com in browser. Datorita variabilelor de mediu, majoritatea campurilor sunt deja completate:
- Database Settings: PostgreSQL, host
db:5432, utilizator si baza de dategitea, parola deja setata. Lasa-le asa. - General Settings: seteaza un Site Title. Verifica ca Server Domain este domeniul tau, SSH Server Port este
2222si Gitea Base URL estehttps://git.example.com/. - Optional Settings, Server and Third-Party Service Settings: “Disable Self-Registration” ar trebui sa fie deja bifat. Bifeaza si “Require Sign-In to View Pages” daca instanta e privata.
- Administrator Account Settings: deschide sectiunea si creeaza utilizatorul de admin. Atentie,
admine un nume rezervat in Gitea, asa ca alege ceva de genul numelui tau.
Apasa “Install Gitea”. Dupa cateva secunde esti logat ca administrator. Gitea si-a scris configuratia cu INSTALL_LOCK = true, deci instalatorul nu mai poate fi afisat niciodata. Poti vedea fisierul pe gazda:
sudo grep -A3 '^\[security\]' /opt/gitea/gitea/gitea/conf/app.ini
De acum, pentru setarile care apar si in compose.yaml, editeaza fisierul Compose si ruleaza sudo docker compose up -d, nu app.ini direct, pentru ca variabilele de mediu castiga la fiecare pornire.
Pasul 6: Activam Git prin SSH
Pe VPS exista acum doua servere SSH unul langa altul, si exact asta vrem: sshd-ul gazdei pe portul 22, pentru tine ca administrator, si serverul SSH din containerul Gitea pe portul 2222, doar pentru operatii Git. Serverul din container nu da nimanui shell, doar ii permite lui Gitea sa verifice a cui e fiecare cheie si sa ruleze comenzi Git.
Pe calculatorul tau (nu pe VPS), creeaza o cheie daca nu ai, apoi afiseaza partea publica:
ssh-keygen -t ed25519 -C "tu@laptop"
cat ~/.ssh/id_ed25519.pub
In Gitea, deschide meniul de la avatar, mergi la Settings, apoi SSH / GPG Keys, apasa Add Key si lipeste linia care incepe cu ssh-ed25519. Apoi testeaza conexiunea:
ssh -T -p 2222 git@git.example.com
Prima data, SSH iti cere sa accepti o cheie de host noua. E cheia serverului SSH din container, diferita de cheia VPS-ului, si e normal: SSH memoreaza cheile per host si port, deci cele doua nu intra niciodata in conflict. Cheile sunt pastrate in ./gitea/ssh, deci raman aceleasi dupa restarturi si upgrade-uri. Raspunsul asteptat este:
Hi there, numeletau! You've successfully authenticated with the key named tu@laptop, but Gitea does not provide shell access.
Sa scrii -p 2222 de fiecare data devine obositor repede. Adauga asta in ~/.ssh/config pe calculatorul tau:
Host git.example.com
Port 2222
User git
IdentityFile ~/.ssh/id_ed25519
Acum functioneaza sintaxa scurta de clonare. Creeaza un repo gol din interfata web (meniul “+”, “New Repository”), apoi urca un proiect existent in el:
cd ~/proiecte/proiectul-meu
git remote add origin git@git.example.com:numeletau/proiectul-meu.git
git push -u origin main
Daca preferi sa faci push direct si repo-ul sa fie creat automat, adauga GITEA__repository__ENABLE_PUSH_CREATE_USER=true in lista de variabile de mediu si ruleaza sudo docker compose up -d. Iar daca vrei neaparat URL-uri de clonare fara port, Gitea suporta “SSH passthrough”, in care sshd-ul gazdei de pe portul 22 trimite conexiunile Git catre container. Are nevoie de un utilizator git pe gazda si de un mic script intermediar, documentatia oficiala de pe docs.gitea.com
il descrie. Pentru majoritatea echipelor, portul 2222 plus intrarea din ~/.ssh/config de mai sus e mai simplu si are mai putine piese care se pot strica.
Pasul 7: Facem mirror la repo-urile de pe GitHub
Un pull mirror este o copie a unui repo remote pe care Gitea o reimprospateaza periodic. E util ca backup off-site pentru proiectele de pe GitHub, ca o copie locala rapida pentru CI, sau ca prima etapa a unei migrari treptate.
In interfata web, apasa “+”, apoi New Migration, si alege GitHub. Lipeste URL-ul repo-ului, de exemplu https://github.com/numeletau/proiect.git, si bifeaza This repository will be a mirror. Pentru repo-uri private, creeaza pe GitHub un personal access token de tip fine-grained, cu acces read-only la “Contents” pentru repo-urile de care ai nevoie, si lipeste-l in campul pentru token. Chiar si pentru repo-uri publice un token ajuta, pentru ca cererile neautentificate catre API-ul GitHub sunt limitate la 60 pe ora.
Doua lucruri de stiut despre mirror-uri: sincronizeaza codul (branch-uri, tag-uri, commit-uri), dar issues si pull request-urile se copiaza doar la o migrare unica, fara bifa de mirror. Iar intervalul implicit de sincronizare este de 8 ore. Il poti schimba per repo din Settings, apoi Mirror Settings, poti porni manual oricand “Synchronize Now”, sau poti schimba valoarea implicita pentru mirror-urile noi cu GITEA__mirror__DEFAULT_INTERVAL=1h in fisierul Compose. Intervalul minim permis este de 10 minute.
Daca ai multe repo-uri, API-ul e mai rapid decat click-urile. Creeaza un token Gitea din Settings, Applications (cu drept de scriere pe repo-uri), apoi:
curl -s -X POST "https://git.example.com/api/v1/repos/migrate" \
-H "Authorization: token TOKENUL_TAU_GITEA" \
-H "Content-Type: application/json" \
-d '{
"clone_addr": "https://github.com/numeletau/proiect.git",
"repo_name": "proiect",
"repo_owner": "numeletau",
"service": "github",
"mirror": true,
"mirror_interval": "8h0m0s",
"private": true
}'
Raspunsul e o descriere JSON a repo-ului nou. Pentru surse private, adauga "auth_token": "TOKENUL_TAU_GITHUB". Exista si directia opusa: un push mirror (in aceeasi pagina Mirror Settings) trimite fiecare schimbare din Gitea catre GitHub, util daca Gitea devine casa principala, iar GitHub doar o vitrina publica.
Pasul 8: Configuram Gitea Actions
Gitea Actions este sistemul de CI integrat in Gitea. Citeste fisiere de workflow cu aproape aceeasi sintaxa ca GitHub Actions si este activat implicit in versiunile actuale. Ce ii lipseste e un runner, un program separat care il intreaba pe Gitea “ai ceva de lucru pentru mine?”, porneste un container nou pentru fiecare job, ruleaza pasii si raporteaza rezultatul. Runner-ul oficial se numeste act_runner.
Mai intai, ia un token de inregistrare: mergi la Site Administration, Actions, Runners, apasa Create new Runner si copiaza token-ul. Pune-l in .env:
cd /opt/gitea
nano .env # seteaza RUNNER_TOKEN=tokenul-copiat
Apoi adauga acest serviciu in compose.yaml, sub services:, la aceeasi indentare ca db::
runner:
image: gitea/act_runner:0.2.11
container_name: gitea-runner
restart: unless-stopped
depends_on:
- server
environment:
- GITEA_INSTANCE_URL=https://git.example.com
- GITEA_RUNNER_REGISTRATION_TOKEN=${RUNNER_TOKEN}
- GITEA_RUNNER_NAME=vps-runner
- GITEA_RUNNER_LABELS=ubuntu-latest:docker://node:20-bookworm
volumes:
- ./runner:/data
- /var/run/docker.sock:/var/run/docker.sock
Linia de label-uri asociaza numele ubuntu-latest, pe care workflow-urile il cer in runs-on, cu imaginea node:20-bookworm, o imagine bazata pe Debian, cu Git si Node.js, cele doua lucruri de care au nevoie majoritatea action-urilor uzuale. Ca si la Gitea, verifica release-urile act_runner pentru o versiune mai noua decat 0.2.11 cand citesti asta. Porneste runner-ul si citeste-i log-ul:
sudo docker compose up -d runner
sudo docker compose logs runner
Cauta Runner registered successfully. Inregistrarea se salveaza in ./runner/.runner, deci token-ul e folosit doar prima data. Inapoi in Site Administration, runner-ul apare cu statusul Idle.
Acum sa-i dam ceva de lucru. In orice repo (verifica sa fie bifat Settings, Repository, Enable Repository Actions), creeaza fisierul .gitea/workflows/ci.yaml:
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Check out the code
uses: actions/checkout@v4
- name: Show what we are building
run: |
echo "Commit: ${{ gitea.sha }}"
git log -1 --oneline
node --version
- name: Make sure the project has a README
run: test -f README.md
Fa commit si push. Deschide tab-ul Actions al repo-ului: in cateva secunde apare o rulare, devine galbena cat lucreaza si verde cand reuseste. Prima rulare e mai lenta, pentru ca runner-ul descarca imaginea node:20-bookworm si action-ul de checkout (pe care Gitea il ia implicit de pe GitHub). Inlocuieste ultimul pas cu testele, linterele sau comenzile tale reale de build si ai un CI functional.
De cata memorie are nevoie un gitea docker install?
Unul dintre cele mai mari avantaje ale lui Gitea este cat de putin cere. Valorile de mai jos sunt tipice pentru o echipa mica, cu cateva zeci de repo-uri; cifrele tale exacte vor varia in functie de marimea repo-urilor, numarul de utilizatori si ce fac joburile de CI.
In practica: 1 GB de RAM e suficient pentru Gitea si PostgreSQL pentru cativa utilizatori. Daca activezi Actions, alege 2 GB sau mai mult, pentru ca un singur npm install sau un build Go poate lua usor cateva sute de megabytes. Un fisier de swap mic e o plasa de siguranta ieftina pe planurile mici, dar nu inlocuieste RAM-ul real pentru build-uri.
Depanare si greseli frecvente
Caddy raspunde cu “502 Bad Gateway”. Caddy ruleaza, dar nu ajunge la Gitea. Verifica sudo docker compose ps si log-urile din pasul 3. Asigura-te ca in Caddyfile apare 127.0.0.1:3000, acelasi port ca in compose.yaml.
Nu se obtine certificat HTTPS. Aproape mereu e DNS-ul (domeniul nu indica inca spre VPS) sau portul 80 blocat. Let’s Encrypt are nevoie de portul 80 deschis pentru verificare, chiar daca utilizatorii folosesc doar 443. Verifica cu getent hosts si sudo ufw status.
“Permission denied (publickey)” la push. Verifica trei lucruri: te conectezi pe portul 2222 si nu pe 22 (ruleaza ssh -vT -p 2222 git@git.example.com ca sa vezi ce cheie se ofera), cheia a fost adaugata la utilizatorul Gitea corect, iar utilizatorul din URL este literal git, nu numele tau.
URL-urile de clonare arata portul sau domeniul gresit. Pagina repo-ului construieste URL-urile din SSH_DOMAIN, SSH_PORT si ROOT_URL. Corecteaza-le in compose.yaml si ruleaza sudo docker compose up -d.
PostgreSQL spune “password authentication failed”. Variabila POSTGRES_PASSWORD e folosita doar cand folderul bazei de date e gol, la prima pornire. Daca ai schimbat .env ulterior, baza de date are inca parola veche. Fie pui valoarea veche inapoi, fie schimbi parola in PostgreSQL cu sudo docker compose exec db psql -U gitea -c "ALTER USER gitea PASSWORD 'parola-noua';" ca sa se potriveasca cu .env.
Erori de permisiuni in log-urile Gitea. USER_UID/USER_GID nu corespund cu proprietarul folderului ./gitea. Seteaza-le la valorile din id -u si id -g, apoi ruleaza sudo docker compose up -d.
Clonarea prin HTTPS cere parola si o respinge. Dupa ce activezi autentificarea in doi pasi, Git prin HTTPS are nevoie de un access token in loc de parola. Oricum, SSH e de obicei mai comod.
Runner-ul nu se inregistreaza. Verifica daca token-ul din .env e corect si daca containerul ajunge la https://git.example.com (testeaza cu sudo docker compose exec runner wget -qO- https://git.example.com/api/healthz). Daca ai schimbat token-ul dupa o incercare esuata, sterge ./runner/.runner si reporneste runner-ul.
Joburile raman la nesfarsit in “Waiting”. Valoarea runs-on din workflow nu corespunde niciunui label de runner. Cu configuratia noastra trebuie sa fie ubuntu-latest.
Note de securitate
- Docker ocoleste UFW pentru porturile publicate. Docker isi scrie propriile reguli de firewall, deci un port publicat ca
"3000:3000"ar fi accesibil din internet chiar daca UFW spune altceva. De asta publicam portul web doar pe127.0.0.1. Portul 2222 e publicat pe toate interfetele intentionat. - Runner-ul are putere de root. Montarea
/var/run/docker.sockii permite runner-ului sa porneasca orice container, ceea ce echivaleaza cu root pe VPS. Ruleaza doar workflow-uri de la oameni in care ai incredere, tine inregistrarea dezactivata si nu rula CI pentru pull request-uri din fork-uri necunoscute. Pentru cod nesigur, pune runner-ul pe un VPS separat, de unica folosinta. - Protejeaza contul de admin. Activeaza autentificarea in doi pasi din Settings, Security, si foloseste un utilizator obisnuit pentru munca de zi cu zi.
- Tine instalatorul inchis. Termina pasul 5 imediat dupa pasul 4, ca nimeni altcineva sa nu-ti poata configura instanta.
- Fa backup la ambele jumatati. Repo-urile sunt pe disc, metadatele in PostgreSQL, si ai nevoie de amandoua. O rutina simpla, de noapte:
cd /opt/gitea
mkdir -p backups
sudo docker compose exec -T db pg_dump -U gitea gitea | gzip > "backups/gitea-db-$(date +%F).sql.gz"
sudo tar czf "backups/gitea-files-$(date +%F).tar.gz" gitea
Copiaza folderul backups in afara serverului, ideal intr-o alta locatie. Un backup pe acelasi disc nu supravietuieste pierderii discului.
- Actualizeaza cu grija. Ca sa actualizezi Gitea, fa un backup, citeste release notes, schimba tag-ul in
compose.yamldaca treci pe o linie 1.x noua, apoi ruleazasudo docker compose pull && sudo docker compose up -d. Nu schimba niciodata versiunea majora de PostgreSQL fara dump si restore.
Deci, merita sa-ti gazduiesti singur Git-ul?
Daca vrei codul, issues si CI-ul sub controlul tau, cu costuri previzibile si date care raman intr-un data center din Romania, Gitea este cea mai simpla optiune serioasa disponibila azi. Ruleaza confortabil pe un server mic, configuratia Docker se salveaza si se muta usor, iar functii precum mirror-urile si Actions inseamna ca nu renunti la mare lucru fata de platformele mari. Daca ai nevoie de setul complet de functii enterprise sau de capacitate masiva de CI, o platforma mai grea sau un serviciu gazduit s-ar putea potrivi mai bine.
Poti incepe chiar acum pe un VPS de la noi: un plan cu 2 GB ruleaza tot ce e in ghidul asta, inclusiv CI. Daca preferi ca altcineva sa se ocupe de instalare, backup-uri, update-uri si monitorizare, echipa noastra de administrare servere iti poate configura si intretine instanta Gitea.
Intrebari frecvente
Este Gitea o alternativa buna la GitHub pentru o echipa mica?
Pentru repo-uri private, code review, issues si CI simplu, da. Pierzi partea de retea sociala a GitHub (stele, descoperire, marketplace-ul urias de Actions publice), dar Gitea poate folosi direct majoritatea action-urilor publice, iar push mirror-urile iti permit sa pastrezi o copie publica pe GitHub daca ai nevoie de vizibilitate.
Pot folosi SQLite in loc de PostgreSQL?
Da. Scoate serviciul db si seteaza GITEA__database__DB_TYPE=sqlite3. E perfect pentru unul sau doi utilizatori. Recomandam PostgreSQL de indata ce mai multi oameni si un runner de CI folosesc instanta in acelasi timp.
Poate Gitea folosi portul 22 pentru SSH in loc de 2222?
Doar daca serverul SSH al gazdei se muta pe alt port, sau daca configurezi SSH passthrough, unde sshd-ul gazdei trimite conexiunile Git catre container. Ambele variante merg, dar 2222 pentru Git si 22 pentru administrare e configuratia cea mai simpla si mai sigura.
Sunt Gitea Actions compatibile cu workflow-urile GitHub Actions?
In mare parte. Sintaxa e aceeasi, majoritatea action-urilor populare functioneaza, iar contextul github e disponibil (cu gitea ca alias). Diferentele apar la functiile legate de infrastructura GitHub, cum ar fi anumite servicii de cache sau imaginile runner-elor gazduite, deci testeaza workflow-urile complexe inainte sa te bazezi pe ele.
Ce e cu Forgejo?
Forgejo este un fork comunitar al lui Gitea, cu functii foarte asemanatoare si o configuratie Docker compatibila. Tot ce e in ghidul asta se aplica, cu mici schimbari la numele imaginilor si la cateva chei de configurare. Alege proiectul al carui mod de guvernanta si ritm de release-uri il preferi.