There is a tiny moment of tension in every SSH setup: two nearly identical filenames sit beside each other, and a form asks you to paste “the key.” This is the moment worth getting right. The file ending in .pub is meant to travel to GitLab. The private file beside it is the proof of identity and stays with you.
Once that boundary is clear, the rest is a calm chain of trust: inspect what already exists, create a key only when needed, let an agent remember its passphrase, add the public half to the intended account, verify GitLab’s server identity, then test which account answered.
Two files, two very different promises
id_ed25519: the private key. Keep it on the device, protect it with filesystem permissions and preferably a passphrase, and never paste it into GitLab.id_ed25519.pub: the public key. Add its complete one-line contents to GitLab.The optional comment at the end helps humans identify the key; it is not used as your GitLab login.
The fingerprint is a compact identifier derived from a key. Compare fingerprints when names alone are ambiguous.
Look before generating another identity
ssh -V
find ~/.ssh -maxdepth 1 -type f \( -name '*.pub' -o -name 'config' \) -printOpenSSH_9.6p1 Ubuntu-3ubuntu13.18, OpenSSL 3.0.13
/home/you/.ssh/id_ed25519.pub
/home/you/.ssh/configWhy this inspection is deliberately narrow
ssh -Vwrites its version to standard error on many OpenSSH builds; the displayed version is from the local Ubuntu validation environment.findis limited to~/.ssh, one level deep, and names ending in.pub; it does not print secret file contents.An existing public key may already be suitable, but first learn which account, device, and purpose it belongs to.
A public key must uniquely map to one GitLab user. For a new device, a separate pair limits the damage if that device is lost.
Create an ED25519 key with a name you will recognize
ssh-keygen -t ed25519 -C "work-laptop-2026" -f ~/.ssh/gitlab_work_ed25519Generating public/private ed25519 key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/you/.ssh/gitlab_work_ed25519
Your public key has been saved in /home/you/.ssh/gitlab_work_ed25519.pubRisk level: caution. Review the command before running it.
The prompts are part of the security design
GitLab recommends ED25519 for most systems. Some FIPS environments may require a supported alternative such as RSA with at least 4096 bits.
-Cstores a human-readable comment in the public key; use a device or purpose label that remains helpful after staff changes.-fchooses explicit filenames and avoids overwriting a default key. If the path already exists, stop and inspect it rather than confirming replacement.A passphrase protects the private key at rest. It is not sent to GitLab;
ssh-agentcan cache the unlocked identity for a session.This command creates credential files, so it is marked caution. The article’s validation used a disposable path and an empty test-only passphrase, never a production key.
Check the fingerprint without exposing the private key
ssh-keygen -lf ~/.ssh/gitlab_work_ed25519.pub
awk '{print $1, $3}' ~/.ssh/gitlab_work_ed25519.pub256 SHA256:5uOudge50nktZjc1pNyE7trIskSoZdRo0TGJLV40My4 work-laptop-2026 (ED25519)
ssh-ed25519 work-laptop-2026Keep the sample fingerprint in the sample
ssh-keygen -lprints a fingerprint;-fselects the public-key file.The SHA256 value shown here belongs to the disposable documentation key and will not match yours.
The
awkcommand prints only the first and third public-key fields—the algorithm and comment—while omitting the encoded key body.GitLab later shows the uploaded public fingerprint, giving you a safe value to compare.
Let the SSH agent hold the unlocked key
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/gitlab_work_ed25519
ssh-add -lAgent pid 12345
Enter passphrase for /home/you/.ssh/gitlab_work_ed25519:
Identity added: /home/you/.ssh/gitlab_work_ed25519 (work-laptop-2026)
256 SHA256:YOUR_FINGERPRINT work-laptop-2026 (ED25519)The agent remembers access, not ownership
ssh-agentcreates a process and exports connection variables into the current shell througheval.ssh-addasks for the local passphrase and loads the private key into that agent; it does not upload the private key.ssh-add -llists fingerprints of loaded identities, which is safer than displaying their contents.Desktop environments often manage an agent already. Starting a second one may work only in that terminal, so inspect your platform’s keychain integration when keys disappear after reboot.
Paste only the public line into GitLab
cat ~/.ssh/gitlab_work_ed25519.pubssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... work-laptop-2026A safe copy has three recognizable parts
Copy the complete single line: algorithm, full encoded public key, and optional comment.
The real line is much longer than the shortened example. Never paste the literal ellipsis into GitLab.
Confirm the filename ends in
.pubbefore copying.Clipboard contents can be read by other applications on some systems; paste promptly and replace sensitive clipboard content afterward when your environment warrants it.
In GitLab, open your avatar → Edit profile → Access → SSH keys → Add new key. Paste the public line, give it a device-specific title such as “ThinkPad T14 — work,” choose a usage type, and set an expiration date that matches your organization’s key-rotation policy.
Choose Authentication when the key should only access Git over SSH.
Choose Signing when it should only verify SSH-signed commits or tags.
Authentication & Signing permits both and is GitLab’s default; use it only when you intend both roles.
GitLab checks uploaded keys against known compromised keys and rejects a known-compromised public key.
One account-level authentication key can access all projects the account is authorized to use; it does not grant new project membership.
Trust the server before asking it to trust you
On the first connection, SSH may show a host fingerprint. That fingerprint identifies the GitLab server—not your personal key. Compare it through a trusted channel before accepting it. GitLab.com publishes its current SSH host-key fingerprints; a self-managed instance exposes them on its instance-configuration help page or through your administrator.
Ask GitLab which account answered
ssh -T git@gitlab.comWelcome to GitLab, @your-username!Read the username, not just the welcome
-Tdisables pseudo-terminal allocation; GitLab uses SSH for Git transport rather than a general shell session.The SSH username is normally
git, while the welcome message identifies the GitLab account bound to the accepted public key.A successful authentication test does not prove that account has permission to a particular project.
For a self-managed instance, replace the hostname and confirm whether its administrator changed the default SSH username or port.
Make one repository use one explicit identity
Host gitlab-work
HostName gitlab.com
User git
IdentityFile ~/.ssh/gitlab_work_ed25519
IdentitiesOnly yesGive a work identity an SSH host alias when several GitLab keys share one machine.
The alias becomes part of the remote URL
Host gitlab-workdefines a local alias; DNS still resolves the realHostName gitlab.com.IdentityFilepoints to the private key locally. Never commit this configuration if it exposes personal paths or infrastructure details.IdentitiesOnly yestells SSH to offer the configured identities instead of every key an agent happens to hold.Use a remote such as
git@gitlab-work:YOUR_NAMESPACE/project.git, then verify it withgit remote -v.For several accounts on one GitLab instance, GitLab recommends host aliases because a public key can map to only one user.
When GitLab still says no
`Permission denied (publickey)`: run
ssh-add -l, confirm the key appears in the intended GitLab account, and check which hostname the remote uses.SSH asks for `git@gitlab.com`’s password: public-key authentication did not succeed. GitLab is not asking for your web password; inspect the key and agent setup.
Too many authentication failures: an agent may be offering many identities. Use
IdentitiesOnly yesand an explicitIdentityFile.Wrong GitLab username welcomes you: another account owns the offered public key. Use distinct keys and host aliases.
Private key permissions rejected: GitLab troubleshooting guidance recommends mode
600for a private key and700for~/.sshon Unix-like systems.Key expired: an expired GitLab SSH key can no longer authenticate or sign. Generate and add a replacement rather than changing your system clock.
Host identification changed: verify the new server fingerprint with GitLab or your administrator before editing
known_hosts.
ssh -Tv git@gitlab.comVerbose output belongs in a private diagnostic window
-vreports configuration selection, host negotiation, and identities offered; repeat it (-vvor-vvv) only when more detail is necessary.Look for the effective hostname, identity filenames, “Offering public key,” and GitLab’s accept or reject response.
Debug output can expose usernames, local paths, hostnames, network addresses, and fingerprints. Redact it before sharing.
This command diagnoses a connection; it does not change keys or GitLab settings.
Retire keys with the same care used to create them
Review the GitLab SSH-key list periodically. Titles, fingerprints, creation dates, last-used dates, and expiry dates help identify stale devices. Revoke a compromised key promptly; remove keys for retired machines; generate separate replacements rather than copying one private key casually between laptops.
The reassuring part of SSH is not that passwords disappear. It is that the most powerful half of the credential never needs to cross the network. Keep that private half private, verify both identities in the conversation, and the small ritual becomes dependable.
Sources and the next useful step
Return to the first-project workflow and push only after the welcome message names the intended account.
Comments and corrections