A server that needs to pull the latest code from several GitHub repos on its own, with no one around to type a password, is a bad place to keep a Personal Access Token. A PAT is scoped to the whole account (or needs fine-grained setup anyway), the leak risk is higher, and rotating it is a hassle. A deploy key fits better: it’s read-only, scoped to a single repo, and dies with the repo if removed, so the blast radius of a compromised server stays small.

For a handful of repos (under 10 or so), generate a separate keypair per repo rather than reusing one key everywhere - a reused key still works, but a leak exposes every repo it’s attached to. No passphrase is needed since the pull runs unattended, and that’s fine here because each key is already restricted to one repo, read-only, on a server that’s trusted to run the pull.

Generate a keypair per repo, named so it’s obvious which repo it belongs to:

ssh-keygen -t ed25519 -C "deploy-repo1" -f ~/.ssh/deploy_repo1 -N ""
ssh-keygen -t ed25519 -C "deploy-repo2" -f ~/.ssh/deploy_repo2 -N ""
# repeat for each repo

Add each public key to its repo under Settings > Deploy keys > Add deploy key, leaving “Allow write access” unchecked.

Point git at the right key per repo with a host alias in ~/.ssh/config, one block per repo:

Host repo1.github.com
  HostName github.com
  User git
  IdentityFile ~/.ssh/deploy_repo1
  IdentitiesOnly yes

Host repo2.github.com
  HostName github.com
  User git
  IdentityFile ~/.ssh/deploy_repo2
  IdentitiesOnly yes

IdentitiesOnly yes matters here - without it, SSH may offer other loaded keys before falling back to the one in the config, which against multiple deploy-key-restricted repos leads to auth failures or GitHub logging a pile of rejected key attempts.

Clone using the alias instead of the real github.com host:

git clone [email protected]:youruser/repo1.git
git clone [email protected]:youruser/repo2.git

For repos already checked out, just swap github.com for the alias in the existing remote URL:

git remote set-url origin [email protected]:youruser/repo1.git

Lock down the key files so SSH doesn’t complain about permissions:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/deploy_repo1 ~/.ssh/deploy_repo2

This per-repo approach stops being the right fit once the repo count grows into the dozens under the same org - at that point a GitHub App with contents:read on selected repos, exchanged for a short-lived installation token before each pull, gives one credential to manage and per-repo access toggled centrally, at the cost of registering the app and scripting the token exchange. For a handful of repos, the per-repo deploy key setup above is simpler and avoids that extra machinery.

Verify each alias resolves to the right key before relying on it in an automated job:

A successful connection replies with a message confirming the GitHub username tied to that deploy key, after which git pull in that repo’s directory should succeed without any prompt.