Jump Hosts: Multi-Hop SSH
Build a three-VM lab and connect to a target through two SSH jump hosts from your Mac.
Before you run
Use a private test environment. Replace example IP addresses with the actual VM addresses. Verify each SSH host key through Multipass before trusting it. ProxyJump authenticates each hop from your Mac; it does not require a private key on a jump host. The jump hosts must allow TCP forwarding, and each hop must be able to reach the next. Keep a recovery session available before changing firewall rules.
Examples
Install Multipass, create three Ubuntu VMs, and record their actual IP addresses.
brew install --cask multipass
multipass launch --name jump1
multipass launch --name jump2
multipass launch --name target
multipass listCreate a dedicated key on the Mac. Choose a passphrase and do not overwrite an existing key.
ssh-keygen -t ed25519 -f ~/.ssh/securepipes_lab_ed25519Copy only the public key to each VM. These commands create the temporary file securepipes-lab.pub in each Ubuntu home directory; check that it does not already exist before running them.
for vm in jump1 jump2 target; do
multipass exec "$vm" -- test ! -e /home/ubuntu/securepipes-lab.pub || break
multipass transfer ~/.ssh/securepipes_lab_ed25519.pub "${vm}:/home/ubuntu/securepipes-lab.pub" || break
multipass exec "$vm" -- sh -c 'umask 077; mkdir -p "$HOME/.ssh"; chmod 700 "$HOME/.ssh"; cat "$HOME/securepipes-lab.pub" >> "$HOME/.ssh/authorized_keys" && chmod 600 "$HOME/.ssh/authorized_keys" && rm "$HOME/securepipes-lab.pub"' || break
doneCompare your public key fingerprint with the installed keys. The authorized_keys file may contain other keys too.
ssh-keygen -lf ~/.ssh/securepipes_lab_ed25519.pub
multipass exec jump1 -- ssh-keygen -lf /home/ubuntu/.ssh/authorized_keys
multipass exec jump2 -- ssh-keygen -lf /home/ubuntu/.ssh/authorized_keys
multipass exec target -- ssh-keygen -lf /home/ubuntu/.ssh/authorized_keysObtain each server host key fingerprint through Multipass. Compare it with the fingerprint shown by SSH before accepting a new host key.
multipass exec jump1 -- sudo ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
multipass exec jump2 -- sudo ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
multipass exec target -- sudo ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pubAdd these entries to ~/.ssh/config on your Mac using your actual VM IPs. Preserve existing entries; place these before any matching Host * defaults. Adjust IdentityFile if you chose another key path.
Host jump1
HostName 192.168.252.2
User ubuntu
IdentityFile ~/.ssh/securepipes_lab_ed25519
IdentitiesOnly yes
Host jump2
HostName 192.168.252.3
User ubuntu
IdentityFile ~/.ssh/securepipes_lab_ed25519
IdentitiesOnly yes
Host target
HostName 192.168.252.4
User ubuntu
IdentityFile ~/.ssh/securepipes_lab_ed25519
IdentitiesOnly yesTest direct access first, then connect through both jump hosts. Accept a host key only after verifying its fingerprint. In Secure Pipes, configure the same two jump hosts in order for the target connection.
ssh jump1
ssh jump2
ssh target
ssh -J jump1,jump2 targetOptional controlled-lab test: only if the target can distinguish the Mac source IP from jump2, and an existing UFW policy permits SSH, allow jump2 before denying the actual Mac source IP. Replace both placeholders. Do not enable or change a production firewall based on this example; keep console access and remove the rules after testing.
# On the target VM, replace the placeholders first:
sudo ufw status numbered
sudo ufw insert 1 allow from <JUMP2_IP> to any port 22 proto tcp
sudo ufw insert 2 deny from <MAC_SOURCE_IP> to any port 22 proto tcpAfter the optional firewall rules, direct SSH should fail while ProxyJump succeeds. Remove the two rules using the same actual IP addresses, then verify access again.
ssh target
ssh -J jump1,jump2 target
# On target, remove the lab rules:
sudo ufw delete deny from <MAC_SOURCE_IP> to any port 22 proto tcp
sudo ufw delete allow from <JUMP2_IP> to any port 22 proto tcpAuthoritative references
Reviewed October 27, 2026