Linux / FreeBSD keyboard.

How to Use SSH

Use SSH to Safely Connect, Run Commands, and Transfer Files

Maybe you want to:
 •  Make interactive connections to servers.
 •  Run commands on servers.
 •  Upload and download files.

You should use SSH. It provides secure and far more capable alternatives to TELNET and FTP.

Operating systems you run on person systems, desktops and laptops, include SSH clients.

Until recently, you had to add a package to Windows. Most people added PuTTY, a free package first released in 1999 and maintained all along by a lone programmer. Microsoft finally included the free OpenSSH client and server packages in Windows 10.

How to Enable SSH on Windows 10

Jump ahead to using SSH

Click on the start button, and select Settings.

Then select Apps & Features, and then Optional features.

Windows 10 Settings: Apps and Features

If necessary, select the option to add features, and select the OpenSSH Client.

Make sure that OpenSSH Client is installed and enabled.

Windows 10 Settings: Optional features

Log off the system, then log back in. Then start and command prompt.

Start a command prompt or a PowerShell window, and type ssh.

If you're told that ssh is not recognized as a command or operable program, we need to make sure that your environment's PATH variable contains what it needs.

Click the Start button, then type env and select Edit the system environment variables. The below window will appear. Select Environment Variables.

Windows 10 Settings: Editing environment variables

Click Path in the bottom pane of the new window, and then Edit.

Windows 10 Settings: Changing the system PATH variable

Below is what I saw. The last entry should have worked, as the OpenSSH client binaries are stored in C:\Windows\System32\Openssh\. I suppose the %SYSTEMROOT% variable is not set as expected. Oh well, I'll add a new entry with the literal path.

I clicked on the last entry, then on New, and them added a new entry with that literal path:

Log off, log on, and it works.

Windows 10 Settings: Changing the system PATH variable

Starting to use SSH

You can run the ssh command with no parameters to get a concise reminder of all options. However, it's a lot of information, and you will probably need to read the manual page to make sense of all that.

Let's start with something simple!

Running one command through SSH

I'm going to assume that you're using a desktop or laptop named workstation, your login name is myname, and you have an account on remote system server.

If you run the command uname -snm you are asking for the nodename (or hostname), kernel name, and architecture.

myname@workstation $ uname --help
Usage: uname [OPTION]...
Print certain system information.  With no OPTION, same as -s.

  -a, --all                print all information, in the following order,
                             except omit -p and -i if unknown:
  -s, --kernel-name        print the kernel name
  -n, --nodename           print the network node hostname
  -r, --kernel-release     print the kernel release
  -v, --kernel-version     print the kernel version
  -m, --machine            print the machine hardware name
  -p, --processor          print the processor type (non-portable)
  -i, --hardware-platform  print the hardware platform (non-portable)
  -o, --operating-system   print the operating system
      --help     display this help and exit
      --version  output version information and exit

myname@workstation $ uname -snm
Linux workstation x86_64

I will use ssh to run that command on the remote server. Notice that the operating system, hostname, and architecture are all different. The command ran on a different platform, within a different operating system.

myname@workstation $ ssh server uname -snm
FreeBSD server amd64

I don't show it here, but there will be a request for your password on that server. You have to type it without seeing what you're typing. Further along, I'll show you how to set up keys for effortless and more security authentication.

up keys

You can follow along here, trying the commands as I show them to you and entering your remote password. Or skip ahead to see how to set up keys and then return to here.

Maybe I want to run two commands in a row. That's easy, but I have to be careful with shell syntax. Here's the first thing you probably think of trying: See how this goes wrong when I try to simply run the same command twice in a row on the remote server with a single command here.

myname@workstation $ ssh server uname -snm ; uname -snm
FreeBSD server amd64
Linux workstation x86_64

What happened? The shell on my workstation saw this as two commands for it to run — first run ssh and then run uname locally. I have to tell the shell to treat the command sequence as a single string by wrapping it in single quotes:

myname@workstation $ ssh server 'uname -snm ; uname -snm'
FreeBSD server amd64
FreeBSD server amd64

That worked, but we want to do something more useful than running the same command twice:

myname@workstation $ ssh server 'uname -snm ; uptime ; whoami'
FreeBSD server amd64
 2:38AM  up 3 days, 1 min, 0 users, load averages: 0.41, 0.48, 0.45

In the examples so far, I just specified the server's name. That means that I have to have an account with the same name as what I'm using locally. If my remote account has a different name, I specify it as part of the destination.

myname@workstation $ whoami ; hostname
myname@workstation $ ssh othername@server 'whoami ; hostname'

An Interactive Session

If I don't specify any command at all, I am connected to an interactive session. My keyboard and display are connected through an encrypted SSH tunnel to an interactive shell running on the other end.

myname@workstation $ ssh othername@server
myname@server $ whoami
myname@server $ hostname
myname@server $ exit
myname@workstation $ hostname

Uploading and Downloading Files

