This introduction will cover the basics of SSH config, explaining how it works and how you can use it to simplify your SSH connections. SSH config is a file that allows you to store settings for your SSH connections, providing a flexible system for defining and reusing connection parameters, and significantly simplifying server management.
The config file
The ssh program on a host receives its configuration from either the command line or from configuration files ~/.ssh/config
and /etc/ssh/ssh_config
1.
Command-line options take precedence over configuration files. The user-specific configuration file ~/.ssh/config
is used next. Finally, the global /etc/ssh/ssh_config
file is used. The first obtained value for each configuration parameter will be used.
The ssh_config client configuration file has the following format. Both the global /etc/ssh/ssh_config and per-user ~/ssh/config have the same format.
- Empty lines and lines starting with ‘#’ are comments.
- Each line begins with a keyword, followed by argument(s).
- Configuration options may be separated by whitespace or optional whitespace and exactly one =.
- Arguments may be enclosed in double quotes (“) in order to specify arguments that contain spaces.
Example:
Host github.com
AddKeysToAgent yes
IdentityFile ~/.ssh/id_ed25519
Host rackham rackham1 rackham2 rackham3 rackham4
User rackham_username
Hostname %h.uppmax.uu.se
IdentityFile ~/.ssh/id_ed25519
ForwardAgent yes
# ForwardX11 yes
Host nac
User nac_username
Hostname nac-login.nbis.se
ForwardAgent yes
IdentityFile ~/.ssh/id_ed25519
Host dardel
User dardel_username
Hostname dardel.pdc.kth.se
ForwardAgent yes
IdentityFile ~/.ssh/id_ed25519
# XAuthLocation added by XQuartz (https://www.xquartz.org)
Host *
XAuthLocation /opt/X11/bin/xauth
In your config you’ll find blocks that start with Host <label>
. When the Hostname
is not supplied, the label provides the default hostname. AddKeysToAgent yes
tells your SSH client to automatically add the private key supplied by IdentityFile
.
Common configuration options
The identity file
This supplies the path to the SSH key file that should be used for authenticating when connecting to a host. There are several types of keys, and the example below uses an EdDSA key which is the default 2. Github has a very nice guide to generating keys 3.
IdentityFile ~/.ssh/id_ed25519
User and Hostname
If your user and hostname is not the same as your local user you can also supply your username when connecting to the host
Host nac
User nac_username
Hostname nac-login.nbis.se
X11 Forwarding
X11 forwarding (ssh -X
) is a technique that allows you to run graphical applications on a remote server but display them on your local machine. This can however be slow. An alternative is port forwarding (see below).
ForwardX11 yes
It’s not recommended to enable this by default as it might start the X Server locally each time you log in, which could be a significant delay
Agent forwarding
Agent forwarding (ssh -A
) in SSH allows you to use your local SSH keys to authenticate to further servers that the server you’ve connected to needs to access, without having to copy your private keys to that intermediate server.
ForwardAgent yes
Proxy Jump
You can use SSH to automatically connect to one host via another. This can be on demand with -J <hostname>
, or it can be added permanently to a host using ProxyJump
.
ssh dardel -J rackham
Host dardel
User dardel_username
Hostname dardel.pdc.kth.se
ForwardAgent yes
ProxyJump rackham
IdentityFile ~/.ssh/id_ed25519
Multiple proxies can be chained in this way.
SSH tunneling
Port forwarding
Port forwarding, also known as SSH tunneling, is a technique that allows you to redirect network traffic through an SSH connection. For example, you can access remote databases, connect to Jupyter/Posit notebooks/servers, and forward web applications locally.
In this example, we’ll:
- Connect from our Laptop to Dardel.
- Get an allocation.
- Connect again from our Laptop to Dardel, but this time specify the port.
- Connect from Dardel to our allocation.
- Start Marimo in headless mode
- Open the connection on our browser.
Request an interactive allocation
First connect to dardel
ssh dardel
Then request an allocation
# Request 4 cpus because of the low memory per core allocation.
salloc -c 4 -t 1:00:00 -A naiss2024-22-1346 -p shared
Normally you would then
ssh $SLURM_NODELIST
and start with your command-line operations, but not just yet.
SLURM_NODELIST
contains the list of nodes you just reserved. If you’ve reserved more than one node, then echo $SLURM_NODELIST
followed by ssh <NODE_ID>
of the node you want to ssh into.
Enable SSH tunneling
Decide the port you’re going to use to tunnel. We’ll use 8080, which is a standard in webserver testing, as we’ll be using Marimo which starts a web-service and runs in the browser.
In a new terminal on your local machine:
ssh -L 8080:<node_id>:8080 dardel
ssh <node_id>
Where -L enables port forwarding, the first 8080
is the local port, and the <node_id>:8080
is the host:hostport
. If you only want to forward from the login node for example, then you might use -L 8080:localhost:8080
instead.
It’s easy to accidentally run commands in the wrong location. Use your prompt to identify where you are, e.g. username@login1
means you’re still on the login node, and username@node_id
means you’re on the allocated worker node.
Run Marimo using Pixi
Once you’ve ssh’ed in, you’ll be put in your home directory. Let’s make an environment using Pixi.
curl -fsSL https://pixi.sh/install.sh | sh
Make a directory to start a Marimo server, and start one.
mkdir marimo_test
cd marimo_test
pixi init -c conda-forge -c bioconda
pixi add marimo
pixi shell
marimo edit --headless --host 0.0.0.0 --port 8080
We use --headless
so marimo doesn’t try to open a browser on the worker node. The --host
listens on all ports, and the --port
is set to 8080.
When Marimo starts up, it will display a URL to copy-and-paste into your local browser.
$ marimo edit --headless --host 0.0.0.0 --port 8080
Create or edit notebooks in your browser 📝
➜ URL: http://0.0.0.0:8080?access_token=kXxlpkz81MXl9fWF65VFqA
➜ Network: http://10.253.5.60:8080?access_token=kXxlpkz81MXl9fWF65VFqA
If you get an error message such as,
channel 4: open failed: connect failed: No route to host
channel 5: open failed: connect failed: No route to host
channel 4: open failed: connect failed: No route to host
channel 5: open failed: connect failed: No route to host
there may already be a service running on the port you chose, e.g. 8080. In this case, select another port and try again, for example, changing ports to 8081.
Quick play with Marimo
Create a new notebook, and then in the first cell add.
import marimo as mo
Add a new Python cell, and then add the following quick mermaid diagram.
= '''
diagram graph LR
A --> B --> C
A --> C
'''
mo.mermaid(diagram)
and run it.
Cleaning up
- Use
Ctrl + C
to shutdown the marimo webserver. - Use
exit
to exit the Pixi shell. - Use
exit
to exit the worker allocation. - Use
exit
to exit the login node.
Permanently configure
To configure services permanently, one can add the LocalForward
to their config.
Host nac
User nac_username
Hostname nac-login.nbis.se
# Blobtools service on port 8001 on login node
LocalForward 8001 localhost:8001