GitLab SSH keys and selecting which key to use
This guide explains how to use more than one SSH key with GitLab on Windows (OpenSSH
and optional Pageant), and how to choose a specific key per repository or per
git push—including when an automation agent runs git in your shell.
Related:
- First push and CI:
gitlab-getting-started.md - CI and runners:
gitlab-ci.md
Canonical remote for this repository
Always use the gitlab-ai SSH host alias for esysdox-ops (automation key
ai_id_ed25519_gitlab, GitLab account @ESysRoot):
git@gitlab-ai:libesys/esysdox-ops.git
Local git remote name: gitlab (already configured after the initial push):
git remote add gitlab git@gitlab-ai:libesys/esysdox-ops.git
git push -u gitlab master
Do not use git@gitlab.com:libesys/esysdox-ops.git for this repo unless
Host gitlab.com in ~/.ssh/config is updated to a valid IdentityFile. The
gitlab.com alias may point at a missing id_ed25519_mg_libesys private key.
Agents and operators should run all GitLab git fetch / git push against
gitlab → git@gitlab-ai:libesys/esysdox-ops.git.
Concepts
| Piece | Role |
|---|---|
| Key pair | Private file on your PC + public file added to GitLab |
~/.ssh/config Host blocks | Map a short name (e.g. gitlab-ai) to gitlab.com + one private key |
| Git remote URL | git@HOST_ALIAS:group/project.git selects which Host block SSH uses |
| GitLab account | Can have many public SSH keys under Preferences → SSH Keys |
SSH does not use “the AI’s key” as a separate identity. Commands run on your machine
and use keys from your .ssh folder (or Pageant). You control the key by remote URL
and IdentityFile in config.
Generate a new key (OpenSSH)
Example: dedicated key for automation or a single machine:
ssh-keygen -t ed25519 -C "ai@libesys.org" -f $env:USERPROFILE\.ssh\ai_id_ed25519_gitlab
- Use a passphrase for interactive-only keys, or
-N '""'only if you accept non-interactive push without a passphrase (automation trade-off). - Outputs:
ai_id_ed25519_gitlab— private (never commit, never paste in chat)ai_id_ed25519_gitlab.pub— public (safe to add to GitLab)
Show the public key for copy/paste:
Get-Content $env:USERPROFILE\.ssh\ai_id_ed25519_gitlab.pub
Add the public key to GitLab
Account key (typical):
- GitLab → Preferences → SSH Keys
- Paste the
.publine → Add key
Repeat for each key you use (personal, work, automation). GitLab accepts multiple keys on one account.
Project deploy key (optional):
- Project → Settings → Repository → Deploy keys
- One writable deploy key per project if you need repo-scoped access only
Configure ~/.ssh/config to select a key
On Windows the file is C:\Users\<you>\.ssh\config.
If you use Pageant (PuTTY), keep an existing line such as:
Include pageant.conf
Add separate Host blocks per key. Use IdentitiesOnly yes so SSH does not
offer every loaded Pageant key until GitLab accepts one at random.
Example: personal key on gitlab.com, automation key on alias gitlab-ai:
Include pageant.conf
# Personal / default LibESys key (OpenSSH file or via Pageant for other tools)
Host gitlab.com
HostName gitlab.com
User git
IdentityFile ~/.ssh/id_ed25519_mg_libesys
IdentitiesOnly yes
# Automation / agent pushes — dedicated key file
Host gitlab-ai
HostName gitlab.com
User git
IdentityFile ~/.ssh/ai_id_ed25519_gitlab
IdentitiesOnly yes
Notes:
HostNameis always the real server (gitlab.com).Hostis only the alias you use in git URLs.- Paths use
~/.ssh/...; OpenSSH on Windows expands them correctly. - If the personal key is only in Pageant as a
.ppk, load it in Pageant or export an OpenSSH private key (PuTTYgen) and pointIdentityFileat that file.
Self-managed GitLab: replace gitlab.com with your hostname in both HostName and
URLs (e.g. git@gitlab-ai:group/repo.git still works if HostName is your server).
Choose the key in git remotes
| Remote URL | SSH uses |
|---|---|
git@gitlab.com:libesys/esysdox-ops.git | Host gitlab.com → id_ed25519_mg_libesys (not used for this repo) |
git@gitlab-ai:libesys/esysdox-ops.git | Host gitlab-ai → ai_id_ed25519_gitlab (canonical for esysdox-ops) |
Add a remote (name gitlab is arbitrary):
git remote add gitlab git@gitlab-ai:libesys/esysdox-ops.git
Push:
git push -u gitlab master
To switch an existing remote to the other key:
git remote set-url gitlab git@gitlab-ai:libesys/esysdox-ops.git
Test before pushing
ssh -T git@gitlab.com
ssh -T git@gitlab-ai
Success looks like:
Welcome to GitLab, @YourUsername!
GitLab may exit with code 0 or 1 for this test command; the welcome line matters.
Ask an agent to use a specific key
When using Cursor or another agent that runs git in your environment, instruct it
explicitly:
- “Use remote
gitlabwith host aliasgitlab-ai”, or - “Push to
git@gitlab-ai:group/esysdox-ops.git”
The agent should not receive your private key in chat. It relies on your local
~/.ssh/config and the remote URL you specify.
One-off key without editing remotes
For a single command:
$env:GIT_SSH_COMMAND = "ssh -i $env:USERPROFILE\.ssh\ai_id_ed25519_gitlab -o IdentitiesOnly=yes"
git push gitlab master
Prefer Host aliases in config for anything repeated.
Pageant and multiple keys
If Include pageant.conf is set, Pageant may still load legacy .ppk keys. Use
IdentitiesOnly yes on each Host gitlab* block so OpenSSH uses only the
IdentityFile you named for that alias.
Typical workflow:
- Daily PuTTY/Pageant workflows → load
.ppkin Pageant. - Git from terminal with a dedicated alias →
Host gitlab-ai+ OpenSSHIdentityFile.
Security practices
| Do | Don't |
|---|---|
Add only .pub files to GitLab | Paste private keys in issues, chat, or email |
| Use separate keys per machine or purpose when useful | Commit *_gitlab private keys to git |
| Revoke keys in GitLab when a machine is retired | Share one private key across people |
| Use deploy keys for single-repo automation | Reuse production personal keys for experiments |
Troubleshooting
Permission denied (publickey)
- Public key not added to GitLab (or wrong account).
- Wrong
Hostin URL (gitlab.comvsgitlab-ai). - Private file path wrong in
IdentityFile. - Pageant offering other keys — set
IdentitiesOnly yes.
Agent push works in terminal but not from IDE
- IDE may use a different user or miss
~/.ssh/config; runssh -T git@gitlab-aiin the same environment the agent uses. - Approve network/shell permissions when the agent runs
git push.
Host key / known_hosts
First connect may ask to trust GitLab’s host key; accept once or add gitlab.com to
known_hosts via a manual ssh -T.
Quick checklist
- Key pair created (
ssh-keygen) -
.pubadded to GitLab SSH Keys (or deploy key) -
~/.ssh/confighas oneHostblock per key withIdentitiesOnly yes -
ssh -T git@gitlab-ai(or your alias) shows welcome message -
git remoteURL uses the intended alias (git@gitlab-ai:...) - Agent instructions name the alias when you want the non-default key