Self-hosting Gitea on Railway: the two gotchas that break clone URLs and SSH
If you want a private git server without paying for GitHub Enterprise or wrestling with GitLab's resource footprint, Gitea is the obvious pick — it's a single Go binary bundling git hosting, issues, PRs, CI hooks and a web UI, and it runs comfortably on the smallest box you've got. I run a one-click Railway template for it and wanted to write up the two things that actually trip people up when they deploy it there, because neither is obvious from the defaults.
Full disclosure up front: I maintain the Railway template linked below and get a kickback if you deploy through it. If you'd rather not use it, the whole setup is just docker run -p 3000:3000 -p 22:22 gitea/gitea:latest with a volume at /data — everything below applies either way.
Gotcha 1: clone URLs break without ROOT_URL
Gitea generates the clone URL you see in the UI (and the one it puts in CI webhook payloads) from GITEA__server__ROOT_URL. Leave it unset on a platform like Railway and it defaults to whatever internal hostname the container sees itself as — not your public domain. Result: the UI looks fine, but every "copy clone URL" button hands people a URL that doesn't resolve. Set GITEA__server__ROOT_URL=https://<your-domain>/ before you push anything through it, not after — some of it (webhook config, in particular) gets baked in rather than computed live.
Gotcha 2: SSH clone needs its own TCP proxy
Railway's HTTP domain only forwards port 3000. git clone https://... works fine over that. git clone git@... does not, because Gitea's SSH daemon listens on 22 and nothing is routing to it — you have to add a second TCP proxy pointed at 22 explicitly in Railway's networking settings. Easy to miss because the web UI and HTTP clone both work perfectly without it, so there's no error until someone tries to clone over SSH and gets connection refused.
SQLite is fine solo, not forever
The template ships with Gitea's built-in SQLite backend, which is genuinely fine for a solo dev or a small team — no extra service to run, no connection string to manage. It's single-writer though, so if you've got CI hammering it with webhook-triggered pushes from multiple people at once, you'll eventually feel it. Gitea supports pointing at an external Postgres with a couple of env vars whenever you outgrow it; I also maintain a plain Postgres 17 template if you want a target for that migration.
Deploy
One-click, volume already wired to /data so repo data survives redeploys: https://railway.com/deploy/gitea-1?referralCode=Z1xivh&utm_medium=integration&utm_source=template&utm_campaign=devto
Happy to answer questions on memory sizing or the SSH proxy setup in the comments — the SSH part especially trips people up on any platform that proxies by domain rather than raw TCP.
Top comments (0)