SSH everywhere

Notes published the
Notes updated the
6 - 7 minutes to read, 1474 words

Just a couple of notes on why I prefer ssh over other protocols, and how to configure it.

Avoid passwords, use keys

It makes it easier to automate jobs (like copying files in a script) and avoid typing passwords

First, generate the key with ssh-keygen.

Then, add to ~/.ssh/config something like

Host <name of remote>
    HostName <ip or name of machine>
    Port <port to connect>
    User <username>
    IdentityFile <path to generated key>
    #IdentitiesOnly yes

# otherwise ssh tries all keys
Host *
    IdentitiesOnly yes

At this point, copy the public key on the remote machine: ssh-copy-id -i ~/.ssh/mykey <name of remote>.

Notice that because of ~/.ssh/config, we do not need to specify the actual name of the remote (or its IP address), nor the username or port.

Once the public key has been successfully copied, change ~/.ssh/config to

Host <name of remote>
    HostName <ip or name of machine>
    Port <port to connect>
    User <username>
    IdentityFile <path to generated key>
    IdentitiesOnly yes

# otherwise ssh tries all keys
Host *
    IdentitiesOnly yes

In other words: uncomment the first IdentitiesOnly yes.

At last, you should be able to connect with ssh <name of remote> without typing the password. It is possible to use ssh -v <name of remote> to see that ssh tries to use the indicated key.

Use tmux or screen

If the connection is lost, one generally cannot reopen the previous console with the program running.

If all programs are executed from tmux or screen, this is a non-issue.

As using nested tmux or screen sessions is impractical, I would recommend adding at least a second modifier for the nested session.

Currently, I am using a function similar to

ssht () {
  ssh -t "$1" "tmux new-session -A -s new-session -A -s ssh_session\; set-option -g prefix2 C-a\; set -g mouse on"
}

This way, by typing ssht remote, when I’m connecting to remote, I’ll be presented to the already existent or newly created session ssh_session. Also tmux session on the remote will use both Ctrl+A and Ctrl+B as prefix modifier (unless configured otherwise). Thus when using nested tmux session (one on the remote, the other on the host) Ctrl+B is used for controlling the tmux session on the host, Ctrl+A for controlling the session on the remote.

An interesting alternative is

ssht () {
  ssh -t "$1" "tmux -S /tmp/tmux-k -f myconfig-file -u -2 new-session -A -s ssh_session\; set-option -g prefix2 C-a\; set -g mouse on"
}

as it would use by default a different tmux configuration file on a different socket. This might be useful when sharing a user account on a remote machine, and when the other user also uses tmux.

Note that if myconfig-file does not need to exist, tmux will display a warning but start successfully.

VirtualBox

VirtualBox makes it easy to open a connection between the host and guest operating system.

Under Settings, if the connection is NAT, add something similar to port forwarding

name| protocol | host ip   | host port | guest ip | guest port
ssh | tcp      | 127.0.0.1 | 2222      |          | 22

It is possible to also add those settings from the command line

vboxmanage modifyvm <name of vm> --natpf1 "ssh,tcp,127.0.0.1,2222,,22"

22 is the default port on the guest for ssh, while 2222 is an unused port on the host. A possible ~/.ssh/config on the host could then look like

Host vdebian
    HostName 127.0.0.1
    Port 2222
    User debian
    IdentityFile ~/.ssh/id_rsa_vdebian
    IdentitiesOnly yes

Starting the virtual machine and connecting (omit the first command if the VM is already running) is just vboxmanage startvm vdebian --type headless && ssh vdebian.

On can also verify programmatically if the machine is running, and starting it if not:

ssh-vdebian
#!/bin/sh

if ! vboxmanage list runningvms | grep vdebian >/dev/null; then :;
  vboxmanage startvm vdebian --type headless
fi
ssh vdebian "$@"

If you want to reach the virtual machine from other machines, then you should leave the host IP empty:

vboxmanage modifyvm <name of vm> --natpf1 "ssh,tcp,,2222,,22"

Windows

Windows uses by default other protocols for connecting to remote machines. ssh is only recently (since Windows 10) a first-class citizen, thus it is not as ubiquitous as SSH on other systems.

