Guide

SSH ProxyJump: Jump Host Config and Safe Access from a Phone

SSH ProxyJump connects your client to a private server through a jump host using ssh -J or a ProxyJump entry in ~/.ssh/config. Unlike agent forwarding, it requires no remote access to your SSH agent; on a phone, use a compatible client or TermAI’s built-in Tailscale for an approved direct route.

CC Chen Chen· Founder·2026-09-09·10 min read

SSH ProxyJump connects your client to a private server through a jump host using ssh -J or a ProxyJump entry in ~/.ssh/config. Unlike agent forwarding, it needs no forwarded agent. From a phone, use a compatible SSH client; TermAI’s built-in Tailscale offers a separate, approved private-network route.

What is SSH ProxyJump, and how does it work?

A jump host is a server that can reach a destination your phone cannot reach directly. A bastion often serves this role at the boundary of a private network.

Phone running the SSH client → Bastion → Private server
                               forwards   SSH session ends here

The originating client authenticates to the bastion, requests a TCP connection to the target, then establishes a separate SSH session with that target through the forwarded connection. You finish at the target’s shell without opening an interactive shell on the bastion. The one-command form is:

ssh -J [email protected] [email protected]

Replace the example addresses and usernames throughout this guide with your approved infrastructure details. The bastion must be reachable from your phone, and it must be able to reach the target’s SSH port. Oracle’s ProxyJump guide documents both this command and the persistent configuration form.

What is the difference between ProxyJump and agent forwarding?

ProxyJump forwards a connection. Agent forwarding exposes a way to request authentication signatures from your local agent.

QuestionProxyJumpAgent forwarding with a second SSH command
Where does the target SSH client run?On your originating deviceOn the bastion
Must private keys be copied onto the bastion?NoNo
Does the bastion need access to your local agent?NoYes, for the forwarded-agent workflow
Typical commandssh -J bastion targetssh -A bastion, then ssh target
Main concernVerify host identities and forwarding policyPrivileged processes on the remote host can misuse the forwarded agent

Agent forwarding does not normally reveal the private key itself. The risk is that someone with sufficient access to the remote agent socket can request signatures and authenticate elsewhere while that access remains available. OpenSSH explicitly cautions about this and suggests a jump host as an alternative. OpenSSH ssh manual

Keep agent forwarding disabled for a routine production jump. A local ssh-agent can still unlock your keys for your own client; using it locally and forwarding it remotely are separate choices.

The target SSH session remains encrypted through the bastion, provided you verify the target’s host identity. The bastion can still observe connection metadata or interrupt traffic. Routing through it also does not automatically provide a recording of commands executed on the target. Teleport’s explanation of the connection path

How do I configure SSH ProxyJump with different keys and ports?

For an OpenSSH client, put this in the originating client’s ~/.ssh/config:

Host bastion
    HostName bastion.example.com
    User jump
    Port 2222
    IdentityFile ~/.ssh/id_ed25519_bastion
    IdentitiesOnly yes
    ForwardAgent no

Host prod-web
    HostName 10.20.0.15
    User deploy
    Port 22
    IdentityFile ~/.ssh/id_ed25519_prod
    IdentitiesOnly yes
    ProxyJump bastion
    ForwardAgent no

The paths refer to private keys available to that client. Provision the matching public key for jump on the bastion and the production public key for deploy on the target through your normal access process. Separate keys let you revoke phone access independently for each role.

Then connect:

ssh prod-web

For a one-off connection with different ports:

ssh -J [email protected]:2222 -p 22 [email protected]

The :2222 belongs to the jump host; -p 22 belongs to the target. Destination options generally do not configure the jump host, so use separate host blocks for different identities. Put specific blocks before broad Host * defaults. OpenSSH configuration reference

Before accepting either host key, compare its fingerprint with a trusted inventory or an administrator through an independent channel. Verify both hosts, not just the first prompt. Follow the host-key verification guide if a previously known fingerprint changes.

How do I use an SSH jump host from an iPhone or Android phone?

First determine whether the app supplies a local SSH command or connects through saved graphical host profiles. A terminal window does not, by itself, tell you which one you are using.

If your phone has a local OpenSSH client

