Skip to content

Multi-Forgejo-Instance Support

The thfg CLI supports multiple Forgejo-compatible instances simultaneously. This guide explains the configuration model, host auto-detection from git remote, compatibility with public instances like Codeberg, and the architectural role of X-Forgejo-Host header routing through the proxy.

thfg resolves the active host using the hosts array in ~/.config/thfg/config.json. Each entry is a HostEntry:

{
"hosts": [
{
"name": "pikapods",
"host": "https://pastoral-oyster.pikapod.net",
"proxyUrl": "https://proxy.example.com",
"token": "YOUR_TOKEN",
"username": "your-username",
"password": "your-password",
"remotes": [
"git@pastoral-oyster.pikapod.net",
"https://pastoral-oyster.pikapod.net"
]
},
{
"name": "codeberg",
"host": "https://codeberg.org",
"token": "YOUR_CODEBERG_TOKEN",
"remotes": [
"git@codeberg.org",
"https://codeberg.org"
]
},
{
"name": "work",
"host": "https://git.mycompany.com",
"proxyUrl": "https://forgejo-proxy.mycompany.com",
"remotes": [
"git@git.mycompany.com",
"https://git.mycompany.com"
]
}
],
"defaultOrg": "my-default-org"
}
FieldRequiredDescription
nameyesUnique identifier for this entry
hostyesForgejo instance base URL (no trailing slash)
proxyUrlnoForgejo API Proxy URL — enables proxy-only features
tokennoForgejo API token (prefer thfg auth login --token)
usernamenoWebUI username — required for project and log commands
passwordnoWebUI password — required for project and log commands
remotesnoGit remote URL prefixes for auto-detection

When you run thfg inside a git repository, the CLI calls git remote -v and matches each remote URL against the remotes prefixes in your hosts array. The first match wins.

# Working in ~/projects/forgejo-proxy (cloned from pastoral-oyster.pikapod.net)
$ thfg issue list
# → automatically resolves to the "pikapods" host entry
# Working in ~/projects/some-codeberg-repo (cloned from codeberg.org)
$ thfg issue list
# → automatically resolves to the "codeberg" host entry

If no remote matches any configured host, thfg falls back to the first entry in the hosts array and emits a warning to stderr. You can override host resolution by setting FORGEJO_HOST or by passing --repo owner/repo explicitly.

  • Matching is prefix-based: "git@codeberg.org" matches git@codeberg.org:alice/myrepo.git
  • HTTPS and SSH remotes are handled separately; add both if you use both
  • Shorter prefixes match more broadly; be specific to avoid false matches

Codeberg runs Forgejo, so the standard Forgejo REST API is fully available. To configure a Codeberg host entry:

  1. Generate a Codeberg API token at https://codeberg.org/user/settings/applications
  2. Add a host entry:
{
"name": "codeberg",
"host": "https://codeberg.org",
"token": "YOUR_CODEBERG_TOKEN",
"remotes": ["git@codeberg.org", "https://codeberg.org"]
}
  1. Run thfg auth status to verify the connection.

Most thfg commands work against Codeberg without any proxy. Commands that require proxyUrl (proxy-specific features) are listed in the next section.

Working with gitea.io and other self-hosted instances

Section titled “Working with gitea.io and other self-hosted instances”

Any instance running Forgejo or Gitea is compatible. The API surface may differ slightly across versions; thfg targets the Forgejo 15.x API surface. Older or newer Gitea instances should work for most commands but may return errors on newer endpoints.

FeatureDirect Forgejo (no proxy)With proxy (proxyUrl)
thfg issue list/view/create/edit/close
thfg repo list/view/create
thfg pr list/view/merge
thfg run list/view
thfg run logs (streaming)❌ requires proxy
thfg project list --org❌ requires proxy
thfg project create/edit/close❌ requires proxy
thfg run diagnose❌ requires proxy
thfg issue list --me (cross-repo)
thfg repo file get/list

For commands marked requires proxy, the CLI routes the request through the proxy’s WebUI-backed endpoints which are not available in the standard Forgejo API.

When the forgejo-proxy is configured with ALLOW_EXTERNAL_HOST_OVERRIDE=true, any request can carry an X-Forgejo-Host header to override which upstream Forgejo instance the proxy routes to. This allows a single proxy deployment to fan out to multiple upstream Forgejo hosts.

The proxy validates the header against an allowlist when ALLOW_EXTERNAL_HOST_OVERRIDE=true is set.

The CLI currently does not automatically add X-Forgejo-Host on all requests — it always uses the host in the matched HostEntry as the direct API target, and proxyUrl for proxy-specific commands. This is intentional: sending all traffic through a shared proxy is an opt-in scenario. Canonical alias calls such as thfg api /activitypub/actor follow the same rule: they only fan out through a shared proxy when you explicitly route them there.

To manually route a request through the proxy to a different upstream, add the header to thfg api:

Terminal window
thfg api /repos/myorg/myrepo \
--header "X-Forgejo-Host: https://other-forgejo.example.com"

Or with curl:

Terminal window
curl -s -H "Authorization: token $TOKEN" \
-H "X-Forgejo-Host: https://other-forgejo.example.com" \
"$PROXY_URL/api/v1/repos/myorg/myrepo"

Enabling external host override on the proxy

Section titled “Enabling external host override on the proxy”

If you operate a shared proxy and want to allow callers to specify an upstream at request time, set:

Terminal window
ALLOW_EXTERNAL_HOST_OVERRIDE=true
Terminal window
# Initialize a new config
thfg config init
# Add a second host entry
thfg config set hosts[1].name codeberg
thfg config set hosts[1].host https://codeberg.org
thfg config set hosts[1].token YOUR_TOKEN
# Verify
thfg auth status
thfg doctor

thfg picks the wrong host Make sure the remotes prefixes are specific enough and that your git remote URL matches exactly. Run git remote -v and compare with your config.

Commands that work on host A fail on host B Check that both host entries have a valid token. For proxy-backed commands, verify that the proxyUrl is set on the correct entry and the proxy is reachable.

Authentication errors on Codeberg Codeberg tokens are scoped — ensure your token has repository, issue, and user read/write scopes depending on which commands you use.

The shared proxy host is asleep before FastAPI starts The proxy cannot normalize provider HTML until the request reaches the app. Keep client-side retry logic in place for this case; the deferred availability gap is tracked in forgejo-proxy#18.