Native SSH

To install and configure SSH, follow the official documentation 🗄️:

# Query if OpenSSH is available, and which versions
Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'

# suppose output is similar top
#  Name  : OpenSSH.Client~~~~0.0.1.0
#  State : Installed
#  Name  : OpenSSH.Server~~~~0.0.1.0
#  State : NotPresent

# install client
Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0

# install server
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0

# Start the sshd services, and set to autostart
Get-Service ssh-agent | Set-Service -StartupType Automatic -PassThru | Start-Service
Get-Service sshd | Set-Service -StartupType Automatic -PassThru | Start-Service

Notice that ssh-copy-id won’t work for deploying keys, so it needs to be done manually

# note: because the default shell is cmd, use '\' instead of '/' for representing a path
ssh <win remote> mkdir 'C:\Users\username\.ssh';
scp <public key> <win remote>:'C:\Users\username\.ssh\authorized_keys';

Update (2024-02-07): If scp fails with subsystem request failed on channel 0, then using the option -O should fix the issue:

# note: because the default shell is cmd, use '\' instead of '/' for representing a path
scp -O <public key> <win remote>:'C:\Users\username\.ssh\authorized_keys';

The default shell is cmd, which is…​ let’s change the default SSH shell at least to PowerShell. I could not find any user-specific settings, only a global one.

ssh <win remote> reg add 'HKLM\SOFTWARE\OpenSSH' /v DefaultShell /t REG_SZ /d 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe'

In case your user is also an administrator, you might want to take a look at this (unfortunately rejected) issue. The Microsoft port of OpenSSH has some non-standard behavior, the TLDR is to comment following lines from C:/ProgramData/ssh/sshd_config out:

Match Group administrators
       AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys

cygwin

The main advantage compared to the integrated ssh is that Cygwin comes with a bash shell, and thus a more familiar environment (tmux and screen included).

Download the setup from the Cygwin website, and execute it as administrator. While installing Cygwin, remember to select the openssh and cygrunsrv packages.

Once the installation has finished, open a Cygwin terminal as administrator(!), and execute ssh-host-config. An interactive setup will ask some basic questions about how to configure the service.

Afterward, I needed to add a new firewall rule

New-NetFirewallRule -Name 'Cygwin-sshd' -DisplayName 'Cygwin-sshd' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22

Contrary to the integrated Windows ssh package, with Cygwin it is possible to deploy the key with ssh-copy-id:

ssh-copy-id -i <key> <win remote>

Android

The most profitable way to use ssh on Android is by using Termux (updated versions are available on F-Droid). For security reasons, connecting with a password is completely disabled. This is generally a good thing but also means that ssh-copy-id will not work for deploying the first public key. It needs to be added manually to ~/.ssh/authorized_keys.

In case you are unable to connect to your Android phone via SSH, you can view the logs either from Termux or adb with logcat -s 'sshd:*'..

Also, note that the default port is 8022 and not 22.

GNU/Linux distributions

If not available, install the SSH package provided by your distribution. Everything should work out of the box.

Graphical programs

Even if ssh is used for executing mainly command line applications, it can also be used for starting graphical programs.

On Windows, when connecting with Cygwin to a remote machine that uses X11 (many Linux distributions), before executing ssh, you should execute

startxwin;
export DISPLAY=:0.0;

while on GNU/Linux systems, export DISPLAY=:0.0; should be sufficient.

X11 forwarding can be used in ssh with the -X or -Y flags.

  • -X might be more secure (depending on your config), but might not work with some programs (unless changing some configuration)

  • -Y will work more often, but if you use it, be sure to trust the remote machine (it could log the key presses, take screenshots, and steal other data)

Those settings can also be set in .ssh/config, those are the options ForwardX11 and ForwardX11Trusted, and can be set to yes or no (with no being the default value, more information can be read from man ssh_config)

In case you are using Wayland, you might need to install XWayland or waypipe.

I did not find any information on how to start a graphical application on a Windows remote.


Do you want to share your opinion? Or is there an error, some parts that are not clear enough?

You can contact me anytime.