Self-hosting di Gitea su un VPS con Docker Compose

11 min di lettura·Matthieu·ci-cdself-hostingdocker-composegiteapostgresqldockergit|

Distribuisci un'istanza Gitea pronta per la produzione con PostgreSQL, passthrough SSH sulla porta 22, CI/CD con Gitea Actions, Git LFS, mirroring da GitHub e backup automatizzati. Tutto su un singolo VPS con Docker Compose.

Gitea è un servizio Git self-hosted, leggero e scritto in Go. Offre pull request, issue tracking, CI/CD, registri di pacchetti e Git LFS in un singolo binario che a riposo occupa circa 150 MB di RAM. Confrontalo con i 4 GB minimi di GitLab e capirai perché Gitea si adatta perfettamente a un VPS.

Questa guida distribuisce Gitea con Docker Compose e PostgreSQL su un VPS. Configurerai il passthrough SSH in modo che git clone git@tuo-server:user/repo.git funzioni sulla porta 22, configurerai Gitea Actions con un runner containerizzato, abiliterai Git LFS, farai il mirroring di repository da GitHub, configurerai i webhook e automatizzerai i backup.

Cosa serve prima di installare Gitea?

Serve un VPS con Debian 12 o Ubuntu 24.04 con Docker e Docker Compose v2 installati, un nome di dominio che punta al tuo server e un reverse proxy (Nginx o Caddy) con TLS configurato. Questa guida presuppone che tu abbia completato l'hardening iniziale del server: utente non-root con sudo, autenticazione con chiave SSH, firewall attivo.

Prerequisito Minimo
OS Debian 12 / Ubuntu 24.04
RAM 1 GB (2 GB consigliati con runner CI)
Docker 27.x+ con Compose v2
Dominio Record A che punta all'IP del VPS
Reverse proxy Nginx o Caddy con TLS

Come distribuire Gitea con Docker Compose e PostgreSQL?

Crea una directory di progetto, genera i secret in un file .env e definisci i servizi Gitea e PostgreSQL in docker-compose.yml. Il file .env tiene le credenziali fuori dal controllo di versione e dai file compose.

Creare la directory del progetto

sudo mkdir -p /opt/gitea
sudo chown $USER:$USER /opt/gitea
cd /opt/gitea

Generare i secret

openssl rand -base64 32 > /dev/null  # test that openssl works
cat > .env << 'ENVFILE'
POSTGRES_USER=gitea
POSTGRES_PASSWORD=REPLACE_ME
POSTGRES_DB=gitea
GITEA_SECRET_KEY=REPLACE_ME
GITEA_INTERNAL_TOKEN=REPLACE_ME
GITEA_LFS_JWT_SECRET=REPLACE_ME
ENVFILE

Ora sostituisci ogni REPLACE_ME con un vero secret:

sed -i "s/^POSTGRES_PASSWORD=.*/POSTGRES_PASSWORD=$(openssl rand -base64 32)/" .env
sed -i "s/^GITEA_SECRET_KEY=.*/GITEA_SECRET_KEY=$(openssl rand -base64 32)/" .env
sed -i "s/^GITEA_INTERNAL_TOKEN=.*/GITEA_INTERNAL_TOKEN=$(openssl rand -base64 32)/" .env
sed -i "s/^GITEA_LFS_JWT_SECRET=.*/GITEA_LFS_JWT_SECRET=$(openssl rand -base64 32)/" .env
chmod 600 .env

File Docker Compose

