
Ogni tanto capita di guardare la propria organizzazione su GitHub e chiedersi quanto di quel codice sia davvero nostro. Non in senso legale ma in senso operativo: dove vive, chi ne detiene le chiavi, cosa succede il giorno in cui cambiano i termini di servizio o il piano gratuito diventa meno gratuito.
Per un homelab è una curiosità. Per chi gestisce script, playbook e configurazioni di infrastrutture altrui, è una domanda che prima o poi presenta il conto.
Forgejo è la risposta più elegante che ho trovato a questa domanda.
È un forge Git self-hosted: repository, pull request, issue, wiki, registry pacchetti e una CI compatibile con la sintassi di GitHub Actions, il tutto in un singolo binario scritto in Go che gira sereno in mezzo giga di RAM.
Non è un GitLab in miniatura, ed è esattamente questo il punto: fa quello che serve davvero, senza portarsi dietro Redis, Sidekiq, Gitaly e otto giga di requisiti minimi.
Nasce nel 2022 come fork di Gitea, quando marchio e domini di quest’ultimo sono passati a una società for-profit. Oggi vive sotto Codeberg e.V., un’associazione non-profit tedesca, con licenza GPL e una governance pubblica.
È la stessa piattaforma che regge Codeberg.org con oltre centomila utenti e non è esattamente un progetto sperimentale.
In questa guida lo installiamo su Ubuntu Server 26.04 LTS partendo da zero: database PostgreSQL, utente di servizio dedicato, deploy da binario con verifica GPG, unit systemd irrobustita, reverse proxy Nginx con certificato Let’s Encrypt e configurazione iniziale.
Alla fine avrai un’istanza raggiungibile in HTTPS, pronta per accogliere il primo git push.
Mettiamoci al lavoro.
PREREQUISITI
- Ubuntu 26.04 LTS (server), accesso sudo
- 2 vCPU / 2 GB RAM / 20 GB disco come minimo ragionevole (Forgejo da solo gira anche con meno, ma le Actions e i repo crescono)
- Un record DNS
A/AAAAche punta al server, ad esempiogit.miodominio.tld - Porte 80 e 443 raggiungibili (o solo interne, se pubblichi tramite un altro proxy)
AGGIORNAMENTO DEL SISTEMA
Aggiornare il sistema e installare le dipendenze con i comandi:
|
0 1 |
sudo apt update && sudo apt upgrade -y sudo apt install -y git git-lfs curl xz-utils gnupg ca-certificates |
Verificare la versione di Git (Forgejo 16 richiede Git ≥ 2.34) con il comando:
|
0 |
git --version |
Dovremmo visualizzare un output simile al seguente:
|
0 |
git version 2.53.0 |
INSTALLAZIONE DATABASE POSTGRESQL
SQLite funziona ed è comodo per test, ma per un’istanza destinata a durare consiglio PostgreSQL.
|
0 1 |
sudo apt install -y postgresql postgresql-contrib sudo systemctl enable --now postgresql |
Creare utente e database con i comandi:
|
0 |
sudo -u postgres psql |
Quindi eseguire i comandi SQL:
|
0 1 2 |
CREATE ROLE forgejo WITH LOGIN PASSWORD 'PASSWORD_MOLTO_ROBUSTA'; CREATE DATABASE forgejo WITH OWNER forgejo TEMPLATE template0 ENCODING 'UTF8' LC_COLLATE 'C.UTF-8' LC_CTYPE 'C.UTF-8'; \q |
NOTA BENE: TEMPLATE template0 con collation C.UTF-8 evita problemi di ordinamento e di ricostruzione indici dopo un upgrade di PostgreSQL. Annota la password: ti servirà nel wizard.
Eseguire un Test di connessione con il comando:
|
0 |
psql -h 127.0.0.1 -U forgejo -d forgejo -c '\conninfo' |
Quindi inserire la password dell’utente creato poco fa
Se è tutto OK dovremmo visualizzare un output simile al seguente:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
Connection Information Parameter | Value ----------------------+------------------------ Database | forgejo Client User | forgejo Host | 127.0.0.1 Server Port | 5432 Options | Protocol Version | 3.0 Password Used | true GSSAPI Authenticated | false Backend PID | 34026 SSL Connection | true SSL Library | OpenSSL SSL Protocol | TLSv1.3 SSL Key Bits | 256 SSL Cipher | TLS_AES_256_GCM_SHA384 SSL Compression | false ALPN | postgresql Superuser | off Hot Standby | off (18 rows) |
CREAZIONE UTENTE DI SISTEMA E STRUTTURA DELLE DIRECTORY
Forgejo non va mai eseguito come root. Creare un utente di servizio git con il comando:
|
0 1 |
sudo adduser --system --shell /bin/bash --gecos 'Forgejo Git Service' \ --group --disabled-password --home /home/git git |
Configurare le directory di dati con i seguenti comandi:
|
0 1 2 3 4 |
sudo mkdir -p /var/lib/forgejo /etc/forgejo sudo chown -R git:git /var/lib/forgejo sudo chmod 750 /var/lib/forgejo sudo chown root:git /etc/forgejo sudo chmod 770 /etc/forgejo |
NOTA BENE: /etc/forgejo resta scrivibile finché il wizard web non ha generato app.ini
DOWNLOAD E VERIFICA DEL FILE BINARIO
Impostare le variabili (adatta versione e architettura linux-amd64 o linux-arm64):
|
0 1 2 |
FORGEJO_VERSION=16.0.1 FORGEJO_ARCH=linux-amd64 BASE="https://codeberg.org/forgejo/forgejo/releases/download/v${FORGEJO_VERSION}" |
Scaricare il binario quindi firma e checksum:
|
0 1 2 3 |
cd /tmp curl -fLO "${BASE}/forgejo-${FORGEJO_VERSION}-${FORGEJO_ARCH}" curl -fLO "${BASE}/forgejo-${FORGEJO_VERSION}-${FORGEJO_ARCH}.asc" curl -fLO "${BASE}/forgejo-${FORGEJO_VERSION}-${FORGEJO_ARCH}.sha256" |
Verificare lo SHA256 con il comando:
|
0 |
sha256sum -c "forgejo-${FORGEJO_VERSION}-${FORGEJO_ARCH}.sha256" |
Dovremmo visualizzare un output simile al seguente:
|
0 |
forgejo-16.0.1-linux-amd64: OK |
Verificare la firma GPG (chiave di release Forgejo) con il comando:
|
0 1 2 |
gpg --keyserver keys.openpgp.org --recv EB114F5E6C0DC2BCDD183550A4B61A2DC5923710 gpg --verify "forgejo-${FORGEJO_VERSION}-${FORGEJO_ARCH}.asc" \ "forgejo-${FORGEJO_VERSION}-${FORGEJO_ARCH}" |
Dovremmo visualizzare un output simile al seguente:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
gpg: directory '/root/.gnupg' created gpg: keybox '/root/.gnupg/pubring.kbx' created gpg: /root/.gnupg/trustdb.gpg: trustdb created gpg: Total number processed: 1 gpg: imported: 1 gpg: Signature made Tue 21 Jul 2026 08:34:47 AM UTC gpg: using EDDSA key 3BF4E813F84812411DA01E5BC4186DF66F4B6750 gpg: WARNING: This key is not certified with a trusted signature! gpg: There is no indication that the signature belongs to the owner. Primary key fingerprint: EB11 4F5E 6C0D C2BC DD18 3550 A4B6 1A2D C592 3710 Subkey fingerprint: 3BF4 E813 F848 1241 1DA0 1E5B C418 6DF6 6F4B 6750 |
NOTA BENE: L’avviso sulla chiave “not certified with a trusted signature” è normale: significa solo che non hai firmato tu quella chiave.
Procedere con l’installazione con il comando:
|
0 |
sudo install -m 755 "forgejo-${FORGEJO_VERSION}-${FORGEJO_ARCH}" /usr/local/bin/forgejo |
fare il check con il comando:
|
0 |
forgejo --version |
Dovremmo visualizzare un output simile al seguente:
|
0 |
forgejo version 16.0.1+gitea-1.22.0 (release name 16.0.1) built with GNU Make 4.4.1, go1.26.5 : bindata, timetzdata, sqlite, sqlite_unlock_notify |
CONFIGURAZIONE DEL SYSTEMD
Eseguire il comando:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
sudo tee /etc/systemd/system/forgejo.service > /dev/null <<'EOF' [Unit] Description=Forgejo (Beyond coding. We forge.) After=network-online.target Wants=network-online.target After=postgresql.service Requires=postgresql.service [Service] Type=simple User=git Group=git WorkingDirectory=/var/lib/forgejo/ RuntimeDirectory=forgejo RuntimeDirectoryMode=0750 ExecStart=/usr/local/bin/forgejo web --config /etc/forgejo/app.ini Restart=always Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/forgejo # Hardening NoNewPrivileges=true PrivateTmp=true ProtectSystem=full ProtectHome=false ProtectKernelTunables=true ProtectKernelModules=true ProtectControlGroups=true RestrictSUIDSGID=true LockPersonality=true [Install] WantedBy=multi-user.target EOF |
Quindi fare un reload e abilitare Forgejo con i comandi:
|
0 1 2 |
sudo systemctl daemon-reload sudo systemctl enable --now forgejo sudo systemctl status forgejo --no-pager |
Se è tutto OK dovremmo visualizzare il seguente output:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
● forgejo.service - Forgejo (Beyond coding. We forge.) Loaded: loaded (/etc/systemd/system/forgejo.service; enabled; preset: enabled) Active: active (running) since Sat 2026-07-25 13:44:14 UTC; 4s ago Invocation: 7ce8cc3c82a94da388640ce1a5d8bcd2 Main PID: 34277 (forgejo) Tasks: 8 (limit: 6210) Memory: 92.3M (peak: 92.4M) CPU: 450ms CGroup: /system.slice/forgejo.service └─34277 /usr/local/bin/forgejo web --config /etc/forgejo/app.ini Jul 25 13:44:14 vm-srv-test forgejo[34277]: 2026/07/25 13:44:14 cmd/web.go:114:showWebStartupMessage() [I] Forgejo version: 16.0.1+gitea-1.22.0 built with G…nlock_notify Jul 25 13:44:14 vm-srv-test forgejo[34277]: 2026/07/25 13:44:14 cmd/web.go:115:showWebStartupMessage() [I] * RunMode: prod Jul 25 13:44:14 vm-srv-test forgejo[34277]: 2026/07/25 13:44:14 cmd/web.go:116:showWebStartupMessage() [I] * AppPath: /usr/local/bin/forgejo Jul 25 13:44:14 vm-srv-test forgejo[34277]: 2026/07/25 13:44:14 cmd/web.go:117:showWebStartupMessage() [I] * WorkPath: /var/lib/forgejo Jul 25 13:44:14 vm-srv-test forgejo[34277]: 2026/07/25 13:44:14 cmd/web.go:118:showWebStartupMessage() [I] * CustomPath: /var/lib/forgejo/custom Jul 25 13:44:14 vm-srv-test forgejo[34277]: 2026/07/25 13:44:14 cmd/web.go:119:showWebStartupMessage() [I] * ConfigFile: /etc/forgejo/app.ini Jul 25 13:44:14 vm-srv-test forgejo[34277]: 2026/07/25 13:44:14 cmd/web.go:120:showWebStartupMessage() [I] Prepare to run install page Jul 25 13:44:15 vm-srv-test forgejo[34277]: Listen: http://0.0.0.0:3000 Jul 25 13:44:15 vm-srv-test forgejo[34277]: AppURL(ROOT_URL): http://localhost:3000/ Jul 25 13:44:15 vm-srv-test forgejo[34277]: Starting new Web server: tcp:0.0.0.0:3000 on PID: 34277 Hint: Some lines were ellipsized, use -l to show in full. |
Controllare i log in caso di problemi con il comando:
|
0 |
sudo journalctl -u forgejo -f |
A questo punto Forgejo è in ascolto su http://127.0.0.1:3000 (di default sull’interfaccia 0.0.0.0, che restringeremo dopo il wizard).
INSTALLAZIONE E CONFIGURAZIONE DEL REVERSE PROXY
Installare Nginx con il comando:
|
0 |
sudo apt install -y nginx |
Configurazione del vhost:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
sudo tee /etc/nginx/sites-available/forgejo.conf > /dev/null <<'EOF' server { listen 80; listen [::]:80; server_name git.miodominio.tld; # Necessario per push/pull di repository di grandi dimensioni 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; # Evita timeout su operazioni Git lunghe proxy_read_timeout 300s; proxy_send_timeout 300s; proxy_request_buffering off; } } EOF |
Quindi eseguire i comandi:
|
0 1 2 |
sudo ln -s /etc/nginx/sites-available/forgejo.conf /etc/nginx/sites-enabled/ sudo rm -f /etc/nginx/sites-enabled/default sudo nginx -t && sudo systemctl reload nginx |
CONFIGURAZIONE DEL CERTIFICATO LET’S ENCRYPT
Eseguire i comandi:
|
0 1 |
sudo apt install -y certbot python3-certbot-nginx sudo certbot --nginx -d git.miodominio.tld |
Certbot aggiunge il blocco listen 443 ssl, il redirect da HTTP e imposta il rinnovo automatico via systemd timer.
Configurare il firewall con i comandi:
|
0 1 2 |
sudo ufw allow OpenSSH sudo ufw allow 'Nginx Full' sudo ufw enable |
ATTENZIONE: In homelab: se usi una CA interna (es. Windows CA con certificato wildcard) o un proxy centralizzato come Nginx Proxy Manager / Caddy, salta Certbot e limita l’esposizione della 3000 alla sola rete di gestione.
CONFIGURAZIONE INIZIALE VIA WEB
Aprire da un qualsiasi https://git.miodominio.tld/. Comparirà il wizard di installazione.
Di seguito tutti i valori da inserire:
Database
- Tipo: PostgreSQL
- Host: 127.0.0.1:5432
- Utente: forgejo
- Password: quella impostata in precedenza
- Nome database: forgejo
- SSL: Disable (connessione locale)
Impostazioni generali
- Site Title: il nome della tua istanza
- Repository Root Path:
/var/lib/forgejo/data/forgejo-repositories - LFS Root Path:
/var/lib/forgejo/data/lfs - Run As Username:
git - SSH Server Domain:
git.miodominio.tld - SSH Port:
22 - Forgejo HTTP Listen Port:
3000 - Forgejo Base URL:
https://git.miodominio.tld/ - Log Path:
/var/lib/forgejo/log
Impostazioni opzionali
- Email Settings: server SMTP, se vuoi notifiche e reset password funzionanti
- Server and Third-Party Service Settings: spunta **Disable Self-Registration** e **Require Sign-In to View Pages** se l’istanza è privata
- Administrator Account Settings: **crea qui l’account amministratore**. Se non lo fai, il primo utente registrato diventa admin — non è quello che vuoi su un’istanza esposta.
Al termine cliccare Installare Forgejo
A questo punto Il file /etc/forgejo/app.ini viene generato e il servizio si riavvia.
Se è andato tutto a buon fine dovremmo visualizzare la Dashboard di ForgeJo
HARDENING POST INSTALLAZIONE
Rendere la configurazione in sola lettura per il servizio con i comandi:
|
0 1 |
sudo chmod 750 /etc/forgejo sudo chmod 640 /etc/forgejo/app.ini |
Far ascoltare Forgejo solo su localhost, dato che davanti c’è Nginx. Modificare il file di configurazione /etc/forgejo/app.ini:
|
0 1 2 3 4 |
[server] HTTP_ADDR = 127.0.0.1 HTTP_PORT = 3000 ROOT_URL = https://git.miodominio.tld/ DOMAIN = git.miodominio.tld |
Di seguito alcune direttive utili da aggiungere o verificare:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
[service] DISABLE_REGISTRATION = true REQUIRE_SIGNIN_VIEW = true ENABLE_NOTIFY_MAIL = true [security] INSTALL_LOCK = true PASSWORD_COMPLEXITY = lower,upper,digit,spec MIN_PASSWORD_LENGTH = 12 [session] COOKIE_SECURE = true [log] LEVEL = Info |
Riavviare Forgejo con il comando:
|
0 |
sudo systemctl restart forgejo |
VERIFICA FUNZIONALE
Creare un repository di test dalla UI, poi da una macchina client:
|
0 1 2 3 4 |
# HTTPS git clone https://git.miodominio.tld/tuo-utente/test.git # SSH (dopo aver caricato la tua chiave pubblica nel profilo) git clone git@git.miodominio.tld:tuo-utente/test.git |
Se l’SSH non funziona controllare che la chiave sia stata scritta in /home/git/.ssh/authorized_keys e che i permessi siano 700 sulla directory e 600 sul file.
BACKUP DI FORGEJO
Forgejo include un comando di dump che raccoglie database, repository, allegati e configurazione:
|
0 1 2 |
sudo -u git bash -c 'cd /var/lib/forgejo && \ /usr/local/bin/forgejo dump --config /etc/forgejo/app.ini \ --file /var/lib/forgejo/backup/forgejo-dump-$(date +%F).zip' |
Creare prima la directory (sudo -u git mkdir -p /var/lib/forgejo/backup) e schedulare il comando con un timer systemd o un cron, poi replicare l’archivio fuori dall’host.
AGGIORNAMENTO DI FORGEJO
L’upgrade consiste nel sostituire il binario:
|
0 |
sudo systemctl stop forgejo |
Scaricare e verificare la nuova versione quindi:
|
0 |
sudo install -m 755 forgejo-NUOVA_VERSIONE-linux-amd64 /usr/local/bin/forgejo |
Avviare Fogejo:
|
0 1 |
sudo systemctl start forgejo sudo journalctl -u forgejo -f |
Prima di ogni upgrade di major version: eseguire il dump e leggi la sezione breaking changes delle release notes. Le migrazioni del database vengono applicate automaticamente al primo avvio e non sono reversibili.
PROBLEMI FREQUENTI
502 Bad Gateway: servizio non attivo o HTTP_ADDR errato systemctl status forgejo – Verificare che la porta 3000 sia in ascolto con ss -ltnp
Push oltre pochi MB rifiutato: limite di Nginx – Aumentare client_max_body_size
Clone SSH chiede la password: chiave non registrata o permessi errati su /home/git/.ssh – Correggere i permessi e controllare authorized_keys
Link generati in http://localhost:3000: ROOT_URL non corretto – Correggere [server] ROOT_URL e riavviare
Errori di collation dopo upgrade PostgreSQL: database creato senza template0 – REINDEX DATABASE forgejo;
Actions non partono: nessun Runner registrato – installare Forgejo Runner e registralo dalla UI (dalla 15.0 la registrazione è guidata via web)
PRO E CONTRO
Di seguito i PRO:
Governance e licenza. È il differenziale vero. Forgejo nasce nell’ottobre 2022 quando domini e marchio Gitea passarono a una società for-profit senza il consenso della community; il progetto vive oggi sotto l’ombrello di Codeberg e.V., un’associazione non-profit tedesca.
Dalla versione 9 è rilasciato sotto licenza copyleft GPL, quindi nessun rischio di edizioni “enterprise” chiuse o di funzionalità tenute dietro un paywall.
Leggerezza. Binario statico singolo in Go, gira tranquillamente in ~512 MB di RAM — abissale la differenza con GitLab CE, che vuole 4 GB minimi (8 per stare comodi) più Postgres, Redis, Gitaly e i worker Sidekiq.
Su un LXC o una VM piccola del tuo homelab è un altro pianeta.
Feature set completo per il 90% dei casi. Repo, pull request, issue, wiki, LFS, registry pacchetti (Docker, npm, PyPI, Cargo, Debian, Go) e CI compatibile con la sintassi GitHub Actions, tutto incluso.
Autoconsistenza del progetto. Forgejo è sviluppato usando Forgejo stesso, testato e rilasciato con Forgejo Actions; Gitea è sviluppato su GitHub e rilasciato con GitHub Actions.
Codeberg fa da banco di prova su scala reale per ogni release prima che arrivi agli altri self-hoster.
Migrazione facile in entrata. L’importer da GitHub/GitLab funziona bene e copre issue, PR, label e milestone, non solo il codice.
Di seguito i CONTRO:
Ecosistema di terze parti più povero. Un decennio di tutorial, provider Terraform, script di backup e guide di integrazione parla di Gitea: quando cerchi soluzioni finisci spesso su documentazione Gitea da adattare. In genere funziona, ma è attrito.
Nessun vendor a cui rivolgersi. Non esiste un contratto di supporto commerciale. Per un’azienda che vuole un’alternativa leggera a GitHub con un fornitore da chiamare, Gitea è la risposta più difendibile in sede di procurement e nel tuo contesto MSP questo pesa soprattutto verso clienti che chiedono un SLA sul software.
CI meno matura di GitLab. Forgejo Actions copre bene i casi standard, ma non ha l’equivalente di pipeline multi-stage complesse, DAG, environment con approvazioni, security scanning integrato o container registry con policy di retention avanzate.
Federazione ancora acerba. ActivityPub/ForgeFed è la bandiera del progetto ma va trattato come un opt-in sperimentale: non contarci per casi d’uso produttivi.
Porta a senso unico verso Gitea. Dopo l’hard fork del 2024 non sono più intercambiabili come drop-in; passare dall’uno all’altro oggi è un progetto di migrazione, non un cambio di configurazione. La direzione Forgejo → Gitea in particolare è chiusa.
Manutenzione a tuo carico. Upgrade, backup, TLS, monitoraggio: tutto tuo. È il prezzo del self-hosting rispetto a GitHub/GitLab.com, e va messo a budget in ore, non solo in euro di VPS.

0 commenti