If you connect to remote computers over the Internet, it is a pretty good chance you use some form of SSH or secure shell. On Linux or Unix you’ll use the ssh
command. Same goes for Linux-like environments on Windows like Cygwin or WSL. For native Windows, you might be using Putty. In its simplest form, ssh
is just a terminal program that talks to a server using an encrypted connection. We think it is very hard to eavesdrop on anyone communicating with a remote computer via ssh
.
There are several tricks for using ssh
— some are pretty straightforward and some are things you might not think of as being in the domain of a terminal program. You probably know that ssh
can copy files securely, and there are easy and hard ways to set up logging in with no password.
However, you can also mount a remote filesystem via ssh
(actually, there are several ways to do that). You can use ssh
to securely browse the web in your favorite browser, or even use it to tunnel specific traffic by port or even use it as a makeshift VPN. In fact, there’s so much ground to cover that this won’t be the last Linux Fu to talk about ssh
. But enough setup, let’s get to the tricks.
A Few Good Options
We’ll assume you know the basics: scp
and sftp
for file copies and ssh-copy-id
for setting up password-less login. (If not, you have ten minutes to do a quick web search.) But one of the things ssh
is great at is manipulating the network. Keep in mind, though, that the server has to have certain options set to do some of the most interesting things, so if you don’t control the ssh
server, some of these tricks might not work for you.
There are a lot of options to remember on the ssh
command line, but luckily you don’t have to. You don’t even have to remember your hostname or user name. In the ~/.ssh/config file
you can create an alias. For example, suppose you want to connect to your home server:
Host homeserver HostName mih0me.dyndns.org Port 1234 User TheAl IdentityFile ~/.ssh/home_id ForwardX11 yes Compression yes TCPKeepAlive yes
You can have as many aliases as you like. Just keep repeating the Host line and then follow it with options. You can also add more than one alias to a single Host statement. The subsequent options will then apply to any of the aliases. Now to connect just issues ssh homeserver
and you are in with all the right options.
Of course, if you are using Putty, your options will mainly be in the host profile and on the ssh
panel of the options screen. You might not get as many options, but there are some you can try.
Be Persistent
One really nice set of options to include set the master control file. For example:
ControlMaster auto ControlPath ~/.ssh/master-%r@%h:%p
This lets multiple sessions to the same host share a single TCP socket. Because it takes a some time to set up a secure socket, this can be speed things up if you keep several sessions going between two hosts. You can set it for all hosts by using the Host *
line in the config file. You can use that for any global options you might have.
On the other hand, if you shove a lot of data over multiple connections, turning on ControlMaster
might not be a great idea. You can add -S none
to override the global setting.
One other thing to note is that your first ssh
session might appear to hang if you try to exit it before all the other connections are closed. Some people deliberately run a hidden ssh
session on login to a host they often connect to which avoids that problem. However, a better way is to set ControlPersist
to yes. That will cause the original session to go to the background indefinitely. If you want a little grace period you can set ControlPersist
to a number like 180. That would cause the background session to end if there are no connections for three minutes.
Another downside to this approach is that you tend to get orphaned master files. In rc.local
I have the following line:
/bin/rm /home/*/.ssh/master-* || true >/dev/null
With Putty, you can click the “Share SSH connections if possible” button in the SSH options panel.
Configuration
There are quite a few configuration options you can use in the config file. For example, BatchMode
lets you tell ssh
the connection is made for unattended use so don’t bother prompting the user for passwords or anything else. That’s not to say it will just let you in, of course. It just means it will fail if you don’t have things set up to login without a password.
There are some other interesting items. For example, you can run a local or remote command on connection. You can also send an environment variable to the remote host or even just set one. For example, suppose you want to always keep your LS_COLORS the same on your workstation and the server, but you frequently change them and don’t want to use the same profiles. You could add this to the host’s config file entry:
SendEnv LS_COLORS
The server has to be configured to accept this, of course. Putty can handle setting an environment variable from the Data tab in its setup.
On the network side, you can specify TCPKeepAlive
to yes if you want the server and client to test their connection during idle periods. This is a two-edged sword. If the connection is idle, you won’t get disconnected. But if the network drops at the right moment for a brief period you might get disconnected where you wouldn’t have if you had stuck with the default. There’s even a way to open a layer 3 or layer 2 tunnel between the machines — a topic for a future Linux Fu.
By Your Command
Don’t forget that ssh
can execute a command and send its output to you. As a practical example, I occasionally reflash my 3D printer firmware. The printer is connected to a Raspberry Pi, but I do the firmware build on my main machine. For a long time, I copied my file to the Pi (using scp
) and then logged into the Pi to run a script I wrote called flash
. The script disables the Reptier server software, flashes the Atmel chip on the printer control board, and then turns the server back on.
Here’s the script that runs on my main computer. Note the ssh
commands. One turns off the server. One scp
command copies the new firmware over. Then another ssh
does the flash and renables the server. There are many other ways to do this, of course. But don’t forget that ssh
can run a remote command and then return.
#!/bin/bash if [ -z "$1" ] then echo Usage: flash hexfile [remote_name] echo If omitted, remote_name will have date attached exit 1 fi ONAME="$2" EXTRA=$(date "+%Y%m%d.%H%M") if [ -z "$2" ] then ONAME="$1-$EXTRA.hex" fi IP=192.168.1.110 echo Stop Server ssh -l pi $IP "sudo systemctl stop RepetierServer" echo Copy... scp "$1" "pi@$IP:a8fw/$ONAME" echo Flashing... ssh pi@$IP "cd a8fw; ./flash $ONAME" echo Restart ssh "pi@$IP" "sudo systemctl start RepetierServer" echo Done exit 0
If you want a more hacker-friendly example, consider using the same idea to run Wireshark locally and analyze a remote packet capture:
ssh root@someserver 'tcpdump -c 1000 -nn -w - not port 22' | wireshark -k -i -
You can do the same trick with tshark,
if you prefer.
Speed Test
What to know how fast your ssh
connection is? Make sure you have pv
installed and try this:
yes | pv | ssh remote_host "cat >/dev/null"
Pretty cool!
If you have good speeds — or even if you don’t — you can try mounting a remote file system using sshfs
. This is a FUSE filesystem — that is, a filesystem that lives as a regular user program, not part of the kernel. With nothing on the remote side but the ssh
server and standard tools, you can make any host you can connect to look like a local file system.
But Wait…
There’s a lot more you can do with ssh
, and I’ll cover more shortly. But for now, hopefully you found at least one ssh
trick you can use that was, if not new, at least a reminder for you.
I use ssh to tunnel vnc sessions across the internet. It makes vnc “secure” and allows me to run a desktop session remotely.
this and SSH -X have been the two best features of SSH I have found for doing office admin (it and business) at home.
+1. both have been life savers, impressed colleagues, and allowed me to penetrate a lot of firewalls…err…I mean, do my job :)
ssh -Y is usually more reliable depending on your situation.
I do that as well a lot. But for some reason vncviewer fails to work when I allow it to use an existing master connection.
Another “hack” I do is to use the socks proxy built into ssh to connect to web servers on my companies intranet from home. There is a Firefox plugin that allows to toggle the proxy settings with a single click.
Oh, and by the way, master connections are very handy if bitbake fails because your ssh git server starts rate limiting connection attempts.
What is missing is a way to create a master connection to a server without creating a shell session.
-f Requests ssh to go to background just before command execution. This is useful if ssh is going to ask for passwords or passphrases, but the user wants it in the background. This implies -n. The recommended way to start
X11 programs at a remote site is with something like ssh -f host xterm.
-N Do not execute a remote command. This is useful for just forwarding ports.
Also worth mentioning: ssh chaining. If you need to ssh to a gateway host in order to ssh into another machine, you may be tempted to run:
ssh external ssh internal
This has the drawback of running the second ssh client on the remote machine, where your private keys, known_hosts and other nice things may not be available (also, the stream is decrypted on the intermediate machine, which may be a trust issue in some cases). You can tunnel the connection instead, like this (in .ssh/config):
Host internal
ProxyCommand ssh external nc internal 22
(one-liner equivalent: ssh internal -o ProxyCommand=’ssh external nc internal 22′)
Running ‘ssh internal’ on your client machine will execute ‘ssh external nc internal 22’ internally, instead of opening a TCP connection. This requires a netcat client on the remote machine. PuTTY has a way of doing this using the ssh-builtin port forwarding.
The chain can be extended as long as common sense would allow.
ssh -J external internal
OpenSSH 7.3 was released on 2016-08-01.
New Features
* ssh(1): Add a ProxyJump option and corresponding -J command-line flag to allow simplified indirection through a one or more SSH bastions or “jump hosts”.
You are welcome.
It’s easier to use the ProxyJump option to chain through hosts, there’s less configuration and you don’t need to depend on nc being present on the middle system.
(also available as “ssh -J jumphost destination”)
Yes ProxyJump is cool. You can even do
ssh -J nearby,nextlayer,evendeeper destination
where `nearby`, `nextlayer`, `evendeeper` and `destination` are all four SSH hosts.
If you don’t have ProxyJump available in your version of ssh, you can also use ‘ssh -W %h:%p external’ as the proxy command.
That’s exactly what ProxyJump does behind the scenes
That ‘yes’ trick is a terrible way to measure network speed. Typically, it’ll measure the ability of one of the two hosts to encrypt/decrypt data.
Good point. I was following directions for installing modified firmwares to minimal linux hardware, it crawled it rather than ran it, and it’s only connection to the outside world is the USB hole I’ve got physical control of, and I’m thinking “Why the merry hell are we doing this with ssh????” because it took like half an hour to write half a megabyte, and I knew it was the crypto slowing it down.
In this case it should benchmark to whatever is bottlenecking data transfer via ssh, not network bandwidth(which may be exactly what you want)?Just make sure compression is disabled ( no -C flag) or use cat /dev/urandom instead of yes
I would also be better to use /dev/zero (instead of /dev/urandom) because that uses even less cpu. Using `dd` (instead of `cat`) is another think worth trying because it allows the buffer size to be changed. If they’re too small they will also limit measured speed.
One of the books in the HB bundle is SSH:The definitive guide.
https://www.humblebundle.com/books/oreilly-classics-oreilly-books
https://www.youtube.com/watch?v=jhUkGIsKvn0
:o)
The site moved to a different host not terribly long ago, and some of the old plugins and fancy tricks didn’t move over. That’s likely what’s going on here.
Worse! Same host “upgraded” on us and we lost features.
In line 12 of the flash script did you mean:
ONAME=”$1-$EXTRA.hex”
Yes. Not sure what happened there.
You still need FUSE support compiled into the kernel for sshfs to function. Most binary distributions will have that already checked, but if you custom roll your own kernel, well, then, you need to double check.
Macs may have a problem.
https://www.theregister.co.uk/2019/12/16/fuse_macos_closed_source/
Here’s something I’ve found useful. If you want to give someone access to a service via an ssh tunnel, you can do that via a user that can’t log in.
Say you have a service on port 6666 of your device fubar, which is only accessible locally [i.e. there’s no internet-facing open port other than ssh]
You can access that by doing ssh -L 6666:127.0.0.1:6666 me@fubar
Then localhost:6666 will give you access to port 6666 on fubar.
If you want to give someone access to the service on port 6666 without giving them login access, create a no-login account like this:
sudo useradd -mb /home -s /usr/sbin/nologin myservice
You should see something similar to this in /etc/passwd:
myservice:x:1002:1002::/home/myservice:/usr/sbin/nologin
Add the public key of the user you want to access myservice to /home/myservice/.ssh/authorized_keys
Now they will be able to access ssh -L 6666:127.0.0.1:6666 myservice@fubar without getting shell access.
If you want to give someone else access, just add their public key to /home/myservice/.ssh/authorized_keys.
What happens if they run “ssh -L 6666:127.0.0.1:6666 myservice@fubar /bin/bash” ?
Setting the user’s shell to `/usr/sbin/nologin` will actually prevent them from logging in at all (by password or key). A better way would be to add `restrict,port-forwarding` (or if you want to limit where forwarding is permitted `restrict,permitopen=”127.0.0.1:6666″`) at the start of the line in authorized_keys (and remove the user’s password with `passwd -d myservice`).
Another way to do keep-alive, is to simply set up `screen` to paint a status bar down the bottom of your SSH session.
In
.screenrc
(or/etc/screenrc
) I have the following:caption always "%{yb} %D %Y-%02m-%02d %0c %H %{k}|%{g} %l %{k}|%{w} %-w%{+u}%n %t%{-u}%+w"
defutf8 on
bind ^a stuff ^a
The first line is the key one for keep-alive purposes, it puts a banner down the bottom with the current date/time, the hostname and what screen windows are open (and which one is active).
The second line turns on UTF-8 mode (a must with modern console applications, IS08859 is for the dinosaurs).
The third line is useful if you have nested screen sessions, or using applications like minicom that need ^a to mean something, you can type ^a by pressing it twice.
It’s truly a shame that all of these Hackaday posts are just for the Linux kernel and aren’t applicable to any other OS at all.
Totally not applicable to any other OS, not:
Solaris,
HP-UX,
AIX,
OpenVMS,
FreeBSD,
NetBSD,
OpenBSD,
HaikuOS,
Gnu Hurd,
SCO UNIX, a bit dead now, replaced by OpenServer (which was based on FreeBSD),
Yep, only Linux and no other OS at all, such a shame.
And not Plan 9.
Psst, don‘t feed the troll. The article titled „Linux foo…“ even mentioned Windows alternatives 😉
Also in your listing of UNIXoid OSses you forgot the most widely used desktop Unix system… macOS
Old ?, Most have a new release every few years. And there is a lot of money in knowing how to raise Lazarus. It is a bit like old school DBA’s or grey beard COBOL programmers, smaller market, much bigger money.
And no way would the above work on DragonFly BSD, just the Linux OS only.
Anyhow no one uses DragonFly BSD with its filesystem that supports snapshots, checksumming and data deduplication – no one would need that.
ssh at least works on W10 now
Yeah, errm… don’t think SCO OpenServer was FreeBSD based.
I’ve used both, and I don’t recall ever needing to re-link FreeBSD’s kernel to change IP addresses, whereas SCO OpenServer 5 did require exactly that (followed by a reboot).
SCO was a primitive OS. Nothing at all like FreeBSD.
I’ve used SCO as well, but the latest and greatest openserver 10 (Xinuos) is based on freebsd!
Moose out front should have told you. Oh wait, he did! “Linux-fu”!
Newest version of w10 and server19 now have sshd onboard an can be installed via aditional feature or ps. Witch of these tricks works I don’t know.
https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Proxies_and_Jump_Hosts#SSH_Over_Tor
This is unexpectedly useful. You can easily any machine behind a NAT with it. By the way does anyone know of a good guide for hidden service authentication configuration. Latest tor versions made it quite more complex.
One fine trick is to use mosh.
Unfortunately mosh runs on UDP so X forwarding doesn’t work – you need a 2nd ssh session for that. Otherwisecoupled with screen mosh is super cool.
Like many of the books in the humble bundle, it’s so old it’s useless – from 2009. A bunch of stuff mentioned in this very article wouldn’t be in that book, because the features came in the last (cough) ten years.
O’reilly has really slipped; many of their core books that they are most famous for are now hopelessly outdated. The DNS and bind book doesn’t even cover DNSSEC, and who the hell uses bind anymore?
The humble bundle is possibly still worth it because a few of the books are more recent, but still….don’t get too excited, and check the dates of the editions included.
you can do ssh natively on windows nowadays
Yeah, to be more specific, on Windows 10 you go:
Start -> Settings -> Apps
Click ‘Optional features’ under Apps & features
Click ‘Add a feature’
Scroll down to OpenSSH Server. OpenSSH Client is probably already installed for most people assuming you’re at a high enough build number.
Yes. I found out by accident when in a Windows cmd session and just typed > ssh me@someserver.com without thinking… and it worked,
Looking forward to more ssh tricks. Great stuff!.
Thanks for compiling this guide, found it helpful to level up a bit of my command-line work.
it looks like sshpass still will NOT work the first time when the local hostname has not been saved to the Known_hosts file in the remote host under .ssh directory. Does anyone know how to get along that?
You can use ssh-keyscan to fetch the remote host key, and add that to the known_hosts file. https://linux.die.net/man/1/ssh-keyscan