Though it is generally the case and is considered a good practice to have only one public-private key pair per device, sometimes you might need to use more than one. You might use an SSH key pair for your personal projects and a different one for work repositories. On top of that, and you could be using another key to access the client's server.
Managing SSH keys can become cumbersome as soon as the need to use a second key arises. Traditionally, you would use
to add your keys to
ssh-agent, typing in the password for each key as needed. The problem, however, is that this needs
to be done every time the computer is restarted since
ssh-agent will also restart and the keys have to be added along with typing in the
passwords for each key all over again.
Fortunately, the OpenSSH client offers the possibility to manage several keys. The solution for this is to automate adding and storing keys and to specify which key to use which repository by creating a configuration file to specify the customizations. For this purpose, the file
~/.ssh/config with details about hosts using different keys (called "identities") is used.
SSH Config is a per-user configuration file for SSH communication.
Create a new file, if you don't already have one, at
~/.ssh/config. If this config file is new, you might have to do
chmod 600 ~/.ssh/config for permissions.
On Linux and macOS, verify that the permissions on your IdentityFile are 400. SSH will reject, in a not very explicit manner, the SSH keys that are too readable. Tighten it a bit by:
chmod 400 ~/.ssh/id_ed25519
The Ed25519 was introduced on OpenSSH version 6.5 and is now the recommended way to generate ssh key pair. This is EdDSA implementation using the Twisted Edwards curve. It uses elliptic curve cryptography that offers better security with faster performance compared to DSA or ECDSA. Today, the RSA is the most widely used public-key algorithm for SSH keys. But compared to Ed25519, it's slower and even considered not safe if it's generated with a key smaller than 2048-bit length.
The Ed25519 public-key is compact, contains 68 characters compared to RSA 3072 that has 544 characters. Generating the key is also almost as fast as the signing process. It's also fast to perform batch signature verification with Ed25519. It is built to be collision resilience. Hash-function collision won't break the system.
$ ssh-keygen -t ed25519 -C "email@example.com"
This creates a new ssh key, using the provided email as a label. If your system doesn't support the Ed25519 algorithm, use:
ssh-keygen -t rsa -b 4096 -C "firstname.lastname@example.org"
I have two keys,
id_25519.pubfor work repositories and
id_25519_personal.pubfor my personal projects.
Forward, the first problem to solve using this
config is to avoid having to add custom-named SSH keys using
ssh-add. Assuming your private key is named
~/.ssh/id_ed25519, add the following to the
Host github.com HostName github.com User github-corporate-user # GitHub username AddKeysToAgent yes UseKeychain yes PreferredAuthentications publickey IdentityFile ~/.ssh/id_ed25519
The base URI of
Host github.com in
config and the base URI of the repository that you want to work with must match.
Next, the second key for your personal projects with a custom hostname:
Host github-personal HostName github.com User github-personal-user # GitHub username UseKeychain yes PreferredAuthentications publickey IdentityFile ~/.ssh/id_ed25519_personal IdentitiesOnly yes AddKeysToAgent yes
identitiesOnly yes in the above setting. This is because the configuration alone does not ensure that the specified key is used. This is because the
ssh-agent has its own logic as to which key is used and the
IdentityFile information only adds these keys to the list of possible keys.
To restrict the selection to the key specified here, you need the set the
IdentitiesOnly - either host-specific or for all hosts. In the latter case, however, a key must be specified explicitly for each host like it is done here.
Test your connection
$ ssh -T email@example.com $ ssh -T git@github-personal
With each command, if you've used RSA keys, you may see this kind of warning, type yes:
The authenticity of host 'github.com (188.8.131.52)' can't be established. RSA key fingerprint is xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx: Are you sure you want to continue connecting (yes/no)?
If everything is OK, you will see these messages:
Hi your_name! You've successfully authenticated, but GitHub does not provide shell access. Hi your_name! You've successfully authenticated, but GitHub does not provide shell access.
Anyways, with the configuration in place, now you can
git clone git@github-personal:github-account/interesting-project.git.
If you had already cloned the repository, you can change the remote url, if you want, by:
git remote set-url origin git@github-personal:github-account/interesting-project.git firstname.lastname@example.org:some-github-user/interesting-project.git
Changes URLs for the remote. Sets first URL for remote
that matches regex (first URL if no is given) to . If doesn’t match any URL, an error occurs and nothing is changed. More
Configure Git Identity
You can configure an individual repo to use a specific user / email address which overrides the global configuration. From the root of the repo, run:
$> git config user.name "Your Name" $> git config user.email "email@example.com"
Or you could edit the config file to add the user identity directly
$> git config --local -e and add the following:
[user] name = Your Name email = firstname.lastname@example.org
If you require different emails to be used for different repositories, from
Git v2.13 you can set the email on a directory basis by editing the global config
~/.gitconfig using conditionals like so:
[user] name = Your Name email = email@example.com [includeIf "gitdir:~/private/"] path = ~/private/.gitconfig
And then your private config at
~/private/.gitconfig would look like:
[user] email = firstname.lastname@example.org
Per repository settings
It turns out you can also define repository-specific keys overriding the configuration in
~/.ssh/config file. There
are, at least, two ways to do this.
One, using the GIT_SSH_COMMAND. From Git version 2.3.0, you can use the environment variable GIT_SSH_COMMAND like this:
GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa" git clone git@github-corporate:company/project.git
Note that -i can sometimes be overridden by your config file, in which case, you should give SSH an empty config file, like this:
GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa -F /dev/null" git clone git@github-corporate:company/project.git
Second, via core.sshCommand. From Git version 2.10.0, you can configure this per repo or globally, so you don't have to set the environment variable anymore!
git config core.sshCommand "ssh -i ~/.ssh/id_rsa -F /dev/null" git pull git push