通过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




