2017-04-30 - By Robert Elder
SSH is a network protocol for securely communicating between computers. Often when people refer to 'using SSH', they are referring to using an SSH client to connect to another computer's SSH server in order to remotely run commands on that computer. Any computer is capable of running both an SSH client and a server. For example, SSH would allow you to list files on a remote computer using a command like this:
ssh firstname.lastname@example.org "ls"
The above command will attempt to log in to a computer located at IP address 192.168.0.123 using the username 'robert'. Once it logs in, it will attempt to run the command "ls", and then exit from the SSH session. For this to work, you will either need to type the remote user's password, or have already set up another authentication method.
If you leave off the command at the end, you will now get an interactive session that lets you run as many commands as you want on the remove server until you type 'exit':
Copy Files Between Computers
You can also use the SSH protocol to copy files between computers in both directions with the 'scp' command:
scp /tmp/my_file email@example.com:/mnt/my_file # From your computer to 192.168.0.123 scp firstname.lastname@example.org:/mnt/my_file /tmp/my_file # From 192.168.0.123 to your computer
The first command above will copy a file located at '/tmp/my_file' on your local machine into the directory '/mnt/' on the remote server. The second command will do the same thing, but in the opposite direction.
Tunneling Other Services
This is where the utility of SSH really shines. You can use SSH to securely tunnel other services through an SSH connection. For example, you could host a git repo on another old computer in your house instead of using GitHub as your remote backup. You could then clone your repo using a command that looks something like this:
git clone my-server:~/my_git_repo.git
Finally, you can even tunnel traffic on a port by port basis. This lets you do things like make a remote service appear as though it is available locally, or the other way around. An example application of this would be to making a local home web server or database able to accept connections from anywhere by using a proxy server with a known IP address.
Why Use SSH?
There are older less secure alternatives to SSH such as telnet, and FTP. These older protocols are less secure because they send your login credentials over the network in a way that lets anyone read them. SSH is more secure because passwords are only sent after a secure channel has been established. SSH also supports public-key cryptography which has a number of security benefits over traditional password-based authentication.
SSH Public And Private Keys
SSH can work with password authentication, but the more modern way to use SSH makes use of public key cryptography instead of passwords. This is the part of using SSH that can be most confusing for beginners. It's actually not that complicated, and once you've done it a few times it will become natural.
Most people are used to the type of authentication where you specify a username and a password which gets sent to a server. The server then checks if your password matches and if it does you are allowed access. Public key cryptography is a bit different and works by requiring the user to create a 'key pair' which consists of:
- A public key that you can distribute to anyone.
- A private key that should be kept secret by the person who created it.
We won't go into the details of how public key cryptography works (because it requires a lot of math), but you just need to know these details:
- There is a complex mathematical relationship between the public and private key.
- A public key can be used to encrypt messages, but not decrypt them.
- A private key can decrypt messages encrypted with the public key.
On Linux, you can create your own key pair using the following command:
After you run this command, you'll get asked the following questions:
- Enter file in which to save the key (/home/Your_Home/.ssh/id_rsa):
- Enter passphrase (empty for no passphrase):
- Enter same passphrase again:
For the first question, you can specify any file name or even the full file path of where you want the public and private key to be stored. The next two questions that ask for a passphrase are allowing you to set up any passphrase of your choosing to protect the key whenever it is used. This is not mandatory, and you can just press enter if you don't want to use a passphrase every time you use the key.
After you finish the above steps, you'll end up with two files that default to being named 'id_rsa' (the private key), and 'id_rsa.pub' (the public key). Here is an example public key:
ssh-rsa AAAAB3Nz4C1yc2EAAAADAQABAAABAQDG3eIHvpiK2At0G+e3Y0vgo0o3aZHM8rJLXMMsGxC5kCorySKb2qtvsSVVm+3KverdalhhuJdLHf1PmVfd+kGgglAYyos21eKevM6Syub4k1r6qvBe/jqwigI1kwr3cL6mU4ifIpUN1eddrcnRVo3F2zdtBXML5Ty+PZ4Hd2/nQKApzohIHDph9wxUMgRA+cevPQpYslyLsP1Bef5ZOlY7GrFwqxNJV5li0tMG5GI+kQ7lUuySkv5Wjqbu/NqHb1OmH++jWJdAZ8BtNUuKjlD9r7lfvzIInX4CNs7KYY/USfL5ZuL/yOIGjjIiY0UMZJkJebiT/CLN/pXkw8ZlDikz robert@ubuntu
And here is its corresponding private key:
-----BEGIN RSA PRIVATE KEY----- MIIEogIBAAKCAQEAxt3iB76YitgLdBvnt2NL4KNKN2mRzPKyS1zDLBsQuZAqK8ki m9qrb7ElVZvtyr3q3WpYYbiXSx39T5lX3fpBoIJQGMqLNtXinrzOksrm+JNa+qrw Xv46sIoCNZMK93C+plOInyKVDdXnXa3J0VaNxds3bQVzC+U8vj2eB3dv50CgKc6I SBw6YfcMVDIEQPnHrz0KWLJci7D9QXn+WTpWOxqxcKsTSVeZYtLTBuRiPpEO5VLs kpL+Vo6m7vzKh29Tph/vo1iXQGfAbTVLio5Q/a+5X78yCJ1+AjbOymGP70ny+Wbi /8jiCo4yImNFDGSZCXm4k/wizf6V5MPGZQ4pMwIDAQABAoIBAGavS3cUQ0/uHnvl rNBUxWlI55mVOWPKLaYcT+sGTqyCdEQHp4cycjNKFS0PRsnZJt0NfHV5CyYOZi4j z+sevaRJpWgnrZqy9kFg3ImPm5PfAqtMeLGUNFnT6TAgrRj3bnoTyAfjo3Nxb/Y/ NmaResMfXo88sRsDU0ooJuFUGsQdAUmYSDJ0wKkuCytW05hYx/sQS8fElhKg3c0f CG/MQwBxOYWOelLBwE76D1RIWDAA9l4+Ol48lE+b5Ltv2dZFVKZht/oFNa/egvMw YTikekakwfkg5MTaDyldD/idet2ZRoLllyObLsEH8c6y9oXVhkZsu6aQ02KEWx0W iD0+IQECgYEA7RzbS3YbJ/Ds+zrf/Czy1j3B+h7x+w67kojpD2kxpS9BWB6957ST ozCGx8ysdJ9kwtGTOe+MTykG0JHyQhV5qv2zIols/2EA2HIQFXUZDNqbfr9Hvekc vRctd60H/jMAMR5DLHu0OorNoY0AA/HATAYQsovkDnlL8IRr3V17uAsCgYEA1rUf pVFcjgoLPon+Zp3rV+9rwrMo8hOZ6EE+lX9uWBtPaKQNXiqkls+xIA8R8sNqdrB2 CkvyFpMz7HVV5rBsMhIqe8ti8Ot5Z2xp7cErxc7XpMuJBTTvmJX5Sti9R7I14CUf 4oFHeSdWJiOS55a85sPXZYHjHA1YuycUNWCcBHkCgYA6yBeZaosq6LBnS94xTxdY g3DuR+PJoIphtm1Is8Rp9gAWD3D22y5qm2IecCAkvUsmfPwptbgr+7jDxhqvxVEn UcOyAS2zVeH2xrg0CZaPODaqQlNPwlWsju1nqM69dvlKM/1lLrmsdbKqpSDm2WzZ q/tBuCpuaBWqV7nB5CYCpwKBgHT2BAA1uzqxJAD0gT57ZnnntgdBO9vra5sG98XO vliGwBJb0+BpUHHLQE0biIZ7h6KSbCsdxgogNFfqb1oU30vDc5suZ36gd+ksOORI p8TA8d4W9lR8ysyPXlc0jJ/i59BryNvF2x6XnCl4lY1NIyh+pPbp88MTTjPdjPeq 4jLZAoGAVuHcLyNV0ZUxTmFZovXfxisc+zdJV3eSaVD7/c7v/sA35cQyojFZEi/l JDJYIq5T4Mo5NnKb+mms3n34ehH50i8BTGeJfnlg63MIrd5fE7jZeFYX2cvx6jD5 mvPGakcGN6ftUaCbEfJfDjf85WjKwiVi52oY1wb/91OrIpoP3io= -----END RSA PRIVATE KEY-----
Once you've created these two files, the general idea is that you can log into remote computers by distributing the public key to the server you want to log into. The private key will always be kept secret on your machine, and you'll need it every time you want to log into a remote computer.
If you're manually setting up SSH between two computer that you own, you'll need to add your public key into a file located at '~/.ssh/authorized_keys' on the remote machine that you want to log into. This file can contain multiple keys to allow access from multiple people.
Using SSH With GitHub
One common use case for SSH is to allow access to a GitHub repo. There is nothing special about how SSH keys work with GitHub compared with how SSH keys are used elsewhere. You can create a key pair in a method similar to that described above. Here is the official GitHub documentation of creating key pairs. Note that (as of writing this article) the official GitHub documentation at the link just provided also includes steps to add the key to your authentication agent with 'ssh-agent'. Using 'ssh-agent' isn't necessary in general, but it is one of multiple methods used to specify which key to use when you attempt to make an actual remote connection.
Once you finish creating the key pair, you can follow the GitHub official documentation on adding the key to your specific repo and account. Note that (as of writing this article), the documentation at this link says to use the program 'xclip', but this isn't necessary. You can simply locate the SSH public key file, open it in a text editor, and copy and paste it.
After you've created the key-pair and added the public key to your GitHub account, you should be able to run an SSH command similar to the following:
ssh -i <path to your private key file> email@example.com
ssh -i ~/.ssh/id_rsa firstname.lastname@example.org
If everything worked, you should see the following:
PTY allocation request failed on channel 0 Hi <Your Repo Name>! You've successfully authenticated, but GitHub does not provide shell access. Connection to github.com closed.
The above message is not an error and it indicates that you're able to authenticate with the server successfully, but it won't provide you with SSH shell access because GitHub only allows you to communicate with their servers though the git client. If you see this message instead:
Permission denied (publickey).
That means something didn't work properly. Check to make sure that the path to the private key is correct, and make sure you uploaded the public key correctly. Also make sure you're using the username 'git' otherwise the username will default to the current user on your local machine.
In order to clone or push to the repo, you should use the various git commands that take advantage of the fact that git can clone or push through and SSH tunnel.
Using SSH With AWS EC2 Instances
With Amazon's EC2 instances, when you are asked to create and download a key pair you get a copy of the private key that lets you access your server. Amazon keeps a copy of the public key file, and whenever you launch a new instance using that key pair, the EC2 instance will be provisioned to have the public key automatically added to the '~/.ssh/authorized_keys' file. This is why you're able to get access to the cloud server without having the physical access you would need to add the initial public key to '~/.ssh/authorized_keys'.
You can find a more detailed guide to SSH with AWS EC2 instances here.
SSH Config File
One of the most important productivity boosters when you're using SSH, is to set up a configuration that remembers all of your connection parameters in the file '~/.ssh/config'. If you don't already have one of these files, you can go ahead and create it. The point of this file is that instead of typing this out every time:
ssh email@example.com -p 1800 -i ~/.ssh/my_private_key
You can type this instead:
As long as your '~/.ssh/config' file contains this entry:
Host robert-server HostName 192.168.0.123 Port 1800 User robert IdentityFile ~/.ssh/my_private_key
This will work in various other places, such as with git or scp:
git clone robert-server:/mnt/my_repo.git scp /tmp/my_file robert-server:/tmp/new_file
One final note about the SSH config file: Some internet service providers will close idle connections, and this means that if you open an SSH connection, but don't type anything for a while, your ISP will timeout the connection, and then your terminal window will just become unresponsive when you try to use it again.
You can prevent this from happening, by adding the following to your SSH config file under each host's connection parameters:
Remote Administration With SSH
As mentioned previously, you can use SSH to log in to another computer remotely, provided that it is running an SSH server, and the proper steps have been taken to set up authentication for incoming users.
Normally when you log into a remote server, if you start a long-running task and then close the terminal, your SSH connection will be closed, but the remote command that you were running will be killed as well. Sometimes, this is not desirable, and you may wish to log in briefly, start a long-running task, then close the window or shut down your local computer. There are a couple ways to solve this problem. Let's look at a simple example:
while true; do sleep 1; done # This will cause the terminal to hang until the command is killed by the user
The first involves using the nohup command which can be done by appending a '&' symbol to the end of any shell command:
while true; do sleep 1; done & # This will run forever in the background
The above command will cause the infinite loop to run in the background until it finishes or it is explicitly killed using the 'kill' command. In the meantime you can run other commands or close the SSH connection without killing the remote background job.
Now when the users closes the SSH connection, the command will continue to run on the remote server.
Another method is to use a terminal multiplexer which is a special program that adds more features to your terminal session. A couple popular ones are GNU Screen and tmux. For whatever terminal multiplexer you decide to use, each will have various commands that allow you to create new terminal sessions, and if you launch a command in one of these it can run in the background. Next time you log into the server, you'll be able to start the terminal multiplexer program again and connect to any running terminal sessions you were using previously.
Port Forwarding With SSH
One of the really cool things you can do with SSH is capture information received on one of your local ports and send it through your encrypted SSH tunnel, then forward it somewhere else at the other end of the tunnel. Here an example:
ssh -L 4005:127.0.0.1:80 robert-server
When the above command is run, it will create a normal SSH connection into 'robert-server' using whatever parameters are in the '~/.ssh/config' file. In addition, any traffic that would otherwise be received on the local computer's port 4005 will instead be sent into the tunnel, then on the other end it will be forwarded to IP 127.0.0.1 on port 80. If 'robert-server' was a web-server, then browsing to 127.0.0.1 from the machine that issued the command above would then show whatever page was running on the web server as if it were running locally. You could do the same thing with a database sever which would allow you to connect to a database hosted on the server that might not be externally accessible.
Commonly Encountered Problems
In the next few sections, we'll review some of the most commonly encountered SSH related errors.
SSH: Connect to Host: Connection Refused
This error can be caused if you're trying to connect to a host that doesn't have an SSH server running on it. It may also be the case that you specified the wrong port number. SSH is usually hosted on port 22, but this can be changed to any port by the server administrator.
SSH: Connect to Host: No Route to Host
This type of error occurs if you are trying to connect to an IP or host name that does not exist. You may get this error if your internet or LAN connection is not working.
Permission Denied (Publickey).
You will see this error if you have been denied access by the SSH server when using public key authentication. Common causes of this message are not specifying the correct private key when attempting the connection, or not specifying one at all.
The Authenticity of Host 'HOSTNAME' Can't be Established
This will often happen the first time you connect to an SSH server because each time you attempt to connect to a server, your local client will look for a piece of saved information (usually located in '~/.ssh/known_hosts') that remembers the identify of machines that you trust. It is common to just type 'yes' for non-serious use cases here. If you were extremely concerned about security, you would call up the system administrator of the server you want to connect to and ask them what the 'RSA key fingerprint' of the target server was. You would then manually add this to the '~/.ssh/known_hosts' file and then you would not see this warning.
WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED
Sometimes you may see a message like this:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! Someone could be eavesdropping on you right now (man-in-the-middle attack)! It is also possible that a host key has just been changed. The fingerprint for the RSA key sent by the remote host is AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA. Please contact your system administrator. Add correct host key in /home/robert/.ssh/known_hosts to get rid of this message. Offending RSA key in /home/robert/.ssh/known_hosts:1 RSA host key for 192.168.0.1 has changed and you have requested strict checking. Host key verification failed.
This message is saying that the identity of the SSH server you're connecting to has changed. This might be a concern if someone else decided to set up an SSH server of their own and trick you (possibly by setting up their own DNS server) into logging into their SSH server instead of the one you think you're logging into.
There are a few cases where this message will be expected though: If you are using Amazon EC2, and you connect to a server at a given elastic IP, it will save the RSA key fingerprint of the server and associate it with that elastic IP address. If you later launch a different server and associate it with that same elastic IP, you will get this error, because the entry in the '~/.ssh/known_hosts' file is still associated with the old SSH server's RSA key fingerprint.
Another situation that can cause this, is if you upgrade the version of SSH running on the server. There are a few cases where it will generate a new RSA key fingerprint which will cause the same issue.
If you are confident that this is not a real security issue, you can use this command to remove the offending entry from your '~/.ssh/known_hosts' file:
ssh-keygen -R <Whatever the IP address in the message was>
WARNING: UNPROTECTED PRIVATE KEY FILE!
This occurs when your permissions are too open on your private key file. A solution is explained in guide to SSH with AWS EC2 instances here.
Debugging SSH connections
If you're attempting to start an SSH connection that isn't working, there is a handy debug flag you can add when you start SSH:
ssh -vvv <...arguments...>
Here is an example of some of the debug output you might see:
debug1: Reading configuration data /home/robert/.ssh/config debug1: /home/robert/.ssh/config line 12: Applying options for hostname debug1: Reading configuration data /etc/ssh/ssh_config debug1: /etc/ssh/ssh_config line 13: Applying options for host debug2: resolving "hostname.com" port 123 debug2: ssh_connect_direct: needpriv 0 debug1: Connecting to hostname.com [192.168.0.1] port 123. debug1: Connection established. ... debug1: kex: client->server cipher: firstname.lastname@example.org MAC: <implicit> compression: none debug3: send packet: type 30 ...
Some of the output will be hard to read, but at least you'll get some keywords that you can search for.
In this article, we've covered some of the broad use cases for SSH, and how to take advantage of them on a Linux platform. We've covered how SSH can be used with GitHub, AWS EC2, or even between computers you have at home. There are also a number of ways you can make use of port forwarding to make remote services appear as though they are being hosted locally. A few common sources of error have also been discussed. This really only scratches the surface of what you can do with SSH, but hopefully this is enough to get you started asking the right questions.