Using X-windows (X11) and secure shell (SSH) to connect to a remote UNIX server (host)

Using a new Bash shell to manage your identity keys

X-windows (X11) and SSH software let you run certain types of software on a remote UNIX server (host) while displaying and controlling the software's graphical user interface (GUI) on your local desktop system. In a cluster computing environment, X11 and SSH are typically used to connect to the cluster's head node as illustrated below.
cluster computing environment

Linux desktop use

Standard Linux distributions come with OpenSSH (e.g. OpenSSH_4.3p2 ), a bash shell (e.g., GNU bash, version 3.2.25), and X11 server (e.g., X.Org version: 1.4.2 ). Linux users should set up their home directory to enable remote connection services. To set up for SSH, use the UNIX ssh key generation command. This will set up up your hidden SSH directory populated with your private/public key files. Watch for any output messages contining the hidden directory name. For example, the message:

Created directory '/home/train7/.ssh'
gives the name of your SSH hidden directory. You will need to know this directory name to set up secure connections to remote hosts using SSH. It is normally the .ssh directory in your home directory.

The SSH agent and agent forwarding are important parts of OpenSSH, which lets you use your private/public key pair to increase productivity. It is possible that your Linux desktop is already setup with an SSH agent. To test your agent, type the command ssh-add -l. If you get a message like The agent has no identities, then you have an SSH agent running. See the tutorial Linux Desktop configuration using SSH agent for step by step instuctions to use your desktop agent.

If however, you get a message like Could not open a connection to your authentication agent, then you do not have an agent to connect to. This tutorial will address this situation and give step-by-step instructions to use bash aliases and SSH configuration files to create an environment for working on your local laptop with trusted connections to remote hosts.

Note on typography: In the following steps, the example sessions have prompts in bold. Several of the prompts are for secret passphrases or passwords. These will not be displayed as you type (not echoed), but do not leave them empty or type the hint, which is in red -- some secret --.

This setup includes adding shortcuts (aliases) to your .bashrc file and putting files in your hidden SSH directory.

Setup your hidden SSH directory with public/private keys

This step is only needed if you have never used SSH from this account. You may already have a hidden SSH directory. If you do not have the directory, or you do not know the name then continue with step one.

Start with a window open in your home directory.

  1. Type the bash command ssh-keygen -C "laptop Aug25"
    [jdoe@centos ~]$ ssh-keygen -C "laptop Aug25"
    Generating public/private rsa key pair.
    Enter file in which to save the key (/home/jdoe/.ssh/id_rsa): 
    Created directory '/home/jdoe/.ssh'.
    Enter passphrase (empty for no passphrase): -- new secret --
    Enter same passphrase again: -- repeat secret --
    Your identification has been saved in /home/jdoe/.ssh/id_rsa.
    Your public key has been saved in /home/jdoe/.ssh/id_rsa.pub.
    The key fingerprint is:
    8f:ce:9a:19:fd:3e:05:ff:2e:90:1a:2e:37:d3:b4:63 laptop Aug25
    [jdoe@centos ~]$
    

    Some installations may require you to specify a key type or length. The options -b 2048 -t rsa are a good choice (for now).

    Take note of your hidden SSH directory /home/jdoe/.ssh. It is normally the .ssh directory in your home directory.

Set up Bash public/private keys

These steps will add a new identity for use in your bash shell and give you an alias to use to start a secure bash shell. With slight modifications, these instructions could be used for csh/tcsh or ksh. You will create an identity (public/private key pair) just for Bash.

Start with a window open in your home directory.

  1. Type the UNIX command ssh-keygen -f .bash_identity.
  2. [jdoe@centos ~]$ ssh-keygen  -f .bash_identity
    Generating public/private rsa key pair.
    Enter passphrase (empty for no passphrase): -- new secret --
    Enter same passphrase again:  -- repeat secret --
    Your identification has been saved in .bash_identity.
    Your public key has been saved in .bash_identity.pub.
    The key fingerprint is:
    41:ab:0b:c3:c7:6b:23:1f:5b:d0:31:78:11:d7:2e:cf jdoe@centos.css.udel.edu
    [jdoe@centos ~]$
    

    Note: If you get command not found, then the OpenSSH tools are not in your path. Contact you system administrator.

  3. Use your favorite editor to add these lines to your .bashrc file and your .bash_profile file.
  4. alias sbash="env PSS_='laptop sbash' ssh-agent bash"
    if [ "$PSS_" ]; then
      idFile=~/.bash_identity
      ssh-add "$idFile" || exit;
      PS1="$PSS_\$ " &&  unset PSS_;
    fi
    