# /opt/gitea/docker-compose.yml
services:
  gitea:
    image: docker.gitea.com/gitea:1.25.5
    container_name: gitea
    environment:
      - USER_UID=1000
      - USER_GID=1000
      - GITEA__database__DB_TYPE=postgres
      - GITEA__database__HOST=db:5432
      - GITEA__database__NAME=${POSTGRES_DB}
      - GITEA__database__USER=${POSTGRES_USER}
      - GITEA__database__PASSWD=${POSTGRES_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=22
      - GITEA__server__LFS_START_SERVER=true
      - GITEA__server__LFS_JWT_SECRET=${GITEA_LFS_JWT_SECRET}
      - GITEA__service__DISABLE_REGISTRATION=true
      - GITEA__service__REQUIRE_SIGNIN_VIEW=false
      - GITEA__security__SECRET_KEY=${GITEA_SECRET_KEY}
      - GITEA__security__INTERNAL_TOKEN=${GITEA_INTERNAL_TOKEN}
      - GITEA__actions__ENABLED=true
    restart: always
    volumes:
      - gitea-data:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "127.0.0.1:3000:3000"
    depends_on:
      db:
        condition: service_healthy
    networks:
      - gitea

  db:
    image: docker.io/library/postgres:17
    container_name: gitea-db
    environment:
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_DB=${POSTGRES_DB}
    restart: always
    volumes:
      - postgres-data:/var/lib/postgresql/data
    networks:
      - gitea
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
      interval: 10s
      timeout: 5s
      retries: 5

networks:
  gitea:
    external: false

volumes:
  gitea-data:
  postgres-data:

Sostituisci git.example.com con il tuo dominio reale. Decisioni chiave:

  • PostgreSQL 17 invece del 14 obsoleto che la maggior parte delle guide raccomanda ancora
  • Volumi nominati (gitea-data, postgres-data) invece di bind mount per una gestione più pulita
  • Health check su PostgreSQL per far attendere Gitea fino a quando il database è pronto
  • DISABLE_REGISTRATION=true perché la registrazione aperta su un'istanza pubblica invita abusi
  • ACTIONS__ENABLED=true per attivare Gitea Actions fin dall'inizio
  • Porta 3000 vincolata a localhost (127.0.0.1:3000:3000) in modo che sia raggiungibile solo attraverso il reverse proxy, non direttamente da internet
  • Nessun mapping della porta SSH sul container. L'SSH sarà gestito tramite passthrough sull'host (sezione successiva)

Avviare lo stack

docker compose up -d
[+] Running 3/3
 ✔ Network gitea_gitea     Created
 ✔ Container gitea-db      Healthy
 ✔ Container gitea         Started
docker compose ps
NAME        IMAGE                           STATUS                   PORTS
gitea       docker.gitea.com/gitea:1.25.5   Up 2 minutes             127.0.0.1:3000->3000/tcp
gitea-db    postgres:17                     Up 2 minutes (healthy)   5432/tcp

Configurazione del reverse proxy

Aggiungi Gitea alla tua configurazione Nginx esistente:

server {
    listen 443 ssl http2;
    server_name git.example.com;

    ssl_certificate /etc/letsencrypt/live/git.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/git.example.com/privkey.pem;

    server_tokens off;

    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;
    }
}

client_max_body_size 512M consente push di grandi dimensioni, particolarmente utile con Git LFS attivo. server_tokens off nasconde la versione di Nginx negli header di risposta, perché la divulgazione della versione aiuta gli attaccanti a sfruttare vulnerabilità note.

sudo nginx -t && sudo systemctl reload nginx

Creare l'utente amministratore

docker exec -it gitea gitea admin user create \
  --username admin \
  --password "$(openssl rand -base64 16)" \
  --email admin@example.com \
  --admin \
  --must-change-password
New user 'admin' has been successfully created!

Salva la password generata in un posto sicuro (un password manager, non un post-it). Il flag --must-change-password forza il cambio password al primo accesso. Una volta effettuato il login, abilita l'autenticazione a due fattori in Settings > Security > Two-Factor Authentication.

Come configurare il passthrough SSH per Gitea in Docker?

Crea un utente git sull'host con lo stesso UID del container. Aggiungi un blocco AuthorizedKeysCommand in /etc/ssh/sshd_config che chiama docker exec gitea /usr/local/bin/gitea keys. Questo instrada le operazioni SSH git dalla porta 22 dell'host direttamente nel container, senza esporre una seconda porta SSH.

Creare l'utente git sull'host

L'utente deve avere UID 1000 per corrispondere all'utente interno del container:

sudo adduser --system --shell /bin/bash --group --disabled-password --home /home/git --uid 1000 git

Se l'UID 1000 è già occupato dal tuo utente abituale, modifica USER_UID/USER_GID nel file compose per usare un UID disponibile, oppure adatta il flag --uid qui.

Creare il wrapper della shell

La shell dell'utente git deve inoltrare i comandi nel container:

