You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

通过SSH隧道连接EC2实例上的Elasticsearch失败求助:连接拒绝异常排查

排查EC2 Elasticsearch SSH隧道连接拒绝问题

首先,从你的报错和代码来看,核心问题出在SSH端口转发的配置错误,导致你的Elasticsearch客户端根本没通过正确的隧道连接到EC2上的ES服务。下面一步步帮你梳理和修复:

1. 修正SSH端口转发的核心错误

你的代码里这一行完全配错了目标端口:

int i = session.setPortForwardingL(30000, "localhost", 22, null);

这里你把本地30000端口转发到了EC2的22端口(SSH服务端口),而不是Elasticsearch的默认9200端口!

正确的写法应该是把本地端口转发到EC2实例内部的ES服务地址和端口:

// 将本地30000端口转发到EC2上的localhost:9200(ES默认端口)
int i = session.setPortForwardingL(30000, "localhost", 9200);

同时,你的RestHighLevelClient连接的是本地9200端口,但隧道是开在30000,所以客户端也要改成连接这个转发后的端口:

// 连接本地转发后的30000端口,而非直接9200
RestClientBuilder builder = RestClient.builder(new HttpHost("localhost", 30000));

2. 验证EC2上的Elasticsearch状态

在EC2实例上执行以下命令,确认ES服务正常运行且监听正确端口:

# 检查ES是否正常响应
curl localhost:9200

# 检查9200端口是否被监听
netstat -tulpn | grep 9200

如果ES没有监听localhost:9200(比如绑定了私有IP或0.0.0.0),那你需要把端口转发的目标地址改成对应的IP,比如:

session.setPortForwardingL(30000, "EC2_PRIVATE_IP", 9200);

3. 确认SSH会话是否成功建立

session.connect()之后,添加一个检查,确保SSH隧道确实建立了:

session.connect();
if (!session.isConnected()) {
    throw new RuntimeException("SSH会话连接失败");
}

如果SSH连接本身失败,那端口转发自然无效,会导致后面的ES连接被拒绝。

4. 检查EC2安全组配置

确保你的EC2安全组允许你的本地IP地址访问22端口(SSH服务),因为SSH隧道是基于这个连接建立的。ES的9200端口不需要对外公开,因为隧道是在EC2内部转发的。

修正后的完整代码示例

Session session = null;
String sshKeyFile = "/path/testSSH.pem";
try {
    JSch jsc = new JSch();
    jsc.addIdentity(sshKeyFile);
    // 替换成你的EC2实例公网IP或域名
    session = jsc.getSession("user", "ec2-instance-public-ip", 22);
    session.setConfig("StrictHostKeyChecking", "no");
    session.connect();
    
    // 确认SSH会话连接成功
    if (!session.isConnected()) {
        throw new RuntimeException("Failed to establish SSH session");
    }

    // 修正端口转发:本地30000 -> EC2内部localhost:9200
    int forwardedPort = session.setPortForwardingL(30000, "localhost", 9200);
    System.out.println("Forwarded local port " + forwardedPort + " to EC2 ES port 9200");

    final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
    credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("user_name", "pass"));
    
    // 连接本地转发后的30000端口
    RestClientBuilder builder = RestClient.builder(new HttpHost("localhost", 30000));
    builder.setHttpClientConfigCallback(a -> a.setDefaultCredentialsProvider(credentialsProvider));
    RestHighLevelClient client = new RestHighLevelClient(builder);

    GetBasicStatusResponse response = client.license().getBasicStatus(RequestOptions.DEFAULT);
    System.out.println("Is eligible for basic license: " + response.isEligibleToStartBasic());
    System.out.println(response.toString());

    // 记得关闭资源
    client.close();
    session.disconnect();
} catch (JSchException | IOException e) {
    e.printStackTrace();
}

总结

你之前的错误本质是端口转发的目标指向错误,同时客户端连接的端口和转发端口不匹配,导致请求无法到达EC2上的ES服务。按照上面的步骤修正后,应该就能解决连接拒绝的问题了。

内容的提问来源于stack exchange,提问作者Imy Gramy

火山引擎 最新活动