Run ssh -V in the local terminal. ProxyJump requires an OpenSSH client with support introduced in version 7.3. This is a client requirement, not a requirement to upgrade the bastion to that same version. OpenSSH 7.3 release notes

Save the configuration above in that local environment and make the key files available there securely. Connect with ssh prod-web. A config saved on your laptop will not automatically exist inside a phone app.

If TermAI is already displaying a remote server’s shell, typing ssh -J ... there starts SSH on that remote server. Its files, keys, and trust boundary apply. It does not configure TermAI’s phone-side connection.

If your mobile client uses host profiles

For a client that explicitly documents jump-host support, map the same details into its supported connection settings:

  1. Create the bastion profile with its public address, port, username, and credential.
  2. Create the target profile with its private address, port, username, and separate credential.
  3. Assign the bastion as the target’s jump host using that client’s documented control.
  4. Keep agent forwarding off, verify both host identities, and test the target connection.

Treat these as the required fields, not universal button names. Check support for your required MFA method and SFTP through the same jump path before relying on the app during an outage.

If you want to reach the server with TermAI

TermAI provides SSH/SFTP on iOS and Android, an AI command assistant, and built-in Tailscale. The OpenSSH examples above are not instructions for a verified native TermAI ProxyJump setting. If your organization mandates a bastion, confirm native jump-host support for your installed version before choosing that route.

Where your access policy permits direct tailnet access, use this TermAI workflow:

  1. Have the administrator connect the target to the approved tailnet and permit your device’s access to its SSH service.
  2. Configure TermAI’s built-in Tailscale connection using your organization’s approved credentials; the getting-started guide describes its auth-key setup.
  3. Add the target’s Tailscale address as the SSH host, with the server’s SSH username, port, and authentication credential.
  4. Connect, verify the server’s host key, and test access while using cellular data.

This reaches the private server without an SSH jump when the network policy allows it. Ordinary SSH over a Tailscale network still uses your server’s SSH authentication. The separately enabled Tailscale SSH feature has its own authentication and policy model. Tailscale SSH documentation

How do I use multiple jump hosts or ProxyCommand?

For more than one bastion, list aliases in connection order:

ssh -J bastion,inner-bastion [email protected]

Define inner-bastion with its own address, username, port, and identity just as you defined bastion. Each intermediate host must reach the next one. A persistent target block can use ProxyJump bastion,inner-bastion.

For a client without -J that supports ssh -W, replace the target’s ProxyJump line with:

    ProxyCommand ssh -W %h:%p bastion

This uses SSH’s forwarding mechanism and does not require netcat on the bastion. ProxyCommand is also useful when a custom transport program is required. Do not combine both directives for the same target; the first obtained one takes precedence. OpenSSH ProxyCommand reference

Conditional routing is possible with Match exec, which runs a local test before applying settings. For incident access from a phone, explicit profiles such as prod-via-bastion and prod-via-tailnet are easier to inspect. A failed ping is insufficient evidence that bypassing a required bastion is appropriate. Teleport’s conditional-jump example

Does ProxyJump work with SFTP, SCP, and port forwarding?

With the OpenSSH config above, start a file-transfer session from the local client:

sftp prod-web

Or specify the jump directly:

sftp -J [email protected]:2222 [email protected]

SFTP supports -J and SSH configuration options. The target must provide an SFTP subsystem; terminal access alone does not guarantee it. OpenSSH SFTP manual

Other OpenSSH-based workflows can reuse the alias:

scp prod-web:/var/log/app/health.log ./health.log
rsync -av -e ssh prod-web:/srv/app/reports/ ./reports/

Use permitted paths; the rsync example requires rsync on both ends. In TermAI, use its SFTP client on the approved Tailscale connection to browse or retrieve files. Do not assume a GUI file-transfer feature inherits a config stored in another app.

For a service listening on the target’s loopback interface, a local OpenSSH tunnel can follow the jump:

ssh -N -L 127.0.0.1:8080:127.0.0.1:8080 prod-web

Here the first loopback address is on the client; the second is on prod-web. Server forwarding policy must permit it. OpenSSH local forwarding reference Mobile apps also differ in whether another app can use their local listener; see port forwarding from a phone.

Why is SSH ProxyJump failing?

Identify the failing hop before changing credentials or firewall rules. In a local OpenSSH environment:

