SSH Configuration

It is recommended to utilize ssh-config to configure SSH. This offers an easy and simple way to connect to servers via SSH without the need to write long SSH commands. The configs can also be checked into a VCS and synchronized via a private git repo across multiple devices. Furthermore, those configs are utilized by other applications such as scp and rsync.

Warning

Remember to never commit key material. Put the path to the keys in a .gitignore file. Use other means to transfer the keys across multiple devices (i.e. by transferring them with scp/rsync, using a password manager capable of storing files securely, or using a physical storage device like a USB stick).

In order to start using it, one has to create a file called config in ~/.ssh. It is sensible to cluster host definitions into their own sub config (i.e. in ~/.ssh/config.d/...) and load those from within ~/.ssh/config. This allows to compartmentalize domain-specific configurations.

~/.ssh/config:

Main SSh configuration file (~/.ssh/config)
# vi:syn=sshconfig

# Include all configs from sub dir
Include config.d/*.conf

# Suppress errors when connecting to a port on the local host
# Useful when one is forwarding to different machines from the same port
Match host localhost
    StrictHostKeyChecking no
    UserKnownHostsFile /dev/null

Documentation about the config format is available at ssh.com.

It is advisable to create domain-specific SSH key pairs and use those instead of password login, as this compartmentalizes the keys and don’t implicate unrelated domains in the case of a loss/compromise of the private key. It also makes it easier to deprecate key pairs by simply deleting the private key. The example configs assume the keys to be stored in ~/.ssh/keys.

In order to create and distribute such key pairs, ssh.com provides a good guide. In short, the procedure could look something like this (note that the variables enclosed in <> will have to be changed):

# Make sure the directory already exists
[[ -d ~/.ssh/keys ]] || mkdir ~/.ssh/keys

# Create a key pair
# optionally set a password to encrypt the private key
ssh-keygen -f ~/.ssh/keys/<key_name> -t ed25519

# Copy the corresponding public key to the server's ~/.ssh/authorized_keys
ssh-copy-id -i ~/.ssh/keys/<key_name> <user>@<host>

# Test to verify
ssh -i ~/.ssh/keys/<key_name> <user>@<host>

Note

If the ssh-config already specifies the host (including the key pair), then the ssh-copy-id command can be shortened to ssh-copy-id <host_abbr>.


Tips

Maintain via Git

It can be very useful to maintain and share the configurations via Git. For this, initialize the ~/.ssh folder as a git repository, put the path to the keys (i.e. keys) into a .gitignore and add and commit it. Then add the configurations as explained in this page (domain-specific configuration files etc.) and upload them to the remote (preferably in a private repository). Once on a different machine, just clone the repository into ~/.ssh.

Warning

Remember to never commit key material! Put the path to the keys in a .gitignore file. Use other means to transfer the keys across multiple devices (i.e. by transferring them with scp/rsync or using a password manager capable of storing files securely).

If there are changes to the configurations in the future, just commit and push them, then pull to all additional affected client devices.

Make Use of Abbreviations

Using the Hostname config, one can fix the actual hostname/IP behind a Host directive for easy access: Instead of ssh dgx.cloudlab.zhaw.ch, just use ssh dgx instead.

Take advantage of SFTP/SSHFS

Certain file managers support adding network resources with a connection string. For example, Nautilus (Linux, default file manager for the GNOME desktop and therefore available in all current Ubuntu desktop installations) allows SFTP shares to be accessed with a URI like: sftp://dgx. This makes browsing image data on remote file systems easier.

For Mac users, they have to install OSX Fuse and SSHFS in order to make use of this feature.

SOCKS5 Proxy

Using the DynamicForward capability, one can create a SOCKS5 proxy to forward traffic to the remote and send off the packets from there. This allows for connecting to the internet from the remote or access applications local to the remote only (i.e. a Jupyter-Lab or Label-Studio instance) without having to specify a local port forwarding every time. To do this, it is recommended to specify the client side SOCKS5 proxy port on the commandline (using -D <port>) instead of the ssh-config, to prevent port allocation problems when opening multiple SSH sessions at the same time. Then the user’s browser can be configured to use the SOCKS5 proxy to connect to the internet.

It is recommended to use a selective proxy plugin for the browser (i.e. FoxyProxy) which can enable the proxy connection based on URL patterns, so only a select number of requests get channelled through the proxy.

Show Divergent Options in Config

To see how the configurations impact a specific host configuration, it is helpful to compare it to the defaults with diff:

Use diff to see the configuration for a specific host.
# Showing the configs for a specific host
diff -y --suppress-common-lines <(ssh -Go IdentityFile=~/.ssh/id_rsa none) <(ssh -G idgx)
# user embe                     | user re
# hostname dgx.cloudlab.zhaw.ch | hostname none
# identityfile ~/.ssh/keys/embe | identityfile ~/.ssh/id_rsa
# proxyjump apu                 <

# Comparing the configs of two hosts
diff -y --suppress-common-lines <(ssh -G dgx) <(ssh -G dgxa100)
# hostname dgx.cloudlab.zhaw.ch | hostname dgx-a100.cloudlab.zhaw.ch


# Set functions in the shell for easier usability
function sshconfig() {
    first="$1"
    second="$2"
    arg=""
    if [ $# -eq 1 ]; then
        second="none"
        arg="-o IdentityFile=~/.ssh/id_rsa"
    fi
    diff -y --suppress-common-lines <(ssh -G "$first") <(ssh -G $arg "$second")
}

# Can be used for one or two hosts:
sshconfig idgx
sshconfig dgx dgxa100

Example config

Variable parts enclosed in <>

Important

These configs assumes that the public key(s) have already been saved into the servers’ ~/.ssh/authorized_keys, as explained here

Configuration file for ZHAW (~/.ssh/config.d/zhaw.config)
# vi:syn=sshconfig

# All APU servers
# Accessible from the Internet
# Cannot be used as a jump proxy for intranet hosts anymore
Match host apu,apu2
    User ubuntu
    IdentityFile ~/.ssh/keys/<shortname>

    Host apu
        Hostname <ip>
    Host apu2
        Hostname <ip>

# i-prefix indicates proxy jump from internet for work from home access
Match host dublin,dgx,idgx,dgx1,idgx1,dgx2,idgx2,dgx3,idgx3,dgxa100,idgxa100
    User <shortname>
    IdentityFile ~/.ssh/keys/<shortname>

    # Accessible only via intranet
    Host dublin
        Hostname dublin.zhaw.ch

    # All DGX servers (accessible only via intranet)
    Host dgx
        Hostname dgx.cloudlab.zhaw.ch

    Host dgx2
        Hostname dgx2.cloudlab.zhaw.ch

    Host dgx3
        Hostname dgx3.cloudlab.zhaw.ch

    Host dgxa100
        Hostname dgx-a100.cloudlab.zhaw.ch
Configuration file for Git remotes (~/.ssh/config.d/git.config)
# vi:syn=sshconfig

Host github.com
    User <username>
    IdentityFile ~/.ssh/keys/github
    # Github's servers don't all have the same host keys
    StrictHostKeyChecking no
    UserKnownHostsFile /dev/null

# For git remotes of the staff account
# When cloning repositories with the staff account, use this host name
Host <shortname>.github.zhaw.ch
    Hostname github.zhaw.ch
    User <shortname>
    IdentityFile ~/.ssh/keys/<shortname>

# For git remotes of the student account
# When cloning repositories with the student account, use this host name
Host <stud_shortname>.github.zhaw.ch
    Hostname github.zhaw.ch
    User <stud_shortname>
    IdentityFile ~/.ssh/keys/<stud_shortname>