Configure SSH for a specific remote host connection

Start with a new window open in your home directory. If you are continuing from the last section, this will start a new shell using your modified .bashrc file. This means you will have the sbash alias available to you.

  1. Type the bash command (alias) sbash to start a bash shell using the Bash identity file created in the last section. You will be prompted for your passphrase.
  2. [jdoe@centos ~]$ sbash
    Enter passphrase for /home/jdoe/.bash_identity: 
    Identity added: /home/jdoe/.bash_identity (/home/jdoe/.bash_identity)
    laptop sbash$
    
  3. Assume that you have an account on a remote host, for example, account train7 on host centos2.udel.edu. You trust this host, i.e., you know the group that has root (super user) access. Use your favorite editor to add these lines to a new file .ssh/config file. (assuming .ssh is your hidden ssh directory.)
  4. Host train
    
    User train7
    Hostname centos2.udel.edu
    ForwardX11 yes
    ForwardX11Trusted yes
    ForwardAgent yes
    

    The name after the Host key word is the SSH service name. You may name it anything you want, e.g., train for a training service and compute for a computing service.

  5. Assuming you used train as the service name in the config file, connect to this service with the command ssh train. If this is the first time you have connected to this host, you will asked if you want to continue (answer "yes"). Then you will be asked for you password on that account.
  6. laptop sbash$ ssh train
    The authenticity of host 'centos2.udel.edu (127.0.0.1)' can't be established.
    RSA key fingerprint is d2:f9:58:79:08:d6:18:22:3f:23:ac:4b:f4:a7:b9:3b.
    Are you sure you want to continue connecting (yes/no)? yes
    Warning: Permanently added 'centos2.udel.edu' (RSA) to the list of known hosts.
    train7@centos2.udel.edu's password: -- known secret --
    Last login: Tue Aug 23 10:04:05 2011 from roaming-215-36.nss.udel.edu
    [train7@centos2 ~]$
    

    If this account does not have an SSH directory, continue at the bash prompt with the command ssh-keygen. This repeats the key generation step of the last section on the remote host. This time, accept the default comment but still put a passphrase on this identity.

    [train7@centos2 ~]$ ssh-keygen
    Generating public/private rsa key pair.
    Enter file in which to save the key (/home/train7/.ssh/id_rsa): 
    Created directory '/home/train7/.ssh'.
    Enter passphrase (empty for no passphrase): -- new secret --
    Enter same passphrase again: -- repeat secret --
    Your identification has been saved in /home/train7/.ssh/id_rsa.
    Your public key has been saved in /home/train7/.ssh/id_rsa.pub.
    The key fingerprint is:
    d4:4d:09:b4:7f:1c:ea:50:d2:d8:5b:7e:ec:fe:10:01 train7@centos2.udel.edu
    [train7@centos2 ~]$
    

    Assuming your SSH directory is .ssh, continue at the bash prompt with the two commands ssh-add -L >> .ssh/authorized_keys and exit. The first command should have no output, and the second will exit your remote shell and close the connection to the centos2.udel.edu host.

    [train7@centos2 ~]$ ssh-add -L >> .ssh/authorized_keys
    [train7@centos2 ~]$ exit
    logout
    
    Connection to centos2.udel.edu closed.
    
  7. You may repeat steps two and three to configure a trusted connection for other SSH services, e. g., add a compute service. Or you may return later to configure them. When you are done with all configurations, type exit at the laptop sbash$ prompt.
  8. laptop sbash$ exit
    exit
    [jdoe@centos ~]$
    

Using the sbash alias with X11

Start a secure session by typing the sbash command and give your passphrase when prompted. Any commands typed in this shell will use an agent to manage your Bash identity, and you will not need a password to connect to the remote hosts which you have configured with the above instructions.

  1. Start a secure bash session:
  2. Type the

    sbash
    
    command and you should get the sbash$ prompt after you enter your passphrase.

    Note: If you do not supply the correct passphrase, you will not get the sbash$ prompt. Test this by typing CTRL-C at the passphrase prompt. You must type sbash again to continue with this test.

  3. Test the configuration of X11:
  4. At the sbash prompt, use the command ssh -f train to fork na X11 application on the train service. For example, to display a green xclock type:

    ssh -f train xclock -bg green
    
  5. Connect using X11:
  6. Log on to the compute service using the X11 terminal emulator with:

    ssh -f compute xterm

  7. Finish your secure session
  8. Close all the X11 windows by clicking the X in the title bar (the red bullet on a Mac) and then stop your secure session with the command:

    exit
    

