SSH Tidbits You Might Not Know About
Weāve got a single-topic Drop today as Iāve been leaning into some SSH features that I should have been using more, but have had to deliberately use both for myself, and when creating skills for agents (so they behave better in various contexts).
Hence, no TL;DR, but I am willing to bet every reader will find at leastĀ oneĀ item you may not know (or have forgotten about), and that you will find regular uses for.

Make connections fail fast instead of hanging
BatchModeĀ is the one that bites everyone who writes automation. SSHās default behavior is chatty: if key auth isnāt set up, it falls back to prompting for a password, which is fine when youāre sitting at a keyboard and catastrophic when a cron job, CI pipeline, or Ansible run hits a misconfigured host ā the connection just hangs, waiting for input that never comes.
BatchMode=yesĀ turns all of that off. No password prompts, no passphrase prompts, no āare you sure you want to continue connecting?ā If key-based auth works, you connect; if it doesnāt, you get an immediate error and carry on with your life.
ssh -o BatchMode=yes user@hostname
Or in your config:
Host myserver HostName example.com BatchMode yes
The important nuance:Ā BatchModeĀ doesnāt disable key auth, it disablesĀ prompts. A valid key inĀ ssh-agentĀ or passed viaĀ -iĀ works exactly as normal ā only the interactive fallbacks get suppressed. Pair it withĀ StrictHostKeyChecking=accept-newĀ to skip the unknown-host-key prompt too, and youāve got a fully non-interactive connection:
ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new user@hostname
In practice this is the difference between a script that fails cleanly and one that wedges your whole pipeline:
#!/bin/bashif ssh -o BatchMode=yes -o ConnectTimeout=5 user@server "uptime"; then echo "Connection successful"else echo "SSH failed ā check your key setup" exit 1fi
(One Debian/Ubuntu quirk:Ā BatchMode=yesĀ there also nudgesĀ ServerAliveIntervalĀ to 300s, which helps detect dead connections in long batch jobs.)
Teleport a shell function to a remote host
This one feels like cheating. Define a function locally, run it on a remote box, copy nothing:
hello() { echo "Hello from $(uname -n)"}ssh user@server "$(declare -f hello); hello"
declare -fĀ serializes the function definition into text, which gets evaluated on the remote side before you call it. Tools likeĀ kittenĀ andĀ promptcmdĀ use exactly this trick to carry their behavior into remote sessions. Once youāve internalized it, youāll find yourself shipping ad-hoc helpers over SSH constantly.
Always land inĀ screen/tmux
If you live inĀ tmuxĀ (which I am using more thanks to Oh My OpenAgent) orĀ screen, why retypeĀ tmux attachĀ (orĀ screen -DR) every time you log in? Put this in your config:
Host myserver RemoteCommand tmux new -A -s main RequestTTY yes
or:
Host myserver RemoteCommand screen -DR main RequestTTY yes
ssh myserverĀ now drops you straight into (or reattaches to) a session namedĀ main. Disconnect ā flaky wifi, closed laptop, whatever ā and everything keeps running, waiting for you when you come back.
Copy yourĀ terminfo, not just your key
Everyone (hopefully) knowsĀ ssh-copy-id user@serverĀ for getting your public key onto a box. Fewer people know the companion move: shipping yourĀ terminfoĀ over so fancy terminals behave correctly on the remote side.
infocmp | ssh user@server -- tic -
This sends your terminalās capability database to the server and compiles it there. Itās the fix for that āNot using a fully-functional terminalā complaint from vim and less when youāre on a host thatās never heard of your terminal emulator.
Iām using this (more) now that Iāve fully migrated toĀ libghostty-backed terminals from WezTerm.
Make config conditional with Match
(Iāve mentioned this before but Iām re-upping it since itās so stupid handy.)
HostĀ blocks match on hostname patterns.Ā MatchĀ blocks go further ā they can key off the user, or even the result of an arbitrary command:
# Only jump through the bastion when the VPN is reachableMatch host *.internal exec "ping -c1 -W1 vpn.example.com >/dev/null" ProxyJump bastion# Use a different identity when connecting as adminMatch host server User admin IdentityFile ~/.ssh/id_ed25519_admin
TheĀ execĀ form is the sleeper feature here: your SSH config can make decisions based on live conditions instead of static patterns.
Split your config into pieces
A single sprawlingĀ ~/.ssh/configĀ eventually becomes unmanageable.Ā IncludeĀ lets you break it apart:
# ~/.ssh/configInclude ~/.ssh/config.d/*.confInclude ~/.ssh/config.workInclude ~/.ssh/config.personal
The practical payoff is separation: work hosts in a gitignored file, personal hosts in your dotfiles repo, and no more accidentally leaking client hostnames into version control.
Eyeball š your host keys
Turn on visual fingerprints and SSH draws a little ASCII-art rendering of the host key every time you connect:
Host * VisualHostKey yes
We humans are bad at comparing hex strings and good at spotting when a picture looks wrong. If a host you connect to daily suddenly shows different art, your brain notices before your conscious mind does.
Kill a frozen session
When a session locks up hard and Ctrl-C, Ctrl-D, and Ctrl-Z all do nothing, thereās an escape hatch built right into the protocol:
Enter ~ .
Press Enter, then tilde, then dot, in sequence. Thatās the SSH escape sequence for āterminate this connection now.ā Itās saved me from opening a second terminal more times than I can count.
I used this enough during travel this week that I felt compelled to add it todayās Drop.
Stop getting silently dropped
NAT timeouts and idle firewalls love to kill SSH sessions out from under you. Keepalives fix it:
Host * ServerAliveInterval 60 ServerAliveCountMax 3
This sends a keepalive through theĀ encrypted channelĀ every 60 seconds ā distinct from TCP keepalive, which lives below the encryption and can be spoofed. If three go unanswered, SSH disconnects cleanly instead of freezing into a zombie session.
Run one sudo command and bail
For one-off privileged commands, you donāt need an interactive session:
ssh -tt user@server -- sudo systemctl restart nginx
The doubledĀ -ttĀ forces TTY allocation soĀ sudoĀ can prompt for its password. The command runs, sudo gets its prompt, the session exits. Clean.
If you want to really level things up a bit, aĀ Host *Ā block with a bunch of these (and other) SSH options canĀ quietly eliminate a dozen tiny annoyances from every connection you make for the rest of the day.
FIN
Remember, you can follow and interact with the full text of The Daily Dropās free posts on:
- Mastodon viaĀ
@dailydrop.hrbrmstr.dev@dailydrop.hrbrmstr.dev - Bluesky viaĀ
<https://bsky.app/profile/dailydrop.hrbrmstr.dev.web.brid.gy>
ā®ļø
Leave a Reply