Forgejo, on :2222 and through the API
Git over SSH on a node port, git over HTTPS through Traefik — where a correct HTTP default breaks git.
Forgejo 17.1.3 runs in-cluster and is where tenants push. It is reachable two ways, and both of them are shaped by hop 2.
SSH on 2222. Port 22 on the node is the node’s own sshd, and with no load balancer there is no second address to give git a port 22 of its own. So Forgejo’s SSH listener is on node port 2222 and every clone URL carries it: ssh://git@git.example.com:2222/tenant/app.git. That is a visible piece of the constraint leaking into a URL a tenant has to type, which is a fine thing to point at in a classroom — architecture is usually invisible to users right up until it is in their remote.
Smart-HTTP through Traefik. Git over HTTPS goes through the API service, which means it comes in through the same entrypoint as everything else, subject to the same entrypoint timeouts. And this is where a default that is correct for HTTP is wrong for git.
The readTimeout fix. Traefik’s respondingTimeouts.readTimeout bounds how long it will spend reading a request. The default is 60 seconds, which is generous for an HTTP request and short for git-receive-pack: a push holds one request open while the client uploads a pack file and the server indexes it. A large repository or a first push of a big history exceeds 60 seconds, Traefik cuts the connection, and the client reports RPC failed; curl 92 or the remote end hung up unexpectedly.
The symptom is why this belongs in classroom time. It works for small repositories and fails for large ones, which points every instinct at the repository, at Forgejo, or at the client’s network. Nothing in the error names the proxy. The fix is one key on the entrypoint — readTimeout: 0s to disable the bound, or a large value if you would rather keep one — and finding it without knowing it exists takes an afternoon.
# platform/traefik/values.yaml
ports:
websecure:
port: 8443
hostPort: 443
transport:
respondingTimeouts:
readTimeout: 0s # default 60s cuts git-receive-pack mid-push.
writeTimeout: 0s # and mid-clone, on a large upload-pack.
# what the tenant sees when this is left at the default:
# $ git push origin main
# Enumerating objects: 41822, done.
# Writing objects: 100% (41822/41822), 412.87 MiB | 6.10 MiB/s, done.
# error: RPC failed; curl 92 HTTP/2 stream 0 was not closed cleanly
# fatal: the remote end hung up unexpectedly
#
# small repos work. large repos fail. nothing mentions Traefik.
Check yourself
2 questions. One attempt each is recorded; the explanation is the point, not the score.
Large git pushes fail with RPC failed; curl 92. Small ones work. Where is the fault?
Why is Forgejo’s SSH on 2222 rather than 22?