Here is an example session testing xclock on your train service and xterm on your compute service.

[jdoe@centos ~]$ sbash
Enter passphrase for /home/jdoe/.bash_identity: 
Identity added: /home/jdoe/.bash_identity (/home/jdoe/.bash_identity)
laptop sbash$ ssh -f train xclock -bg green
laptop sbash$ ssh -f compute xterm
laptop sbash$ exit
exit
[jdoe@centos ~]$

Helpful Tips

Start a new window and type the sbash command to start a shell with the sbash$ prompt after you supply your bash identity passphrase. Here is a list of commands you can type at the sbash prompt:

  1. Log in to a remote host (No password or passphrase is required.):
  2. laptop sbash$ ssh train
    Last login: Fri Sep  2 16:26:21 2011 from centos.css.udel.edu
    [train7@centos2 ~]$
    

    The session on the remote host continues in the same window.

  3. Start a new window that is logged on to a remote host:
  4. laptop sbash$ xterm -e ssh train &
    [2] 29879
    laptop sbash$ 
    

    The Last login: line and the prompt on the remote host will appear in a new window. The xterm will be running on your local machine with process id 29879. You may use any X11 terminal emulator which works on your local deskop. For example, use gnome-terminal -x in place of xterm -e.

  5. Log in to a remote host in a new window:
  6. laptop sbash$ ssh -f train xterm
    laptop sbash$ 
    

    The Last login: line and the prompt on the remote host will appear in a new window. The xterm will be running on the remote machine. You may use any X11 terminal emulator that is installed on the remote host. For example, use gnome-terminal in place of xterm.

  7. Reattach a screen session on a remote host in a new window:
  8. laptop sbash$ ssh -f train xterm -e screen -R
    laptop sbash$ 
    

    If you do not have a detached screen session on the remote host, this will open a new window with just your remote host prompt. If you have a detached session, it will reattach the old session.

  9. Cut and paste between windows:
  10. To copy and paste from one xterm to another xterm with a three-button mouse:

    • Start a selection with the left mouse button.
    • Adjust with the right mouse button.
    • Paste with the middle mouse button.

    For example, to copy several words from one window and paste them to another, left-double-click on the first word, right-double-click on the last word, and then middle-click in the destination window.

    Note: The right mouse may bring up a popup menu, in which case you will not be able to adjust the selection.

  11. Execute a remote command:
  12. laptop sbash$ ssh compute 'ps -fu $USER'
         UID   PID  PPID   C    STIME TTY         TIME CMD
      joedoe 29496 29494   0 08:55:42 pts/195     0:00 -bash
      joedoe  8199  8198   0 12:57:04 ?           0:00 xclock
      joedoe  9191  9190   0 13:17:03 ?           0:00 ps -fu joedoe
    

    This will display all processes you have running on the compute service. Enclose the entire remote command in single quotes so shell characters, such as, $, *, ~ and | are interpreted on the remote host. In this case you want $USER to expanded to your username on the remote host. If you want a single quote contained in the remote command use the three characters '"'.

  13. Execute a remote command in a loop:
  14. laptop sbash$ for h in train compute; do
    > echo $h && ssh $h uptime
    > done
    train
     16:23:57 up 145 days,  5:11,  2 users,  load average: 0.00, 0.00, 0.00
    compute
      4:34pm  up 173 day(s),  1:35,  30 users,  load average: 1.10, 1.12, 1.12
    sbash$ 
    

    This will echo the SSH services train and compute and then output from the uptime command on the host.

  15. Add a bash script to your path:
  16. Loops and other flow-of-control bash features are best done in a script.

    Write a bash script for more complicated tasks, which may involve executing commands on your remote hosts. To add the script to your path, copy it to a directory in your path and make it executable. Scripts that are started from an interactive shell will have all exported functions that are defined in the .bashrc file.

    Install this script in your ~/bin/rmkey file and make it executable:

    #!/bin/bash 
    #
    #  usage: rmkey [file] 
    #    file - private key file to be removed, along with the corresponding
    #         public key file, and all the keys stored in the authorized key
    #         files on the remote hosts explicitly contained in the config file.
    configFile="$HOME/.ssh/config"
    
    ## Get $idFile and $idFile.pub as the private/public key files.
    idFile=${1:-$HOME/.ssh/id_rsa}
    
    
    ## Do we need to remove the public key from the remote hosts?
    if [ -r "$idFile.pub" -a -r "$configFile" ]; then
      save_key='^$'
      ## Extract the public key (without options or comment)
      save_key=$(sed -n 's/.*\(ssh-[a-z]* [A-Za-z0-9+/]*=*\).*/\1/p' "$idFile.pub")
      ## For each host, edit the authorized keys file
      for host in $(awk '/^Host [^*?]*$/ {print $2}' "$configFile"); do
        printf "e .ssh/authorized_keys\ng#$save_key#d\nw\n" | ssh $host 'ed -s'
      done
      
    ## remove the files
    rm "$idFile" "$idFile.pub"
    
    

    Note: The old key is extracted from the public key file using sed, a stream editor. Any public key options will run before the ssh- and the comment is after the optional key padding characters (=) .

  17. Define a bash function:
  18. Use Bash functions to enhance your enviroment. Bash functions are short scripts, which can be defined and exported in your .bashrc file. To add a function to extract hosts from your configuation file, add these lines to your .bashrc file

    function config-hosts {
      awk '/^Host [^*?]*$/ {print $2}' ~/.ssh/config
    }
    export -f config-hosts
    

    Note: This function will use awk to extract the service names from your configuration file. These are the second fields of lines beginning with "Host". This command will extract only services which are not patterns, which contain * or ? characters.

    Now the last example could be done using the config-hosts function.
    sbash$ for h in $(config-hosts); do
    > echo $h && ssh $h uptime
    > done
    train
     16:23:57 up 145 days,  5:11,  2 users,  load average: 0.00, 0.00, 0.00
    compute
      4:34pm  up 173 day(s),  1:35,  30 users,  load average: 1.10, 1.12, 1.12
    sbash$ 
    
  19. Add a bash script to your path:
  20. Write a bash script for more complicated tasks, which may involve executing commands on your remote hosts. To add the script to your path, copy it to a directory in your path and make it executable. Scripts that are started from an interactive shell will have all exported functions that are defined in the .bashrc file.

    Install this script in your ~/bin/bash-keygen file and make it executable.

    #!/bin/bash 
    #
    #  Usage: bash-keygen 
    #    Generates new private/public key pair for use with the sbash alias
    #    The old keys are removed, and the new key is added on 
    #    all hosts in the config file and
    
    ##### $idFile/$idFile.pub are the private/public key files.
    idFile=$HOME/.bash_identity
    idComment="${PSS-sbash} $(date +%b-%d)"
    
    ##### Extract the public key (without options or comment)
    old_key='_na_'
    if [ -r "$idFile.pub" ]; then
      old_key=$(sed 's/.*\(ssh-[^=]*\)=.*/\1/' "$idFile.pub")
    fi
    
    ##### Generate new keys (overwriting old)
    ssh-keygen -b 2048 -t rsa -f "$idFile" -C "$idComment" || exit 1
    
    ##### For each host edit the authorized keys file
    for h in $(config-hosts); do ssh $h 'ed -s' <<end_edscript
    e .ssh/authorized_keys
    g#$old_key#d
    \$a
    $(cat "$idFile.pub")
    .
    w
    end_edscript
    done
    

    Note: The old key is extracted from the public key file using sed, a stream editor. Any public key options will run before the ssh- and the comment is after the = key terminating character.

    Note: The .ssh/authorized_keys file is modified on all remote hosts using ed, a scriptable command-line editor. The multiple-line ed script has the following commands:

    1. Load the file to be edited with the e command.
    2. Delete all lines containing the old key with the d command.
    3. Add the newly generated key after the last line with the a command.
    4. Write out the changes with the w command.

    Here is an example session which starts an sbash shell and checks the fingerprint of the old key before generating the new key. The authorized keys file is updated on all the hosts with no passwords since the old key is still handled by the agent.

    [jdoe@centos ~]$ sbash
    Enter passphrase for /home/jdoe/.bash_identity: -- known secret --
    Identity added: /home/jdoe/.bash_identity (/home/jdoe/.bash_identity)
    sbash$ ssh-add -l
    2048 44:6e:d3:56:3d:4e:36:6b:a3:84:15:20:97:9d:57:22 /home/jdoe/.bash_identity (RSA)
    sbash$ bash-keygen
    Generating public/private rsa key pair.
    /home/jdoe/.bash_identity already exists.
    Overwrite (y/n)? y
    Enter passphrase (empty for no passphrase): -- new secret --
    Enter same passphrase again: -- repeat secret --
    Your identification has been saved in /home/jdoe/.bash_identity.
    Your public key has been saved in /home/jdoe/.bash_identity.pub.
    The key fingerprint is:
    5e:c6:00:20:f2:fd:7e:03:a7:ce:f9:a4:8a:0e:9d:97 sbash Sep-16
    sbash$ exit
    exit
    [jdoe@centos ~]$
    

