Complete Guide to Setup SSH Keys for Github (in Linux)

How to not Enter A Password and Still Be Safe

I use 2FA wherever I can. One of them is Github. However, the problem with 2FA, at least for Github, is that you have to get and use your personal access token for pushing to your repository on Github instead of your password. Well, this makes sense since the ability to access, read and write to your repository must have a security level to a similar extent to simply logging in Github website, yet personal access token is just too long, you can't memorize it and you need to take a note somewhere so that you can copy and paste each time. However, HTTPS is not the only way you can push to your repository. SSH is one of them and it is safer to use.

SSH keys are located in your computer, which means your computer is the key to push to or pull from your repository. That also means any other machine will not be able to push to your repository. This is a great scenario for companies where they require access to the repository only on company machines. Instead of providing each employee credentials, you set it up on your company machines.

SSH keys also can be passwordless unless you define one. You do not have to write your password each time you push to the repository.

As to how to set it up, there are many great documentations, StackExchange answers or blog posts out there. In this post, I will try to provide a complete guide to set up SSH keys for your Github account.

Step 1: Generating SSH Key

This step can be also followed on Github's own documentation. The documentation itself tells you what to do but does not go into details as to why. I will explain it.

Firstly, you should create a new SSH key by doing below:

ssh-keygen -t ed25519 -C "your_email@example.com"

Change your email with your own email. The email you have used to register to Github is probably the best, otherwise you may have permission problems. Also, in this command, I use ed25519 as a public key cryptography algorithm. There are also other algorithms as well such as RSA, but since Github recommends to use it, we better use it as well.

When you run this command, you will get an interactive session, asking you:

Enter a file in which to save the key (/home/you/.ssh/id_ed25519):

This part is important and is up to your choice. If you leave it as is, it will automatically find the key and use it when you try to log in with your SSH to Github (which is every git push), which is convenient for maybe some of us.

However, having different keys for different hosts also makes sense. If you use (or will use) SSH on a different service, then creating and grouping with different names under ~/.ssh is a good idea. Using the same key for different services is similar to using the same key for your all houses. If the key gets somehow stolen, then all your stuff gets gone for sure. The catch is, if you rename your key, it will not be automatically discovered by SSH. So you will have to add your key to your agent each time you log in, which I will discuss later on.

If you have chosen the name, also you should be aware of the fact that you need to enter full path to the question. If you enter only the file name, then it gets created on the current working directory.

Step 2: Setting Up SSH Agent

We need to start ssh-agent and register our key in there so that whenever we git push, Git will be able to know to use SSH key.

In the Github's documentation above, it tells you to spawn ssh-agent process, yet the problem is that this process only lasts as long as your computer runs. When you restart, you need to start ssh-agent again.

However, in Linux, we have systemctl, a service manager that will spawn processes on boot or login. Luckily, our hero lightsing provides us a way to register ssh-agent as systemctl service so it can run on each log in automatically.

Firstly, you should know that SSH service is user-scoped. We have our keys under our home directory, so it is reasonable to register this service as user, which will run when we log in to our user (not when we boot up). In order to do that, we need to create the config directory for systemctl as seen below:

mkdir -p ~/.config/systemd/user/

Then, we will create ssh-agent.service file in there to spawn ssh-agent process when we log in. In this step, you can use whatever text editor you'd like, or create it with the default one like below:

touch ~/.config/systemd/user/ssh-agent.service
xdg-open ~/.config/systemd/user/ssh-agent.service

Paste below, save and close:

[Unit]
Description=SSH key agent

[Service]
Type=simple
Environment=SSH_AUTH_SOCK=%t/ssh-agent.socket
ExecStart=/usr/bin/ssh-agent -D -a $SSH_AUTH_SOCK

[Install]
WantedBy=default.target

This is basically a service file which describes to spawn ssh-agent and use socket file to communicate with other processes like Git in this case.

However, if you recognize in the service file, we also have SSH_AUTH_SOCK environment variable so we need to set it up so that ssh-agent can recognize it when it launches. In order to do that:

touch ~/.pam_environment
xdg-open ~/.pam_environment

And define the variable in that file, save and close:

SSH_AUTH_SOCK DEFAULT="${XDG_RUNTIME_DIR}/ssh-agent.socket"

Now we need to activate ssh-agent on boot is to enable it on systemctl and start it:

systemctl --user enable ssh-agent
systemctl --user start ssh-agent

--user flag tells this is a user-scoped service, which will spawn when your user logs in in your machine. enable is a subcommand telling "Start this service whenever I log in." and start is a subcommand telling "Start this service right away.".

You can check the status of your service by doing:

systemctl --user status ssh-agent

This should say "active (running)".

The next thing we should do is to tell ssh-agent to use our keys when we use Git. To do that, we need to add some line to ~/.ssh/config file. Luckily, we can do it in one line in terminal:

echo 'AddKeysToAgent  yes' >> ~/.ssh/config

Also, we better set the permissions for ~/.ssh/config file to tell that my user owns that file. To do that:

chmod 600 ~/.ssh/config

Step 3: Setting Up Github to Use SSH Key

Github's documentation also has this already covered. I will try to explain even further.

First, you should login to your Github account and head to settings page:

click your profile image and click settings

Then, you should go to "SSH and GPG Keys" page:

click SSH and GPG keys button on the left

Then you click "New SSH Key" button:

click new ssh key button

You should see a form as below:

new ssh key form

In this form, name can be whatever you'd like, and can be human-readable. Since my SSH key is github_homemachine, I will call it "Github Home Machine" in here.

In the Key input, you should paste the content of your public key you have created under ~/.shh directory. Remember, though, you should paste your public key, which ends with pub extension. Then hit save.

Step 4: Testing SSH Key

You can test if you are authenticated on github.com without actually pushing or pulling with Git. All you need to do is:

ssh git@github.com -v

Almost near the end, you should see "Hi erayerdin! You've successfully authenticated, but GitHub does not provide shell access.", which is a good sign.

Step 5: Using SSH Key

When you complete this setup, SSH URL will be the default in Github when you click "Code" button on any repository's home page.

it is the default as you can see

You should use this in your projects.

How to Use On a New Project

You should copy the SSH link provided by "Code" button on repository's home page. cd into your local repository and add it as such:

git remote add origin git@github.com:username/reponame.git

How to Change Existing Repository to SSH Key

First, you need to remove origin from your local repository. cd into there and do:

git remote remove origin

Then, just like a new project, add your SSH URL:

git remote add origin git@github.com:username/reponame.git

This is how you setup SSH with your Github account, which is a safer way and will make it easier to access a repository at the end of the day. Hope this post also helped you.


Troubleshooting

It was working, but now it says "Permission denied" when I try to push my code.

The problem is probably your key's name being not one of defaults. There are two solutions to this: (i) either rename your key to one of SSH defaults so it can be detected automatically (ii) or add your key to the agent each time you restart your computer (yes, the problem was you restarted your computer so your SSH agent got reset).

To apply the first solution, just go into ~/.ssh and rename your private and public key to id_ed25519 and id_25519.pub. This solution is convenient if you have only one SSH service and that is Github. Or you can use the same key multiple times but this arises security concerns.

To apply the second solution, just do ssh-add ~/.ssh/my_key_name each time you log in or restart your machine. With this solution, you can use different keys under different names with different services using SSH, which is more secure than the first solution but, as I've said, requires this extra step on each time you reboot your machine.