Use the scp command, part of the same suite. In a way, it works just like the cp command. The difference is that the source and destination can start with a remote hostname, optionally with a different username.

If you only specify the remote hostname, it refers to your home directory on that system. Probably /home/myname but potentially anywhere.

If you specify the remote hostname and a relative path, then the remote location is relative to your home directory there.

If you specify the remote hostname and an absolute path, then that's the absolute location over there.

So, let's say I want to list all my local files named *.html, copy them to the other machine, and verify that it worked, I could do the following. Note that I need to wrap the remote command within single quotes, so the wild card is interpreted over there, not by the local shell. And apparently oldfile.html was already there.

myname@workstation $ ls *.html
file1.html	file2.html	file3.html
myname@workstation $ scp *.html server:
myname@workstation $ ssh server 'ls *.html'
file1.html	file2.html	file3.html	oldfile.html

I could create a new directory on the server, which will be a subdirectory of my home directory. Then I can copy the files into there.

myname@workstation $ ssh server mkdir newfiles
myname@workstation $ scp *.html server:newfiles

Or, I can use absolute paths:

myname@workstation $ scp *.html server:/tmp
myname@workstation $ scp 'server:/tmp/*.txt' .

Watch out. It's easy to leave off the ":", and scp is happy to act entirely locally. This creates a new local file named server. The symptom is that you don't see the report on how much was transferred and how long it took.

myname@workstation $ scp newfile server:
newfile                             100%  184KB 459.9KB/s   00:00
myname@workstation $ ls server
/bin/ls: cannot access 'server': No such file or directory
myname@workstation $ scp newfile server
myname@workstation $ ls server

Setting Up Keys

Typing passwords becomes tedious. Let's set up a new cryptographic identity.

CAUTION: The following will obliterate an existing SSH identity.

The key generation program supports a key type that is no longer used by the SSH service. So we will only make useful keys.

The last command specifies a 4096-bit RSA key pair, we might as well be cautious. The two elliptic curve key pairs are of fixed sizes.

myname@workstation $ ssh-keygen -t ecdsa
myname@workstation $ ssh-keygen -t ed25519
myname@workstation $ ssh-keygen -t rsa -b 4096

For each, press <Enter> to accept the default location.

For security, enter a passphrase. For your sanity, use the same passphrase for each one.

You now have three key pairs in the directory ~/.ssh. The private keys are in files named id_ecdsa, id_ed25519, and id_rsa. The corresponding public keys are in files with .pub appended to their names.

I want to authorize the public keys. This means that a remote user should be authenticated as me if they, or really their SSH software, can prove that they have access to the correponding private keys. I set this up locally with this command:

myname@workstation $ cat ~/.ssh/*.pub > ~/.ssh/authorized_keys

The permissions should be mode 700 on the .ssh directory, 600 for the private key files, and 644 at the most liberal for the public key files. The ssh-keygen file should have done the right thing.

Now I can copy my SSH key collection to all the remote servers I want to use. The scp options are -p to preserve mode (and modification timestamp) and -r for recursive copy.

myname@workstation $ for s in server1 server2 server3 server4
> do
>   scp -pr .ssh ${s}:
> done

If I'm on a graphical desktop that has the SSH key agent set up correctly, like Mint Linux, I'll log off and then back on again. The ssh-add -l command should show me that an SSH key agent has access to my keys, so I can run ssh and scp commands without being prompted for a login password, or a key passphrase.

If I'm on a text console, I can start a key agent and give it access to my private keys with the following.

myname@workstation $ ssh-agent $SHELL
myname@workstation $ ssh-add

Tunneling Graphics through SSH

Jump back to the command introduction

Let's say I want to run a graphical application, executing the program on the remote system, interacting with it here. I will add the -f option to fork off that process once I'm authenticated, so I get my local interactive prompt back again. And the -X option to tunnel what happens through an encrypted SSH tunnel plugged into the X display. And, just in case, the -C option to ask for compression of everything moving through the SSH tunnel. It might compress by default, depending on how SSH is set up on both systems, but there's no harm in asking.

myname@workstation $ ssh -fXC server thunderbird

Using SSH Within a Script

Here's a script I can use to automatically find and upload everything that needs updating on my server, after I have been modifying the copy of my site on my local system.

myname@workstation $ cat ~/bin/update-web

for FILE in $( find /var/www/html -type f -newer ~/.TIMESTAMP-web |
			egrep -v '\.swp$|\.directory$' |
			sort )
	scp -p $FILE$FILE
touch ~/.TIMESTAMP-web

It finds all the web site files newer than ~/.TIMESTAMP-web, ignoring any vim swap files and any annoying .directory files created by a graphical file browser. Then it copies each into place on the server with permissions and timestamps preserved. Finally, it updates the timestamp file so it only does what's needed the next time.

Of course I need to have key-based authentication set up, otherwise I must type my password over and over.

And, my real script also figures out whether it's running on my desktop or laptop and also copies the update to the other one, unless it's on my laptop and not at home, in which case it doesn't update the timestamp file.