Troubleshooting

Permissions on directories and files

All files and directories must not be writable by either group or others. This includes the directories containing the files. In addition, all private key files must not be readable by anybody but you. In this tutorial we use ssh-keygen to create the key files and the hidden SSH directory, if needed. If you do not get any error message from ssh-keygen, then all the permissions are correct, and you should not change them by explicitly using the chmod command.

There are two files in the SSH directory that need to be created without using SSH commands - the configuration file .ssh/config and the authorized keys file on the remote host .ssh/authorized_keys. These must not be writable by the group or others. We have assumed in this tutorial that your account is set up to not extend write access to anybody but yourself. We have used the default umask of 022, which masks out write access for both group and others.

If the permission mods are incorrect, you will get warnings or error messages, and things may not work properly. Sometimes, the problem is not obvious from the error message.

  1. Error when creating keys:
  2. The ssh-keygen command may give an error such as

    Saving key failed: ~/.bash_identity
    
    if it can not set things properly. This is usually caused by incorrect permission mods on the containing directory (home directory, in this case). To fix this type of error, type:
    chmod u+w,go-w ~
    

  3. Error when using keys:
  4. You will get a warning and your private key is ignored.

    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    @         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    Permissions 0640 for '/Users/jdoe/.ssh/id_rsa' are too open.
    It is recommended that your private key files are NOT accessible by others.
    This private key will be ignored.
    
    You could fix this by fixing the premission mods on the file in question. To be safe, you should remove the key file and generate a new key with the ssh-keygen program. This may find more errors which you should fix. Once the new keys are generated, you will need to send the public keys to to all your remote hosts. again.



  5. Error when connecting to an SSH service:
  6. The configuration file and the configation file must not be writeable. In the following session the .ssh directory and the .ssh/config file are both group writable.

    wifi-roaming-128-4-203-31:~ jdoe$ ssh train
    Bad owner or permissions on /Users/jdoe/.ssh/config
    wifi-roaming-128-4-203-31:~ jdoe$ chmod g-w .ssh/config
    wifi-roaming-128-4-203-31:~ jdoe$ ssh train
    ssh: Could not resolve hostname centos.css.udel.edu: nodename nor servname provided, or not known
    wifi-roaming-128-4-203-31:~ jdoe$ chmod g-w .ssh
    wifi-roaming-128-4-203-31:~ jdoe$ssh train
    Warning: No xauth data; using fake authentication data for X11 forwarding.
    Last login: Thu Sep  8 11:50:23 2011 from wifi-roaming-128-4-203-31.nss.udel.edu
    [train7@centos ~]$
    

    After seeing the bad permissions on the configuration file, you should check to make sure nobody in your group changed your file, and before closing the directory you should make sure you don't see any new files, renamed files or removed files.

  7. Bad owner or permissions on the authorized keys file:
  8. I .ssh/authorized_keys on the remote server does not have the correct permissions, it will not be used, and you will be ask for the account password. There is no error message.

Encrypted home directory

If your home directory on the remote host is encrypted, then isshd service cannot read your authorized keys, and you will have to supply the account password. There is a solution, which involves the system administrator. The system administrator can configure the sshda service to look for authorized keys in a location outside of the user's home directory. See SSH/OpenSSH/Keys - Community Ubuntu Documentaion.

Export a public key to a pre-configured remote host

Step three in the above section "Configure SSH for a specific remote host connection" consists of connecting to the new host and executing three commands: ssh-keygen, ssh-add -L, and exit. The key generation command is not necessary if your home directory on the remote host is already configured for OpenSSH.

Most Linux servers will be using OpenSSH, but there are other versions of SSH that use the same public/private key standards but store the public keys in a different format. To allow the use of the keys on different versions, the ssy-keygen -e command will export the public key in a standard transfer format.