sudo tee /usr/local/bin/gitea-shell > /dev/null << 'WRAPPER'
#!/bin/sh
/usr/bin/docker exec -i --env SSH_ORIGINAL_COMMAND="$SSH_ORIGINAL_COMMAND" gitea sh "$@"
WRAPPER
sudo chmod 755 /usr/local/bin/gitea-shell
sudo usermod -s /usr/local/bin/gitea-shell git
ls -la /usr/local/bin/gitea-shell
-rwxr-xr-x 1 root root 99 Mar 20 10:00 /usr/local/bin/gitea-shell

Aggiungere l'utente git al gruppo docker

sudo usermod -aG docker git

Questo dà all'utente git il permesso di eseguire docker exec. Su un server dedicato a Gitea è accettabile. Su un host condiviso, considera regole sudo limitate al comando docker exec specifico.

Configurare sshd

Aggiungi questo blocco alla fine di /etc/ssh/sshd_config:

# Gitea SSH passthrough
Match User git
  AuthorizedKeysCommandUser git
  AuthorizedKeysCommand /usr/bin/docker exec -i gitea /usr/local/bin/gitea keys -c /etc/gitea/app.ini -e git -u %u -t %t -k %k

L'AuthorizedKeysCommand chiede al container Gitea di verificare se la chiave pubblica presentata dal client SSH appartiene a un utente Gitea registrato. Se corrisponde, SSH concede l'accesso. Il blocco Match User git limita questo al solo utente git, lasciando il tuo accesso SSH abituale invariato.

sudo sshd -t

Nessun output significa che la configurazione è valida. Se vedi errori, controlla il blocco Match per eventuali refusi.

sudo systemctl restart sshd

Testare l'accesso SSH

Aggiungi la tua chiave pubblica SSH al tuo account Gitea tramite l'interfaccia web (Settings > SSH/GPG Keys). Poi dalla tua macchina locale:

ssh -T git@git.example.com
Hi there, admin! You've successfully authenticated with the key named "my-laptop", but Gitea does not provide shell access.

Ora puoi clonare, fare push e pull tramite SSH sulla porta 22:

git clone git@git.example.com:admin/my-repo.git

Come abilitare e configurare Gitea Actions per il CI/CD?

Gitea Actions è un sistema CI/CD integrato con una sintassi compatibile con GitHub Actions. Lo abiliti con una variabile d'ambiente (già impostata nel nostro file compose), distribuisci un runner come servizio Docker Compose e scrivi file YAML di workflow nei tuoi repository.

Come registrare un act_runner con Docker Compose?

Prima genera un token di registrazione del runner dal pannello di amministrazione di Gitea:

docker exec -it gitea gitea actions generate-runner-token
NxxxxxxxxxxxxxxxxxxxxxxxN

Copia questo token. Aggiungilo al tuo file .env:

echo "GITEA_RUNNER_TOKEN=YOUR_TOKEN_HERE" >> /opt/gitea/.env
chmod 600 /opt/gitea/.env

Ora aggiungi il servizio runner al tuo docker-compose.yml:

  runner:
    image: docker.io/gitea/act_runner:0.3.0
    container_name: gitea-runner
    environment:
      - GITEA_INSTANCE_URL=http://gitea:3000
      - GITEA_RUNNER_REGISTRATION_TOKEN=${GITEA_RUNNER_TOKEN}
      - GITEA_RUNNER_NAME=vps-runner
    volumes:
      - runner-data:/data
      - /var/run/docker.sock:/var/run/docker.sock
    depends_on:
      - gitea
    restart: always
    networks:
      - gitea

Aggiungi runner-data: alla sezione volumes: in fondo al file. Poi avvia il runner:

docker compose up -d runner
docker compose logs runner --tail 20
level=info msg="Starting runner daemon"
level=info msg="Runner registered successfully"

Il runner monta il socket Docker (/var/run/docker.sock) per poter creare container per ogni job. È una pratica standard per i runner CI, ma significa che i job possono accedere al demone Docker dell'host. Per ambienti isolati, considera l'uso di Docker-in-Docker (DinD).

Variabile d'ambiente Scopo
GITEA_INSTANCE_URL URL interna dove il runner raggiunge Gitea (usa il nome del servizio, non il dominio pubblico)
GITEA_RUNNER_REGISTRATION_TOKEN Token monouso da gitea actions generate-runner-token
GITEA_RUNNER_NAME Nome visualizzato nel pannello di amministrazione di Gitea

