homelab-blueprint/docker-compose-files/forgejo/README.md
Brian Pooe 9dfde294cb feat(forgejo): move git-over-SSH to standard port 22
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.
2026-07-19 15:09:55 +02:00

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_data named volume (local disk) — app config, SSH host keys, session store, Bleve search index.

  • forgejo_db_data named 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

  1. Create .env if it does not exist:

    cp -n docker-compose-files/forgejo/.env.sample docker-compose-files/forgejo/.env
    
  2. Set the required values in docker-compose-files/forgejo/.env — at minimum FORGEJO_ROOT_URL, FORGEJO_DOMAIN, FORGEJO_DB_PASSWORD, and FORGEJO_DATA_ROOT.

  3. Add the UNAS share and bind-mount it into the LXC, following nfs-mounts.md (add forgejo_data to the share list there, same No Root Squash treatment as paperless_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
    
  4. Deploy with make:

    make deploy-forgejo
    

    Manual 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
    
  5. 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_VERSION to 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 routine docker compose pull.
  • FORGEJO__security__INSTALL_LOCK=true is 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