SSH is a VPN, a proxy, and a PKI — you're probably using 10% of what it can do
OpenSSH 10.4 shipped in July 2026, multiplexing saves 5 seconds per connection, and SSH certificates have been replacing authorized_keys since 2010 without anyone noticing. If you're still typing passwords to reach your servers, this article is for you.
OpenSSH 10.4 dropped on July 6, 2026, SSH turned 30 the year before — counting from Tatu Ylönen’s first implementation in 1995 — and most sysadmins are still typing ssh user@host like it’s 1999. This is a waste of a protocol: SSH isn’t just a remote terminal — it’s a VPN, a SOCKS proxy, a certificate authority, a connection multiplexer, and a filesystem tunnel. OpenSSH has shipped all of these capabilities for over a decade, with zero external dependencies, no extra daemons, and no additional network overhead.
This article covers seven advanced features that turn SSH into a network Swiss Army knife, with configurations tested against OpenSSH 10.x.
Multiplexing — one TCP connection, all your shells
Every sysadmin knows the pain: each ssh opens a fresh TCP connection, re-runs the Diffie-Hellman key exchange, and re-authenticates the user. To a server 150 ms away, an interactive session costs 2 to 3 seconds just to get to a prompt. Every scp, git push over SSH, and rsync pays the same tax.
SSH multiplexing solves this cold. The first connection — the master connection — opens the TCP tunnel and authenticates once. Every subsequent connection to the same host rides that tunnel over a UNIX-domain socket on your local machine, with no new TCP handshake and no re-authentication. The latency savings are immediate: 5 to 10 seconds shaved off every session on a 150 ms link.
The configuration is three lines in ~/.ssh/config:
Host *
ControlMaster auto
ControlPath ~/.ssh/controlmasters/%r@%h:%p
ControlPersist 10m Three directives, three jobs. ControlMaster auto enables automatic multiplexing: if a socket already exists for the target, the client piggybacks it; otherwise, it creates a master. ControlPath defines the UNIX socket location — %r for remote user, %h for host, %p for port. ControlPersist 10m keeps the master alive for 10 minutes after the last shell exits; without it, the master dies the moment you close your first terminal, making multiplexing useless for consecutive commands.
Catch #1: the directory ~/.ssh/controlmasters/ must exist. mkdir -p ~/.ssh/controlmasters && chmod 700 ~/.ssh/controlmasters before the first connection.
Catch #2: ControlPersist is silently ignored without ControlMaster auto. The three directives are a package deal.
Verify it’s working:
# Open a first session
ssh user@host
# In a second local terminal, check active sockets
ls -la ~/.ssh/controlmasters/
# The second connection reuses the tunnel — visible in verbose logs
ssh -v user@host 2>&1 | grep "auto-mux"
# Should print: "auto-mux: Trying existing master" The master connection costs one socket and a negligible amount of server memory. The trade-off: one network drop kills all multiplexed sessions — that’s the price of tunnel sharing. ControlPersist doesn’t protect against this; it only keeps the master alive after voluntary shell exits, not during a network outage.
ProxyJump and bastions — crossing network layers without a VPN
The scenario is universal: a production server isn’t directly reachable from the Internet. It sits behind a bastion — a hardened machine that acts as the single entry point to the internal network. The naive approach is SSH into the bastion, then SSH from the bastion to the target. Two authentications, two sessions, and scp is impossible without a two-hop rsync dance.
ProxyJump (introduced in OpenSSH 7.3, August 2016) fixes this with a single directive:
Host prod-*
ProxyJump bastion.example.com
User app # One command, one passphrase prompt
ssh prod-db1
# SSH transits through the bastion automatically Under the hood, ProxyJump establishes an SSH connection to the bastion, then asks the bastion’s SSH daemon to relay the TCP stream to the target (-W host:port). Authentication remains end-to-end: your private keys never leave your laptop and are never exposed on the bastion. Pair this with ssh-agent or a FIDO2 security key to enter your passphrase exactly once.
Chained ProxyJumps. Nothing prevents stacking:
Host prod-db-deep
ProxyJump public-bastion,internal-bastion The SSH client hops from your laptop to public-bastion, then to internal-bastion, then to the target. ssh prod-db-deep crosses three network layers in a single keystroke.
Agent forwarding: don’t. The historical reflex is ForwardAgent yes on the bastion so your local keys work from the next hop. Don’t do this. A compromised bastion can use your agent to bounce to every machine where your key is authorized. This attack is documented since 2016 and the risk is real: if an attacker gains root on the bastion, they can intercept the SSH_AUTH_SOCK socket and sign connections as you. ProxyJump eliminates this risk by keeping authentication on your local machine.
If you absolutely must use ForwardAgent, enable it only on the final target, never on the bastion:
Host prod-*
ProxyJump bastion.example.com
ForwardAgent yes # on the final target only And prefer ssh-add -c (require touch confirmation) to gate every key use.
SSH certificates — your own PKI, no X.509 required
This is OpenSSH’s most underused feature, and its most powerful. Since OpenSSH 5.4 (March 2010), SSH supports a native certificate format — do not confuse this with X.509. The principle: you create a Certificate Authority (CA) key, sign your users’ and hosts’ public keys with it, and configure your servers to trust the CA rather than individual keys.
The architectural consequence is a clean break from the past. No more authorized_keys files with 300 lines synced manually across 50 servers. No more orphan keys from an admin who left six months ago. Key rotation becomes a centralized operation: you revoke the certificate, not the key.
Step-by-step setup
1. Create the CAs (once, on an offline machine ideally):
ssh-keygen -t ed25519 -f /etc/ssh/ca_user -C "User CA - Ettayeb Infra"
ssh-keygen -t ed25519 -f /etc/ssh/ca_host -C "Host CA - Ettayeb Infra" Two separate CAs: one for user keys, one for host keys. This separation is critical — a compromised user CA must not allow server impersonation, and vice versa.
2. Configure servers to trust these CAs:
# /etc/ssh/sshd_config
TrustedUserCAKeys /etc/ssh/ca_user.pub
HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub 3. Sign a user’s key:
# Sign the key for 12 hours, with the Unix username locked
ssh-keygen -s /etc/ssh/ca_user \
-I "walid-ettayeb" \
-n "root,app" \
-V +12h \
~/.ssh/id_ed25519.pub -I is a free-form identifier (for audit logs). -n forces the principal — the Unix user account the connection is authorized under. -V +12h sets the validity window: an SSH certificate has an expiration date, unlike a bare public key.
The output is an id_ed25519-cert.pub file alongside your public key. SSH picks it up automatically if the server trusts the signing CA.
4. Inspect a certificate:
ssh-keygen -L -f ~/.ssh/id_ed25519-cert.pub
# Shows: type, CA, principals, validity, serial, extensions What certificates give you that raw keys don’t
- Expiration. A key signed for 12 hours limits the compromise window. If your laptop is stolen, the certificate expires before you’ve finished filing the police report.
- Revocation. Add the certificate’s serial number to a
RevokedKeysfile on the server, and it’s instantly unusable — everywhere, in one operation. - Forced principals. The
-n rootin the signature locks the Unix user. Even if an attacker steals the certificate, they can’t log in as anyone else. - Audit trail. The
-Iidentifier shows up in/var/log/auth.log, so you can trace who connected, not just which key. - Extensions. You can embed constraints in the certificate:
permit-port-forwarding,permit-pty,force-command. A certificate becomes a scoped “access token” to a subset of SSH functionality.
The cost. An SSH certificate infrastructure needs a signing tool — a 50-line Python script or a service like Smallstep SSH, HashiCorp Vault, or Teleport (now owned by ForgeRock). The standard is open and documented in PROTOCOL.certkeys in the OpenSSH repository.
Port forwarding — SSH as a VPN and SOCKS proxy
Port forwarding is the feature that turns SSH into a universal network tunnel. Three modes exist, and knowing the difference changes how you design access to internal services.
Local forwarding (-L): bring a remote port to your machine
ssh -L 8080:internal-db:5432 user@bastion This listens on localhost:8080 and relays all traffic to internal-db:5432, as seen from the bastion. From your laptop, psql -h localhost -p 8080 reaches the internal database without exposing it to the Internet. No HTTP proxy, no NAT — just a raw TCP relay.
Local forwarding is the safest mode: the port binds to localhost by default and is not reachable from the network. To listen on all interfaces, use -L 0.0.0.0:8080:... or set GatewayPorts yes on the server.
Remote forwarding (-R): expose a local port on the remote server
ssh -R 9000:localhost:3000 user@bastion This opens port 9000 on the bastion and relays traffic back to localhost:3000 on your laptop. Useful for temporarily exposing a dev service to a colleague, or giving an external webhook access to your local environment.
Remote forwarding is disabled by default on most servers even with AllowTcpForwarding yes — you need GatewayPorts clientspecified or yes in sshd_config to allow listening on anything other than localhost.
Dynamic forwarding (-D): a SOCKS proxy through SSH
ssh -D 1080 user@bastion This turns your machine into a SOCKS5 proxy on localhost:1080. All traffic routed through this proxy exits from the bastion — DNS resolution included if you pass --socks5-hostname to your client.
# Configure your browser to use SOCKS proxy on localhost:1080
# Or from the CLI:
curl --socks5-hostname localhost:1080 https://ifconfig.me
# Returns the bastion's IP, not yours The -D flag is an application-level VPN with zero privilege escalation. No tun interface, no routing table changes, no network configuration. One user process, one local socket, and all your application traffic exits through the bastion. The combination ssh -D 1080 -N -f user@bastion opens the tunnel in the background (-f), without a shell (-N), ready to serve indefinitely.
Limitation: SSH SOCKS is TCP-only. No UDP, no native DNS (unless your client delegates resolution via --socks5-hostname). For a full VPN experience, combine SSH with sshuttle — a tool that builds a transparent VPN tunnel using SSH as transport, with no dedicated VPN server required.
SSHFS — mount a remote filesystem with the permissions of your SSH key
SSHFS (built on FUSE and the SFTP protocol) does for filesystems what ssh -L does for TCP ports: it exposes a remote directory as a local mount, with no NFS, no Samba, and zero server-side configuration.
# Install (once)
apt install sshfs
# Mount
sshfs user@host:/var/log /mnt/host-logs
# Use it — the remote directory behaves like any local directory
ls /mnt/host-logs
grep ERROR /mnt/host-logs/syslog
# Unmount
fusermount -u /mnt/host-logs No server configuration is needed beyond the SFTP subsystem (enabled by default). Permissions are those of the SSH user: you see what your key is authorized to see.
Useful options:
sshfs -o reconnect,ServerAliveInterval=15,ServerAliveCountMax=3 \
-o cache=yes,cache_timeout=60 \
user@host:/data /mnt/data reconnect: automatically re-establishes the connection after a network drop.ServerAliveInterval=15: sends a keepalive every 15 seconds to prevent idle timeouts.cache=yes,cache_timeout=60: caches file attributes for 60 seconds — dramatically speeds uplsandfind.
SSHFS is not a NAS. Throughput is capped by SSH encryption overhead and network latency: on a 50 ms link, you’ll top out around 30 to 50 MB/s on a modern CPU. For log inspection, config editing, or ad-hoc file transfers, that’s more than enough. For permanent mounts or bulk data, reach for NFS or a distributed filesystem.
MOSH — the shell that survives network changes
MOSH (Mobile Shell), released in April 2012 by an MIT team, solves a problem SSH was never designed for: network mobility. Close your laptop, switch Wi-Fi networks, unplug Ethernet and fall back to cellular — SSH drops the connection. The TCP socket is severed, the shell is dead, and your tmux session dies with it (unless you reconnect in time).
MOSH replaces SSH’s TCP transport with a UDP-based protocol called SSP (State Synchronization Protocol). The core idea: the remote terminal state is synchronized in real time with the client, and every keystroke is displayed locally via predictive echo before the server even responds. Underlining marks unconfirmed predictions — a technique borrowed from collaborative text editors.
What MOSH does better than SSH:
- IP roaming. Switch networks and your MOSH session survives. UDP has no connection — the server keeps sending packets to the last source IP it saw, and picks up the new one when it arrives.
- Predictive local echo. On a 300 ms link, SSH displays each character with a 300 ms delay. MOSH shows your keystrokes instantly, catches up with corrections when the server response arrives, and underlines what isn’t yet confirmed.
- No buffer bloat.
Ctrl+Calways interrupts the remote process immediately, even with a saturated network buffer — the SSP protocol uses adaptive frame rates based on network conditions.
What MOSH doesn’t do:
- No port forwarding (
-L,-R,-D). - No
scpor SFTP — MOSH is an interactive shell, not a tunnel. - No native
ssh-agentforwarding. - No multiplexing: each MOSH session is independent.
How it works: the MOSH client first connects to the server over SSH (standard authentication), launches the mosh-server process which listens on a random UDP port, then the MOSH client connects to that UDP port. The initial SSH connection can drop immediately — MOSH runs entirely over UDP from that point, with its own AES-128-OCB encryption.
# Install (client + server)
apt install mosh
# Connect — same syntax as SSH
mosh user@host
# With a non-standard SSH port
mosh --ssh="ssh -p 2222" user@host MOSH doesn’t replace SSH — it complements it. Keep SSH for tunnels, file transfers, and automation. Use MOSH for long-running interactive sessions, especially over mobile or high-latency links. Version 1.4.0 (October 2022, the latest stable release) added true-color support, which was sorely missing for modern terminal color schemes.
Hardening sshd_config — the minimum every server should have
Most SSH hardening boils down to five directives that close doors left open by default. Here’s what a minimal hardened sshd_config should contain, beyond host keys:
# /etc/ssh/sshd_config — hardened excerpt
# 1. Disable root login — always
PermitRootLogin no
# 2. Key-based authentication only — no passwords
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM yes # keep PAM for session modules, but no password auth
# 3. Restrict weak algorithms
KexAlgorithms curve25519-sha256,[email protected]
Ciphers [email protected],[email protected]
MACs [email protected],[email protected]
HostKeyAlgorithms ssh-ed25519,[email protected]
# 4. Limit exposure
MaxAuthTries 3
MaxSessions 5
LoginGraceTime 30
ClientAliveInterval 300
ClientAliveCountMax 2
# 5. Lock down unnecessary forwarding
AllowTcpForwarding no # or yes if you need it
X11Forwarding no
AllowAgentForwarding no # critical if you use ProxyJump
PermitTunnel no # unless you're doing SSH VPNs (tun) The rationale, directive by directive:
PermitRootLogin nois the first thing every SSH scanner tests. Since OpenSSH 8.4 (September 2020), the default isprohibit-password— root login only via key. Go further withno: no production scenario should ever need direct root access.PasswordAuthentication noeliminates password brute-forcing. If you must keep password auth for legacy users, isolate them in aMatchblock and enable rate-limiting withPerSourcePenalties(OpenSSH 9.8+, June 2024), which penalizes source IPs after repeated failures.- The algorithms listed above exclude NIST P-256/P-384 curves (potentially weakened), CBC ciphers (vulnerable to padding oracle attacks), SHA-1 (broken), and the
umac-64MAC (too short). The definitive guide is themodulifile shipped with OpenSSH — keep only groups ≥ 3072 bits. ClientAliveInterval 300+ClientAliveCountMax 2disconnect ghost sessions after 10 minutes of network silence. Without these, a client that drops its connection without sending a TCP RST holds a session slot indefinitely.AllowTcpForwarding noif you’re not using-L/-R/-D. An attacker with a limited shell can abuse port forwarding to pivot into your internal network. If you need it, scope it withPermitOpen.
Going further — conditional Match blocks:
# Restrict forwarding to the network admin group
Match Group netadmins
AllowTcpForwarding yes
PermitOpen 10.0.0.0/8:* 172.16.0.0/12:*
# Allow password auth for interns, with rate limiting active
Match Group interns
PasswordAuthentication yes After any change, validate before reloading:
sshd -t && systemctl reload sshd sshd -t tests the syntax — if it’s wrong, the daemon refuses to reload and you keep your current session alive. Never run systemctl restart sshd directly: a syntax error locks you out of the machine.
The verdict
SSH is the only network tool already installed on 100% of your servers, and it does more than 90% of sysadmins ask of it. Graduating to the next level requires no new software — only configuration.
- You manage more than three servers and type
ssh user@hostfive times a day: enable multiplexing. Three lines in~/.ssh/config, and every session after the first opens in under 100 ms. The most immediate productivity gain available. - You have a bastion and you’re doing the double-hop dance: switch to
ProxyJump. One command, one authentication, and yourssh-agentnever leaves your laptop. - You have 10 admins, 50 servers, and unmanageable
authorized_keyssprawl: deploy SSH certificates. Aned25519CA, a 50-line signing script, and key rotation becomes a routine operation instead of a synchronization nightmare. - You’re exposing an internal service to a colleague through a temporary firewall rule: use
ssh -Rinstead. One command, no firewall changes, no clean-up. - You work from trains and coffee shops with flaky Wi-Fi: install MOSH. Your shell survives network changes, and your keystrokes appear instantly even at 300 ms of latency.
- You want to browse server logs without downloading files: mount the directory with SSHFS.
grep,less,tail -fas if they were local — noscp, norsync, no interactive session. - You manage Internet-facing servers: apply the five hardening directives.
PermitRootLogin noandPasswordAuthentication noalone block 99% of automated attacks.
The power of SSH comes from doing one thing well for 30 years — but that “one thing” is far broader than “remote terminal.” Master these seven features, and you will have deleted three tools from your stack and two SaaS subscriptions from your budget.
References
- OpenSSH 10.4 Release Notes, OpenSSH, July 6, 2026.
- OpenSSH Cookbook — Multiplexing, Wikibooks, accessed June 2026.
- PROTOCOL.certkeys — OpenSSH Certificate Protocol, OpenBSD CVS, initial version March 2010.
- SSH Certificates — Smallstep Blog, Carl Tashian, Smallstep, March 2020.
- ProxyJump in OpenSSH 7.3, OpenSSH Release Notes, August 2016.
- ssh(1) Manual — OpenBSD, Forwarding section, OpenBSD, 2026.
- sshd_config(5) Manual — OpenBSD, OpenBSD, 2026.
- Mosh: the mobile shell, MIT, version 1.4.0, October 2022.
- Mosh research paper, Winstein & Balakrishnan, USENIX ATC, 2012.
- SSHFS — GitHub, libfuse, 2026.
- Hardening OpenSSH — ANSSI Guide, ANSSI, updated 2024.
- Applied Crypto Hardening — BetterCrypto.org, SSH chapter, 2023.