Come appare un workflow Gitea Actions?

Gitea Actions usa la stessa sintassi YAML di GitHub Actions, con alcune differenze. Crea .gitea/workflows/build.yml nel tuo repository:

name: Build and Test

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: '1.23'

      - name: Build
        run: go build -v ./...

      - name: Test
        run: go test -v ./...

  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4

      - name: Deploy via SSH
        env:
          DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
        run: |
          mkdir -p ~/.ssh
          echo "$DEPLOY_KEY" > ~/.ssh/id_ed25519
          chmod 600 ~/.ssh/id_ed25519
          ssh -o StrictHostKeyChecking=accept-new user@production "cd /app && git pull && systemctl restart myapp"

Salva il secret DEPLOY_KEY nelle impostazioni del repository sotto Settings > Actions > Secrets.

Funzionalità Gitea Actions GitHub Actions
Directory dei workflow .gitea/workflows/ .github/workflows/
uses: actions/* Funziona (recuperato da GitHub di default) Nativo
Servizi container Supportato Supportato
Build a matrice Supportato Supportato
Workflow riutilizzabili Supportato da Gitea 1.24 Supportato
Actions del Marketplace La maggior parte funziona, alcune richiedono adattamento Nativo

Come abilitare Git LFS in Gitea?

Git Large File Storage permette di tracciare file binari (immagini, modelli, dataset) senza gonfiare il repository. Gitea ha il supporto LFS integrato. Lo abbiamo già abilitato con LFS_START_SERVER=true nel file compose. I dati LFS vengono salvati nel volume gitea-data di default.

Per configurare il percorso di archiviazione esplicitamente o aumentare i limiti, modifica la configurazione di Gitea:

docker exec -i gitea sh -c 'cat >> /data/gitea/conf/app.ini' << 'EOF'

[lfs]
PATH = /data/git/lfs
EOF

Riavvia Gitea per applicare le modifiche:

docker compose restart gitea

Sul lato client, installa git-lfs e traccia i tipi di file:

git lfs install
git lfs track "*.bin" "*.h5" "*.onnx"
git add .gitattributes
git commit -m "Track model files with LFS"
git push

I file LFS vengono archiviati sul server al PATH configurato dentro il container. Per deployment di grandi dimensioni, puoi configurare lo storage compatibile S3 in app.ini sotto la sezione [lfs].

Come fare il mirroring dei repository GitHub su Gitea?

Il pull mirroring crea una copia in sola lettura di un repository GitHub sulla tua istanza Gitea. La sincronizzazione avviene automaticamente secondo un intervallo configurabile. Utile per il backup, per avere una cache locale dietro il runner CI, o per ridurre la dipendenza da GitHub.

Nell'interfaccia web di Gitea:

  1. Clicca su + > New Migration
  2. Seleziona GitHub come sorgente
  3. Inserisci l'URL del repository (es. https://github.com/owner/repo.git)
  4. Per i repository privati, inserisci il tuo nome utente GitHub e un personal access token come password
  5. Seleziona This repository will be a mirror
  6. Imposta l'intervallo di mirroring (default: 8 ore)
  7. Clicca su Migrate Repository

Il mirror sincronizza branch, tag e release. Issue, pull request e wiki possono essere migrati durante l'importazione iniziale ma non vengono sincronizzati continuamente.

Per fare il mirroring tramite API:

curl -X POST "https://git.example.com/api/v1/repos/migrate" \
  -H "Authorization: token YOUR_GITEA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "clone_addr": "https://github.com/owner/repo.git",
    "mirror": true,
    "mirror_interval": "8h",
    "repo_name": "repo-mirror",
    "repo_owner": "admin",
    "service": "github"
  }'

Come configurare i webhook per il deployment?

I webhook inviano richieste HTTP POST a un URL quando si verificano eventi in un repository. Sono un modo semplice per attivare deployment, notifiche o sistemi CI esterni.

Nel tuo repository, vai su Settings > Webhooks > Add Webhook > Gitea:

  • Target URL: https://deploy.example.com/hooks/gitea
  • HTTP Method: POST
  • Content Type: application/json
  • Secret: genera con openssl rand -hex 32
  • Trigger events: Push events (o personalizza)

Sul lato ricevente, il tuo script di deployment deve verificare la firma del webhook:

# The webhook sends a X-Gitea-Signature header
# Verify it with the shared secret before acting on the payload
EXPECTED=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" | awk '{print $2}')
if [ "$SIGNATURE" != "$EXPECTED" ]; then
  echo "Invalid signature"
  exit 1
fi

Un ricevitore webhook minimale usando uno strumento leggero come webhook:

[
  {
    "id": "deploy",
    "execute-command": "/opt/deploy.sh",
    "command-working-directory": "/opt/app",
    "trigger-rule": {
      "match": {
        "type": "payload-hmac-sha256",
        "secret": "your-webhook-secret",
        "parameter": {
          "source": "header",
          "name": "X-Gitea-Signature"
        }
      }
    }
  }
]

Come fare il backup di un'istanza Gitea?

Gitea include un comando gitea dump che impacchetta i repository, il database, la configurazione e gli oggetti LFS in un singolo file zip. Per PostgreSQL, serve anche un pg_dump separato per il ripristino point-in-time.

Backup manuale

docker exec -it gitea /usr/local/bin/gitea dump -c /data/gitea/conf/app.ini --file /data/gitea-backup.zip
docker cp gitea:/data/gitea-backup.zip /opt/gitea/backups/

Il dump include:

Contenuto Incluso nel dump
Repository Git
Database (SQLite o dump)
Configurazione (app.ini)
Oggetti LFS
Allegati, avatar
Pacchetti No (backup separato)

Per PostgreSQL, esegui anche:

docker exec gitea-db pg_dump -U gitea gitea | gzip > /opt/gitea/backups/gitea-db-$(date +%Y%m%d).sql.gz

Backup automatizzato con cron

sudo mkdir -p /opt/gitea/backups
sudo chown root:root /opt/gitea/backups
sudo chmod 700 /opt/gitea/backups

Crea lo script di backup:

sudo tee /opt/gitea/backup.sh > /dev/null << 'BACKUP'
#!/bin/bash
set -euo pipefail

BACKUP_DIR="/opt/gitea/backups"
DATE=$(date +%Y%m%d-%H%M)

# Gitea dump
docker exec gitea /usr/local/bin/gitea dump -c /data/gitea/conf/app.ini --file /data/gitea-backup.zip --quiet
docker cp gitea:/data/gitea-backup.zip "$BACKUP_DIR/gitea-dump-$DATE.zip"
docker exec gitea rm /data/gitea-backup.zip

# PostgreSQL dump
docker exec gitea-db pg_dump -U gitea gitea | gzip > "$BACKUP_DIR/gitea-db-$DATE.sql.gz"

# Keep last 7 daily backups
find "$BACKUP_DIR" -name "gitea-*" -mtime +7 -delete

echo "Backup completed: $DATE"
BACKUP
sudo chmod 700 /opt/gitea/backup.sh
ls -la /opt/gitea/backup.sh
-rwx------ 1 root root 523 Mar 20 10:00 /opt/gitea/backup.sh

Programmalo quotidianamente alle 3 di mattina:

echo "0 3 * * * root /opt/gitea/backup.sh >> /var/log/gitea-backup.log 2>&1" | sudo tee /etc/cron.d/gitea-backup
sudo chmod 644 /etc/cron.d/gitea-backup

Testa lo script una volta manualmente:

sudo /opt/gitea/backup.sh
Backup completed: 20260320-1030
ls -lh /opt/gitea/backups/
-rw-r--r-- 1 root root 2.3M Mar 20 10:30 gitea-dump-20260320-1030.zip
-rw-r--r-- 1 root root  48K Mar 20 10:30 gitea-db-20260320-1030.sql.gz

Copia i backup fuori dal server. Un backup locale che muore con il disco non è un backup.

Come aggiornare Gitea in sicurezza?

Scarica la nuova immagine, ricrea il container e lascia che Gitea gestisca automaticamente le migrazioni del database. Fissa le versioni delle immagini in modo che gli aggiornamenti siano intenzionali, non accidentali.

cd /opt/gitea

# Back up first
sudo /opt/gitea/backup.sh

# Update the image tag in docker-compose.yml, then:
docker compose pull gitea
docker compose up -d gitea
docker compose logs gitea --tail 30

Osserva i messaggi di migrazione:

2026/03/20 10:35:00 ...les/migration.go:67:Migrate() [I] Migration completed

Dopo aver confermato che Gitea si avvia correttamente, aggiorna il runner se è disponibile una nuova versione:

docker compose pull runner
docker compose up -d runner

Qual è la differenza tra Gitea e Forgejo?

Forgejo si è separato da Gitea alla fine del 2022, dopo che una società a scopo di lucro (Gitea Ltd.) ha preso il controllo del progetto Gitea. Forgejo è governato da Codeberg e.V., un'associazione tedesca senza scopo di lucro. All'inizio del 2026, Forgejo è un hard fork con codebase divergenti. Entrambi funzionano con un setup Docker simile, ma la migrazione tra i due non è più trasparente.

Gitea Forgejo
Governance Gitea Ltd. (a scopo di lucro) Codeberg e.V. (senza scopo di lucro)
Licenza MIT GPL-3.0+ (da Forgejo v9.0)
Immagine Docker docker.gitea.com/gitea codeberg.org/forgejo/forgejo
Supporto Actions Sì (act_runner) Sì (runner compatibile)
Compatibilità API Compatibile GitHub Compatibile GitHub
Funzionalità uniche Gitea Enterprise, server MCP Federazione (ForgeFed), strumenti di moderazione

Se vuoi un progetto governato dalla comunità con licenza copyleft, scegli Forgejo. Se vuoi il progetto originale con supporto commerciale, scegli Gitea. Il setup Docker Compose di questa guida funziona per entrambi con modifiche minime (cambia l'immagine, adatta i percorsi).

Se inizi con Gitea e vuoi cambiare in seguito: esporta i dati con gitea dump, installa Forgejo e importa. Testa a fondo. Le codebase si sono sufficientemente diversificate da avere alcuni schemi di database diversi.

Quanta RAM e CPU serve a Gitea?

Un'istanza Gitea con PostgreSQL usa circa 150-250 MB di RAM a riposo. Con uso attivo di 5-10 utenti e runner CI, prevedi 300-500 MB totali. È circa 10 volte più leggero di un'istanza GitLab, che richiede almeno 4 GB.

Questi numeri provengono da un'istanza Gitea in produzione su un VPS Virtua Cloud (4 vCPU, 8 GB di RAM):

docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"
NAME            CPU %     MEM USAGE / LIMIT
gitea           0.15%     148.2MiB / 7.77GiB
gitea-db        0.08%     45.3MiB / 7.77GiB
gitea-runner    0.02%     32.1MiB / 7.77GiB
Scenario RAM (stack completo) CPU
A riposo, pochi repo ~230 MB < 1%
Attivo, 5-10 utenti ~400 MB 2-5%
Build CI in corso ~600 MB (picchi durante i build) 20-50% per job
Equivalente GitLab 4.000+ MB 10%+ a riposo

Gitea gira tranquillamente su un VPS da 2 GB. Con runner CI, 4 GB offrono margine per build simultanei.

Risoluzione dei problemi

Connessione SSH rifiutata: Verifica che l'utente git esista, che sshd_config contenga il blocco Match e che sshd sia stato riavviato. Controlla i log:

journalctl -u sshd -f

Il runner non prende i job: Conferma che il runner è registrato nel pannello di amministrazione (Site Administration > Actions > Runners). Controlla i log del runner:

docker compose logs runner --tail 50

Errori di connessione al database all'avvio: L'health check dovrebbe prevenirlo, ma se Gitea parte prima che PostgreSQL sia pronto:

docker compose restart gitea

Il push LFS fallisce con errore 413: Aumenta client_max_body_size nella configurazione Nginx. 512M di solito basta, ma adatta in base ai file più grandi.

Log di Gitea:

docker compose logs gitea --tail 100

Oppure segui in tempo reale:

docker compose logs gitea -f

Copyright 2026 Virtua.Cloud. Tutti i diritti riservati. Questo contenuto è un'opera originale del team Virtua.Cloud. La riproduzione, ripubblicazione o redistribuzione senza autorizzazione scritta è vietata.

Pronto a provare?

Distribuisci il tuo server in pochi secondi. Linux, Windows o FreeBSD.

Vedi piani VPS