Skip to content

[Bug]: Can't set up GitHub Enterprise Cloud with data residency (*.ghe.com) as a source — App install URL uses GHES-style /github-apps/ path and 404s #10573

Description

@phoenixgao

Error Message and Logs

Adding a GitHub App source that points at a GitHub Enterprise Cloud with data residency tenant (https://<subdomain>.ghe.com, e.g. an Enterprise Managed Users / EMU setup) cannot be completed.

The GitHub App itself is created successfully through the manifest flow — Coolify retrieves and stores the app_id, client_id, client_secret, webhook_secret, and private key. But the "Install repositories on GitHub" button (and the "Update repositories" button) links to a URL that returns 404 on GitHub. The installation can therefore never be completed, no installation_id is captured, and the source stays stuck at "You must complete this step before you can use this source!" with no repositories available.

Root cause: Coolify decides the install path with html_url === 'https://github.com' ? 'apps' : 'github-apps'. Any host that isn't literally github.com — including *.ghe.com — is treated as GitHub Enterprise Server and gets the GHES-style /github-apps/... path. But *.ghe.com (Enterprise Cloud with data residency) runs the github.com URL scheme, where the correct, owner-scoped path is /apps/<owner>/<slug>/installations/new.

Steps to Reproduce

  1. Have a GitHub Enterprise Cloud with data residency tenant (https://<subdomain>.ghe.com), e.g. EMU.
  2. In Coolify: Sources → add GitHub App → GitHub Enterprise, with:
    • HTML URL: https://<subdomain>.ghe.com
    • API URL: https://<subdomain>.ghe.com/api/v3
    • Organization: <org>
  3. Click Register now → redirected to GitHub → name the app → create.
    (The app is created and the manifest conversion succeeds — Coolify stores app_id, client_id, client_secret, webhook_secret, and the private key.)
  4. Coolify shows "You must complete this step before you can use this source!" with Install repositories on GitHub.
  5. Click it → https://<subdomain>.ghe.com/github-apps/<kebab-name>/installations/new404.
  6. installation_id is never set; no repositories can be selected; the source is unusable.

Manually creating the app and pasting all credentials into Coolify hits the same wall: the Update repositories button uses the same broken URL helper and also 404s.

Expected behavior

For *.ghe.com hosts, Coolify should build the github.com-family, owner-scoped install URL using GitHub's returned app slug:

https://<subdomain>.ghe.com/apps/<owner>/<slug>/installations/new

instead of the GHES-style

https://<subdomain>.ghe.com/github-apps/<kebab-name>/installations/new

Example Repository URL

No response

Coolify Version

v4.1.2

Are you using Coolify Cloud?

No (self-hosted)

Operating System and Version (self-hosted)

Ubuntu 24.04 Server

Additional Information

This requires three corrections in getInstallationPath():

  1. /github-apps//apps/
  2. include the owner (org) segment: /apps/<owner>/...
  3. use GitHub's returned app slug, not Str::kebab($source->name)

Additional Info

  • Coolify version: v4.1.2 (self-hosted).
  • Tenant: GitHub Enterprise Cloud with data residency (*.ghe.com), Enterprise Managed Users (EMU).

Source of the bug (commit e7dff30b7c998c301fd91bd169727b90c59ec291):

bootstrap/helpers/github.phpgetInstallationPath():

$name = str(Str::kebab($source->name));
$installation_path = $source->html_url === 'https://github.com' ? 'apps' : 'github-apps';
return "$source->html_url/$installation_path/$name/installations/new?".http_build_query(['state' => $state]);

}
function getInstallationPath(GithubApp $source): string
{
$name = str(Str::kebab($source->name));
$installation_path = $source->html_url === 'https://github.com' ? 'apps' : 'github-apps';
$state = Str::random(64);
Cache::put('github-app-setup-state:'.hash('sha256', $state), [
'action' => 'install',
'github_app_id' => $source->id,
'team_id' => $source->team_id,
], now()->addMinutes(60));

Both the Install and Update repository buttons call this helper:

</x-forms.button>
@can('update', $github_app)
<a href="{{ $this->getGithubAppNameUpdatePath() }}">
<x-forms.button canGate="update" :canResource="$github_app"
class="bg-transparent border-transparent hover:bg-transparent hover:border-transparent hover:underline">
Rename
<x-external-link />
</x-forms.button>
</a>
<a href="{{ getInstallationPath($github_app) }}" class="w-fit">
<x-forms.button canGate="update" :canResource="$github_app"

Related: the slug issue (#3 above) overlaps with #5364, where Coolify's local app name diverges from GitHub's returned slug and causes Rename/Update 404s.

GHE.com (data residency) URL conventions — per GitHub Docs, *.ghe.com uses the github.com scheme with the host swapped, not the GHES scheme:

GHES (what Coolify currently applies) GHE.com / github.com (correct)
REST API base https://HOSTNAME/api/v3 https://api.<subdomain>.ghe.com
App install URL /github-apps/<slug>/installations/new /apps/<owner>/<slug>/installations/new

Note: in my case Coolify's API URL was set to https://<subdomain>.ghe.com/api/v3 and the manifest conversion still succeeded, so /api/v3 appears to resolve on this tenant. The API base is therefore a secondary concern; the install path scheme is the actual blocker. Ideally Coolify should also derive https://api.<subdomain>.ghe.com for *.ghe.com hosts.

EMU note: managed users can install GitHub Apps on an org they own (the relevant case here) and can create GitHub Apps, but GitHub App manifests are not available for enterprise-owned apps, and Marketplace apps are unavailable on GHE.com — so the org-owned manifest flow is the expected path, which makes the install-URL bug the sole blocker.

Suggested fix: detect *.ghe.com hosts and treat them like github.com for URL construction — use /apps/, include the owner segment, use GitHub's returned slug, and derive api.<subdomain>.ghe.com for the API base.

Metadata

Metadata

Assignees

No one assigned

    Labels

    🐛 Possible BugReported issues that need to be reproduced by the team.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions