Setting up SSH Keys

See also the GitHub SSH Key Guide.

Generate your key:

ssh-keygen -t rsa -b 4096 -C "<your email address>"

You can leave the password field blank, but I recommend setting one (you can save it in your OS Keychain anyway).

This will generate two files. The public key is at ~/.ssh/id_rsa.pub. This is what you share with other people. You should never give anyone else your private key, which is ~/.ssh/id_rsa.

ed25519 keys

These are a new type of key that is shorter but harder to crack that the older rsa format. Older machine might not understand them though, so you might want to generate an rsa key as a backup.

Copying these keys is much nicer though, so worth using them where possible.

ssh-keygen -t ed25519 -C "<your email address>"

Your public key will look like this, don't worry, it's still secure enough.

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDsiCLI9WWTrSd4MDUpSM35f44HPKYaV96e8WGyjgDzQ gib@fahn.co

Add your key to the ssh keychain

Run ssh-add with the path to the private key you created, then enter your password.

ssh-add ~/.ssh/id_rsa

Add your public key to GitHub

Copy the public key to your clipboard, and then paste it into any site

macOS:

cat ~/.ssh/id_rsa.pub | pbcopy
open https://github.com/settings/keys

Linux:

cat ~/.ssh/id_rsa.pub | xclip -selection clipboard
xdg-open https://github.com/settings/keys

Now paste in the key that the previous command copied to your keyboard.

Repeat for any other site that needs your ssh keys (like Gitlab, GitHub Enterprise, or Bitbucket).

Put your public key on remote machines

If you want to ssh into machines, it's much easier to authenticate via key rather than via password. To set up your account on that machine for remote access do:

# ssh-copy-id takes the same arguments as ssh, including `-i ~/.ssh/other_key`
# in case you chose a different name.
# <machine> can be a hostname (foo.bar.com) or an IP address.
ssh-copy-id <remoteuser>@<machine>

This just appends your id_rsa.pub to the ~/.ssh/authorized_keys file on the remote machine. You can paste it in manually if you want.

Troubleshooting

If you run ssh <remoteuser>@<machine>, you should now connect without having to type your password (if <remoteuser> equals the output of uname, then you can omit the <remoteuser>@ part).

If it doesn't work:

Make sure permissions are set directly on both local and remote machines. Try running the following on both machines:

# Only you should be able to write to your home directory.
chmod go-w ~
# No-one else should be able to write to anything in ~/.ssh.
chmod -R go-w ~/.ssh
# No-one else should be able to read your private keys.
chmod go-r ~/.ssh/*
# Optionally allow others to see your public key and config:
chmod go+r ~/.ssh/*.pub ~/.ssh/config

If you get a password prompt, try manually specifying the path to the private key with ssh -i ~/.ssh/id_rsa <remoteuser>@<machine>. Make sure you're using the right remote username (and that you can ping <machine>).

If you don't get a password prompt you probably can't access the machine.

Setting up an ssh config

So now you can be lazy and not type your password. But machine names are long and annoying, and often you have a different username, or a different private key, and typing it all is a drag.

Say you have a group of machines you frequently ssh into called foo1-bar.xxx.com, foo2-bar.xxx.com etc. You might have a different username on those machines too. Instead of typing ssh remoteuser@foo1-bar.xxx.com every time, you can just add this to your ssh config:

Host 1 2 3 4 5 6 7 8 9
    # %h gets replaced with the Host string above.
    HostName foo%h-bar.xxx.com
    User remoteuser

And now you just type ssh 1, ssh 2 etc.

Now you find that you keep getting pesky messages every time you connect to a new machine asking if you want to add the RSA key to the trusted list, and you have to type yes.

Or you find that some machines close the connection if you don't type anything for a couple of minutes.

Or you want to set a default key for all machines that isn't ~/.ssh/id_rsa.

You just add this to the beginning of your ssh config:

# Defaults for all hosts
Host *
# Consider getting a shiny modern key.
   IdentityFile ~/.ssh/id_ed25519
# Backup key for older machines (ssh tries each one).
   IdentityFile ~/.ssh/id_rsa
# Automatically accepts the "do you accept this RSA key" prompt.
   StrictHostKeyChecking=no
# Don't close the connection if you are idle for a while.
   ServerAliveInterval 120
# Use a different default user for sshing.
  User gib
# Tells ssh to ignore the following option if ssh is too old to understand it.
   IgnoreUnknown AddKeysToAgent
# Automatically run the ssh-add command if it's not already in the ssh keyring.
   AddKeysToAgent yes

These generic rules can be overwritten by more specific ones you define below.

The next level

I have alias s=ssh in my dotfiles.

Check out the ssh and ssh-config man pages for more useful stuff.