← Back home

2026.09 / repository access 056

Coolify private GitHub repo: fix “Permission denied (publickey)”

A Coolify deployment can fail before the Docker build even starts. The log ends with [email protected]: Permission denied (publickey), Could not read from remote repository, or Repository not found. Rebuilding the image will not help because Coolify has not obtained the source.

The reliable fix is to identify the authentication path and repair that path only. For a private GitHub repository, Coolify normally uses either a GitHub App or an SSH deploy key. A deploy key is a good least-privilege choice for one repository: GitHub grants the public half access to that repository, while Coolify stores the matching private half. The repository can remain private and the key can remain read-only.

Do not make the repository public, paste a personal access token into the clone URL, or turn off SSH host verification to make one deployment pass. Match one source mode, URL and credential pair instead.

First, classify the exact Git failure

Open the failed deployment and find the first Git error, not the final generic “deployment failed” line. These messages point to different boundaries:

Log messageMost likely boundary
Permission denied (publickey)GitHub did not accept the SSH key presented by Coolify
Repository not foundWrong owner/repository path, deleted repository, or authenticated identity lacks access
Host key verification failedThe Git host identity is missing, changed or not trusted in the clone environment
Remote branch ... not foundAuthentication may work, but the configured branch name does not exist
Could not read Username on an HTTPS URLA private repository is being cloned through an unauthenticated HTTPS path

Keep the complete failed deployment identifier and timestamp. If several deployments are queued, cancel duplicates and diagnose one. The Coolify deployment queue checklist covers the separate case where the clone has not started yet.

1. Confirm which Coolify source type the app uses

Before rotating anything, inspect the application’s source configuration. A private repository connected through a GitHub App and one connected through a deploy key are different authentication systems:

Do not create both a GitHub App connection and a deploy key as a reflex. More credentials make the failure harder to reason about. Repair the configured method or deliberately migrate to the other one.

2. Use the SSH clone URL for a deploy-key application

Coolify’s deploy-key documentation explicitly requires the provider’s SSH clone URL for the Private Repository (with deploy key) source. For GitHub, the safe generic shape is:

[email protected]:OWNER/REPOSITORY.git

Check the owner and repository spelling, including a recent organization transfer or rename. Do not use an address shaped like https://[email protected]/.... Embedded credentials can leak through configuration screens, process arguments, deployment output or copied support logs.

A repository rename may be redirected for some Git operations, but production configuration should use the current canonical path. Correct it in Coolify, save it, and verify that a new deployment log shows the intended URL without exposing any credential.

3. Prove the public and private halves belong together

In Coolify, open Keys & Tokens → Private Keys and identify the private key selected by the application. In GitHub, open the repository’s Settings → Deploy keys and identify the corresponding public key. Compare their displayed fingerprints where available; never copy the private material into a terminal transcript, issue, chat or public article.

The common failure is simple drift:

If the match cannot be established, replace the pair rather than guessing. Generate a fresh key in Coolify, add only its public half to the intended GitHub repository, keep write access disabled, select the fresh private key on the application, and run one deployment. Retain the old pair only until the new clone succeeds; then remove the stale key from both systems.

4. Keep the deploy key read-only and repository-specific

GitHub deploy keys attach directly to a single repository. GitHub says they are read-only by default, and Coolify only needs clone and fetch access for a source deployment. Leave Allow write access off unless a separately justified workflow truly writes to the repository—which ordinary deployment does not.

Use a different deploy key for each private repository. That limits the damage if one credential is exposed and makes ownership clear during rotation. If one application needs code from several private repositories through Git submodules or private dependencies, its main repository key does not automatically grant access to all of them. Give each dependency an intentional authentication path, or use a narrowly installed GitHub App when repository-by-repository key management becomes cumbersome.

5. Separate repository authentication from server SSH

The same phrase—Permission denied (publickey)—can also appear when Coolify cannot SSH into its destination server. Read the host in the error:

Changing a GitHub deploy key cannot repair Coolify-to-server SSH, and changing the server key cannot repair a GitHub clone. This distinction prevents a repository incident from turning into an infrastructure access incident.

6. Handle host-key failures without disabling verification

If the error is Host key verification failed, the client did not establish a trusted identity for the Git server. That is not the same as GitHub rejecting your deploy key. Do not add StrictHostKeyChecking=no or accept an unexplained changed host key.

For GitHub, compare the observed host-key fingerprint with GitHub’s published SSH key fingerprints. Then repair the trusted-host entry through the supported Coolify/server mechanism. A changed key can be a legitimate rotation, a stale local record, a DNS/routing mistake, or an interception attempt; verification is what distinguishes them.

7. Check the branch only after authentication succeeds

Once the repository can be read, the deployment can still fail if Coolify requests a branch that no longer exists. Compare the application’s configured branch with the repository’s branches and default branch. Names are case-sensitive. Common causes include a move from master to main, a deleted release branch, or an application created from a temporary feature branch.

Do not switch branches blindly on a stateful or manually hot-fixed application. First compare the configured branch, intended commit and currently running release. The Coolify GitHub deploy-not-updating guide explains how to trace the expected commit through the build and public route.

8. Run one controlled deployment and verify the release

After correcting the source, key and branch, trigger one deployment. The log should prove this sequence:

  1. the SSH clone authenticates without prompting;
  2. the intended owner/repository is fetched;
  3. the configured branch resolves to the intended commit;
  4. the Docker or buildpack build starts;
  5. the replacement container becomes healthy;
  6. the public route serves unique content from that release.

Do not stop at a green status or HTTP 200. An old container may still be serving, and a single-page application may return its homepage for a missing path. Fetch a release-specific endpoint, heading, asset name or harmless commit marker that only the intended version contains:

curl --fail --silent --show-error \
  'https://app.example.com/release-check?v=EXPECTED_RELEASE' | \
  grep -F 'EXPECTED UNIQUE CONTENT'

If clone succeeds but no deployment starts after the next push, repository access is fixed; automatic deployment is a separate webhook or GitHub App concern. A deploy key lets Coolify read source. It does not, by itself, notify Coolify that a commit was pushed.

Safe recovery checklist

  1. Capture the first Git error and identify the host it names.
  2. Confirm whether the application uses a GitHub App or deploy key.
  3. For deploy-key mode, use [email protected]:OWNER/REPOSITORY.git.
  4. Confirm the repository owner and name are current.
  5. Match the Coolify private key to the public deploy key on that exact repository.
  6. Replace an uncertain pair; never expose the private half while testing.
  7. Leave write access disabled and use one key per repository.
  8. Verify a host-key failure against the provider’s published fingerprints.
  9. Check the configured branch after repository authentication succeeds.
  10. Deploy once, follow its exact log, and prove unique live release content.
  11. Remove stale credentials after the replacement works.

Authoritative references: Coolify’s deploy-key guide documents generating the key in Coolify, adding the public half to the repository, keeping write access disabled, selecting the SSH URL and verifying the clone. GitHub’s deploy-key documentation explains repository scope and read-only defaults. GitHub also maintains dedicated guides for Permission denied (publickey) and published SSH host-key fingerprints.