Many developers working with remote servers face a common challenge: needing different connection methods depending on network context. A typical SSH config might look like this:
Host internal-server
HostName internal.ip
ProxyCommand ssh -W %h:%p external-server
This works when you're outside the corporate network, but creates unnecessary latency when you're already inside the VPN where direct access is possible.
The solution lies in creating a conditional ProxyCommand that tests connectivity before deciding the route. Here's how to implement it:
Host internal-server
HostName internal.ip
ProxyCommand bash -c "if ping -c 1 -W 1 %h >/dev/null 2>&1; then exec nc %h %p; else exec ssh -W %h:%p external-server; fi"
For more reliability, we can add connection testing through multiple methods:
Host internal-server
HostName internal.ip
ProxyCommand bash -c "if (ping -c 1 -W 1 %h >/dev/null 2>&1 || nc -z -w 1 %h %p >/dev/null 2>&1); then exec nc %h %p; else exec ssh -W %h:%p external-server; fi"
For systems where ping might be blocked but SSH connections work:
Host internal-server
HostName internal.ip
ProxyCommand bash -c "if ssh -o ConnectTimeout=1 -q %h exit; then exec nc %h %p; else exec ssh -W %h:%p external-server; fi"
Each connectivity test adds some overhead. The ping method is fastest (typically 1 second), while SSH testing takes longer but is more accurate. Choose based on your network environment.
Remember that any conditional logic introduces potential failure points. Ensure your fallback method (the proxy connection) remains secure even if the direct connection test fails unexpectedly.
Many developers working with remote servers face this common scenario: some internal servers are accessible both directly (when on company VPN/internal network) and through a proxy server (when outside). The standard SSH config approach looks like this:
Host internal-server
ProxyCommand ssh -W internal.ip:22 external-server
This works, but creates unnecessary latency when you're already on the internal network. The connection first goes out to the external proxy server and then back in, adding hops when a direct connection would suffice.
There are several ways to implement conditional proxying in your SSH config:
Method 1: Using nc (netcat) for Connection Testing
This approach tests connectivity before deciding whether to proxy:
Host internal-server
ProxyCommand bash -c 'if nc -z -w 2 internal.ip 22 2>/dev/null; then nc internal.ip 22; else ssh -W internal.ip:22 external-server; fi'
Method 2: Using Match Exec
For OpenSSH 7.4+ (released 2016-12-19), you can use Match exec:
Host internal-server
Match exec "nc -z -w 2 internal.ip 22"
Hostname internal.ip
Match all
Hostname internal.ip
ProxyCommand ssh -W %h:%p external-server
Method 3: Separate Host Entries with Different Conditions
Create two host entries and use different aliases:
# Direct connection when available
Host internal-server-direct
Hostname internal.ip
User myuser
# Add other direct connection parameters
# Proxy connection when direct fails
Host internal-server
Hostname internal.ip
User myuser
ProxyCommand ssh -W %h:%p external-server
For the most robust solution, combine connectivity testing with fallback:
Host internal-server
Hostname internal.ip
User myuser
ProxyCommand bash -c 'if ping -c 1 -W 1 internal.ip >/dev/null 2>&1; then exec nc %h %p; else exec ssh -W %h:%p external-server; fi'
When implementing conditional proxying:
- The connection test timeout (the -w parameter) should be short (1-2 seconds)
- Consider using ping instead of nc if firewalls block port probes
- For frequently accessed servers, the slight delay for the connection test may be worth the direct connection speed
Be aware that:
- Connection tests might leak information about your network environment
- Ensure your external proxy server is properly secured
- Consider using SSH certificates instead of passwords for automated connections