ssh -G prod-web
ssh -vvv bastion
ssh -vvv prod-web

-G prints evaluated configuration without connecting. Verbose output helps distinguish bastion authentication from target authentication. Redact infrastructure details before sharing logs. OpenSSH diagnostic options

SymptomWhat to check
Timeout before bastion authenticationBastion address and port, public firewall rules, and whether the phone’s current source IP is allowed.
Bastion authenticates, then connection times outRouting and firewall access from the bastion to the target’s actual SSH port.
Permission denied (publickey)Identify which host rejected the login; check that host’s username, selected key, and public-key authorization.
Too many authentication failuresSelect the intended identity for that hop and avoid offering unrelated agent keys.
Target hostname cannot be resolvedCheck DNS from the bastion for the target name; try its approved private IP to isolate DNS.
administratively prohibited: open failedCheck forwarding restrictions on the bastion, including account- and key-specific restrictions.
Host-key warningIndependently verify the fingerprint; do not disable checking to make the error disappear.

For a bastion administrator, this illustrates a narrowly scoped forwarding allowance for the example destination:

Match User jump
    AllowTcpForwarding local
    PermitOpen 10.20.0.15:22
    AllowAgentForwarding no

Merge it with existing policy rather than replacing the server configuration. DisableForwarding yes can override forwarding permissions. Validate changes and keep a recovery session open before reloading SSH. OpenSSH server configuration reference

Also check the matching authorized_keys entry: no-port-forwarding or restrict can prohibit forwarding. A permitopen restriction does not by itself re-enable forwarding disabled elsewhere. OpenSSH authorized-key options

When a connection works on office Wi-Fi but fails on cellular, examine the bastion’s source-IP policy. See SSH IP allowlisting from a phone before widening access.

How can I manage the private server safely in TermAI?

Once TermAI has an approved SSH connection to the target, begin by confirming where you landed:

hostname
whoami
pwd

For a Linux server using systemd and nginx, ask TermAI’s AI assistant:

Suggest a read-only command to inspect nginx logs from the last ten minutes. Explain the flags. Do not restart or modify anything.

Review the suggestion before confirming execution. An appropriate command for that environment might be:

journalctl -u nginx --since "10 minutes ago" --no-pager

Check the service name, time range, and required permissions. If a restart becomes necessary, make it a separate decision after reviewing the evidence and your runbook. TermAI’s assistant suggests commands and waits for your confirmation; it is not an autonomous production agent. The free tier includes five AI requests per day and unlimited SSH/SFTP. TermAI features and free tier

Prepare for disconnections too. If tmux is installed on the target, start or reattach an incident session there:

tmux new-session -A -s incident

After reconnecting, attach again and inspect the result before repeating an interrupted-looking command. Losing the phone’s connection does not prove the remote operation failed. Keep-alives cannot guarantee that a mobile operating system will keep a background app running. Build this check into your mobile production safety routine.

What else should I know about SSH ProxyJump?

Does ProxyJump require ssh-agent or agent forwarding?

No. A client can authenticate using local key files without forwarding an agent. A local agent is optional; remote access to it is unnecessary for the jump.

Can ProxyJump use a private key stored only on the bastion?

Not in the normal ProxyJump flow. The originating client authenticates to the target, so it needs access to the target credential. Running a second SSH client on the bastion is a different arrangement.

Does the jump host need OpenSSH 7.3 or newer?

ProxyJump was added to the OpenSSH client in version 7.3. The jump server needs compatible SSH TCP forwarding, not a matching client version or netcat installation.

Can I use ProxyJump with a password or MFA?

Yes, when the client supports the authentication methods required by each server. Expect separate authentication prompts for the bastion and target, and test the complete flow on your phone before an incident.

Is TermAI’s built-in Tailscale the same as ProxyJump?

No. ProxyJump uses an SSH bastion as a forwarding hop. TermAI’s built-in Tailscale provides a private network route; with authorized reachability, you can connect to the server’s SSH service directly.

Try TermAI

Free on iOS and Android. 5 AI requests/day on the free tier, plus unlimited SSH/SFTP and built-in Tailscale.

CC
Chen Chen — Founder of TermAI

Writes about mobile DevOps, terminal UX, and the surprising depth of "boring" infrastructure.