Skip to content

Naming a Loopback Forgejo Through hosts and ROOT_URL

Adityo Guni Waluyo

A local domain via /etc/hosts plus DOMAIN and ROOT_URL in Forgejo, and the 100 MB Cloudflare upload cap that makes the SSH path the sensible choice.

At ten in the morning I committed a config that opened LAN access to Forgejo through a domain, and one hour later the next commit closed it again. A revert within one hour, an embarrassing but honest track record. The plan was simple: my HTTP forge lives on loopback, give it a nice name on the laptop, done. It turns out those two commits were a lesson in how a domain name lives in three different places at once: the hosts file, the application config, and the network path you pick.

The Shortcut Illusion in /etc/hosts

The classic first step: add one line to the laptop's /etc/hosts, mapping repo.adityo.web.id to the machine running the container. The format is genuinely simple, a text file that associates IP addresses with hostnames, one line per address [6], and changes normally take effect immediately [6]. The pattern is legitimate, the man page itself names bootstrapping and small networks without DNS as its classic uses [6]. From the browser, the Forgejo page opens right away under that sweet new name. Feels like winning.

But hosts only changes the client side. Forgejo itself has no idea about its new name, and the clone URLs shown in the UI are still generated from its internal config. At this point I briefly believed the client-side override was enough. It never is.

DOMAIN and ROOT_URL: the Name on the Server Side

One formatting detail that trips people up: this image's env vars use a double-underscore separator, FORGEJO__server__DOMAIN, not a single one. The double underscore marks a section boundary, so server then DOMAIN [1]. Typing one underscore and the variable lands in the wrong section, silently, with no clear error. I got bitten once before noticing the pattern.

The server side lives in two env vars I added to Compose: FORGEJO__server__DOMAIN=repo.adityo.web.id and FORGEJO__server__ROOT_URL pointing at the same domain. The docs describe ROOT_URL as the override for the automatically generated public URL, useful precisely when internal and external URLs don't match, the official example being a Docker container [3]. The reverse proxy page points in the same direction: when the URL users see differs from what Forgejo sees, ROOT_URL is what keeps generated links from breaking [7]. Once both env vars were in and the container restarted, the clone URLs in the UI finally matched the name I typed in the browser. Only then did the domain feel whole, on both sides at once.

There is also a practical upside that makes this pattern worth keeping even for a single laptop: no TTL to wait out and no DNS zone to edit. Delete the line from hosts and the name vanishes without leaving config residue on the server [6]. For short-lived experiments, the throwaway nature is the feature.

Why I Reverted Anyway: the 100 MB Cap at the Edge

The part that made this morning's commit walk it back: opening the HTTP path meant putting it behind Cloudflare, and Cloudflare's own table lists a max upload size of just 100 MB on Free and Pro plans, 200 MB on Business [5]. The docs even offer their escape hatches: split uploads into smaller chunks, or use a DNS-only record that skips the proxy [5]. For a forge whose entire reason to exist is big files, chunking is permanent extra work, and DNS-only means going through the trouble of naming the thing just to give up edge protection. The sensible answer was none of those: SSH on port 3122 never touches the Cloudflare edge at all, so HTTP went back to loopback, the domain stays alive through hosts plus ROOT_URL for light browsing, and every heavy push goes over SSH. An hour earlier it looked like a revert. In hindsight it reads as the right routing decision.

What that one hour taught me: a hostname never lives in just one place. Something resolves it, an application renders links with it, and a network path carries the heavy traffic. All three can, and probably should, be configured separately.

Sumber

  1. Forgejo Docs: Installation with Docker
  2. Forgejo Docs: Configuration Cheat Sheet
  3. Cloudflare Docs: Default Cache Behavior (upload limits)
  4. hosts(5) - Linux manual page
  5. Forgejo Docs: Reverse Proxy

Related articles