pentaho/pentaho-kettle · critical · SshConnectionException

SSH over HTTP proxy connection failed: Proxy: : Target…

Error message

SSH over HTTP proxy connection failed: 
Proxy: :
Target: :
Note: Ensure HTTP proxy supports CONNECT method and target is reachable.

What it means

MinaSshConnection.configureHttpProxyConnector() wraps any failure to establish the SSH session through the configured HTTP proxy into SshConnectionException with a detailed message including proxy host:port, target host:port, and user info. It fires when the HTTP proxy refuses, cannot CONNECT, or cannot reach the target.

Solutions

  1. Verify the proxy host/port and that the proxy is reachable from the client host
  2. Confirm the proxy allows CONNECT to the SSH target port; many only permit 443 — use a proxy or gateway that permits port 22
  3. Supply proxy credentials if the proxy requires authentication
  4. Test the tunnel independently (e.g. curl -x proxy CONNECT) to isolate proxy vs target issues
  5. If a proxy is not actually needed, clear proxyHost/proxyPort so the direct connection path is used

Example fix

// before
config.setProxyHost("corp-proxy"); config.setProxyPort(8080); // proxy forbids CONNECT :22
// after
config.setProxyHost("ssh-gateway"); config.setProxyPort(3128); // CONNECT allowed to target:22
// or remove proxy:
// config.setProxyHost(null);
Defensive patterns

Strategy: try-catch

Validate before calling

// probe the proxy CONNECT path before connecting
try (Socket px = new Socket(config.getProxyHost(), config.getProxyPort());
     OutputStream os = px.getOutputStream(); InputStream is = px.getInputStream()) {
  os.write(("CONNECT " + config.getHost() + ":" + config.getPort() + " HTTP/1.1\r\nHost: "
      + config.getHost() + ":" + config.getPort() + "\r\n\r\n").getBytes(StandardCharsets.US_ASCII));
  os.flush();
  String resp = new String(is.readNBytes(1024), StandardCharsets.US_ASCII);
  if (!resp.contains(" 200 ")) throw new IllegalStateException("proxy CONNECT refused: " + resp.split("\r\n")[0]);
}

Type guard

boolean proxyConnectOk(String proxyHost, int proxyPort, String targetHost, int targetPort) {
  try (Socket px = new Socket(proxyHost, proxyPort)) {
    px.getOutputStream().write(("CONNECT " + targetHost + ":" + targetPort + " HTTP/1.1\r\n\r\n").getBytes());
    byte[] b = px.getInputStream().readNBytes(64);
    return new String(b).contains(" 200 ");
  } catch (IOException e) { return false; }
}

Try / catch

try {
  conn.connect();
} catch (SshConnectionException e) {
  if (e.getMessage().contains("HTTP proxy connection failed")) {
    log.error("Proxy {}:{} cannot tunnel to {}:{} — check CONNECT ACL/credentials",
      config.getProxyHost(), config.getProxyPort(), config.getHost(), config.getPort());
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling connect() with proxyHost/proxyPort configured when the proxy is down or unreachable, the proxy rejects CONNECT to the target port, proxy auth is required but not supplied, or the target is blocked by proxy ACLs.

Common situations: Corporate HTTP proxies that only allow CONNECT to 443 while the SSH target listens on 22, stale proxy credentials after rotation, misconfigured proxy port, or proxies that silently drop rather than reject the CONNECT tunnel.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13). Data as JSON: /api/errors/6e11fc9f3e14daec. Report an issue: GitHub.

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/core/ssh/mina/MinaSshConnection.java:171

    configureHttpProxyConnector();

    log( DEBUG, "Connecting to HTTP proxy: " + config.getProxyHost() + ":" + config.getProxyPort() );
    log( DEBUG, "Target SSH server (via proxy): " + config.getHost() + ":" + config.getPort() );

    return client.connect( config.getUsername(), config.getProxyHost(), config.getProxyPort() );
  }

  private void configureHttpProxyConnector() throws SshConnectionException {
    try {
      client.setClientProxyConnector( this::sendHttpConnectRequest );
    } catch ( Exception e ) {
      String errorMsg = "SSH over HTTP proxy connection failed: " + e.getMessage()
          + "\nProxy: " + config.getProxyHost() + ":" + config.getProxyPort()
          + "\nTarget: " + config.getHost() + ":" + config.getPort() + formatUserInfo()
          + "\nNote: Ensure HTTP proxy supports CONNECT method and target is reachable.";
      log( ERROR, errorMsg );
      throw new SshConnectionException( errorMsg, e );
    }
  }

  private String formatUserInfo() {
    return " (user: " + config.getUsername() + ")";
  }

  private void sendHttpConnectRequest( ClientSession session ) throws IOException {
    log( DEBUG, "Sending HTTP CONNECT proxy metadata" );

    String connectRequest = buildHttpConnectRequest();
    log( DEBUG, "HTTP CONNECT request: " + connectRequest.replace( "\r\n", "\\r\\n" ) );

    IoSession ioSession = session.getIoSession();
    ByteArrayBuffer buffer = new ByteArrayBuffer( connectRequest.getBytes() );
    ioSession.writeBuffer( buffer );

    log( DEBUG, "HTTP CONNECT request sent via proxy connector" );

View on GitHub (pinned to f3058517a1)