Relocated LXC 114's own admin sshd to port 2200 (systemd ssh.socket override) to free port 22 for Forgejo's git-SSH, dropping the ugly :2222 from every clone URL. Updated the 5 hosts' remotes/SSH config and the corresponding UniFi rules to match.
3.9 KiB
Forgejo
Self-hosted Git service (soft fork of Gitea) with Postgres.
Persistent Data
Split between local disk and the UNAS forgejo_data share (see
nfs-mounts — you'll need to add this share
following that guide, it isn't in the table yet):
-
forgejo_datanamed volume (local disk) — app config, SSH host keys, session store, Bleve search index. -
forgejo_db_datanamed volume (local disk) — Postgres data directory. Databases don't belong on NFS regardless of engine (locking/fsync semantics), so this stays local even though Forgejo isn't using SQLite. -
Share dirs, NFS-mounted on the Proxmox host and bind-mounted into the LXC at
FORGEJO_DATA_ROOT:repositories/— bare git repo objects. This is what grows over time.lfs/— Git LFS objects.attachments/— issue/PR attachments.avatars/— user and repo avatars.
Git's own protocol tolerates NFS latency far better than a database does, so this bulk data is a safe, capacity-friendly NAS candidate.
The share binds use create_host_path: false, so the stack refuses to start
if the share is not mounted, rather than silently writing into an empty
directory that later needs merging back in.
Installation
-
Create
.envif it does not exist:cp -n docker-compose-files/forgejo/.env.sample docker-compose-files/forgejo/.env -
Set the required values in
docker-compose-files/forgejo/.env— at minimumFORGEJO_ROOT_URL,FORGEJO_DOMAIN,FORGEJO_DB_PASSWORD, andFORGEJO_DATA_ROOT. -
Add the UNAS share and bind-mount it into the LXC, following nfs-mounts.md (add
forgejo_datato the share list there, sameNo Root Squashtreatment aspaperless_data):# On the Proxmox host, once the share is mounted at /mnt/unas/forgejo_data pct set <vmid> -mp0 /mnt/unas/forgejo_data,mp=/mnt/unas/forgejo_data mkdir -p /mnt/unas/forgejo_data/{repositories,lfs,attachments,avatars} chown -R 101000:101000 /mnt/unas/forgejo_data -
Deploy with
make:make deploy-forgejoManual equivalent:
./substitute_env.sh docker-compose-files/forgejo/template.yaml docker-compose.forgejo.yml .env docker-compose-files/forgejo/.env docker compose -f docker-compose.forgejo.yml config --quiet docker compose -f docker-compose.forgejo.yml up -d -
Open
http://<host-ip>:3000, create the first (admin) account, and confirm repo creation/push/clone works.
Reverse Proxy
Add a block for git.<domain> (port FORGEJO_HTTP_PORT) to
docker-compose-files/caddy/Caddyfile_template, then make reload-caddy.
Git-over-SSH (FORGEJO_SSH_PORT) is not proxyable through Caddy — expose that
port directly if you want SSH clone/push from outside the LAN.
FORGEJO_SSH_PORT defaults to 2222 because the LXC's own admin sshd
already owns port 22. This instance was later moved to the standard port —
the LXC's admin sshd got relocated to 2200 first (systemd ssh.socket
override), freeing 22 for Forgejo's git-SSH. See .env.sample for the
one-time steps if you want to do the same elsewhere.
Notes
- Pin
FORGEJO_VERSIONto a specific major (as shipped,10) rather than floating — Forgejo releases can carry DB migrations, so an unpinned tag risks pulling a breaking bump on a routinedocker compose pull. FORGEJO__security__INSTALL_LOCK=trueis baked into the template since all DB config is supplied via environment — this skips the web installer so a stray first visitor can't reconfigure the instance.
Useful Commands
# Tail logs
docker compose -f docker-compose.forgejo.yml logs -f forgejo
# Create an additional user without open registration
docker exec -it forgejo forgejo admin user create --username <name> --email <email> --random-password
# Recreate after an image update
docker compose -f docker-compose.forgejo.yml pull
docker compose -f docker-compose.forgejo.yml up -d