
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 DU 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