连接AWS EC2上MongoDB遇SocketTimeoutException,求Java配置PEM及用户名方法
解决AWS EC2上MongoDB Java连接超时及PEM认证配置问题
嘿,遇到MongoDB连接超时和Java里不知道怎么配置PEM证书、用户名认证的问题是吧?我帮你一步步捋清楚解决方案~
一、先搞定「java.net.SocketTimeoutException: connect timed out」超时问题
你能用Putty连EC2,说明EC2本身网络是通的,但MongoDB连不上,大概率是这几个环节出了问题:
- EC2安全组没开放27017端口:Putty用的是22端口,和MongoDB的27017完全不搭。赶紧去AWS控制台的EC2安全组里,添加入站规则——允许你Java客户端所在的IP(测试阶段可以临时用
0.0.0.0/0,但生产环境绝对别这么干)访问27017端口(TCP协议)。 - MongoDB绑定地址限制了外部访问:打开EC2上的MongoDB配置文件(一般是
/etc/mongod.conf),找到net.bindIp配置项,默认可能是127.0.0.1,这会导致只有EC2本地能访问MongoDB。改成0.0.0.0(允许所有IP访问)或者EC2的私有IP,然后重启MongoDB服务:sudo systemctl restart mongod。 - EC2本地防火墙拦截了27017端口:如果EC2上开了iptables或者ufw这类防火墙,得确保27017端口被放行。比如用iptables的话,执行
sudo iptables -A INPUT -p tcp --dport 27017 -j ACCEPT,然后保存规则。
二、Java代码里配置PEM证书及用户名认证
你原来的代码只是简单的裸连接,没配置SSL和认证信息,肯定没法通过MongoDB的安全校验。下面分两种常见情况给你代码示例:
情况1:MongoDB直接开放27017端口并启用SSL认证
如果你的MongoDB已经配置了SSL(用PEM证书做身份验证),那Java代码需要加载PEM证书并配置SSL上下文,同时带上用户名密码:
import com.mongodb.MongoClient; import com.mongodb.MongoClientOptions; import com.mongodb.MongoCredential; import com.mongodb.ServerAddress; import com.mongodb.DB; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; import java.io.FileInputStream; import java.security.KeyStore; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.Arrays; public class MongoDbSslConnection { public static void main(String[] args) { try { // 1. 加载你的PEM证书文件 CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); FileInputStream pemInputStream = new FileInputStream("/绝对路径/your-mongo-cert.pem"); X509Certificate cert = (X509Certificate) certFactory.generateCertificate(pemInputStream); // 2. 创建临时密钥库并添加证书 KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(null, null); keyStore.setCertificateEntry("mongo-trust-cert", cert); // 3. 初始化信任管理器 TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(keyStore); // 4. 创建SSL上下文 SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, tmf.getTrustManagers(), null); // 5. 配置MongoDB客户端的SSL选项 MongoClientOptions clientOptions = MongoClientOptions.builder() .sslEnabled(true) .sslContext(sslContext) .build(); // 6. 设置MongoDB认证信息(用户名、认证数据库、密码) MongoCredential credential = MongoCredential.createCredential( "你的MongoDB用户名", "userDB", // 和你要连接的数据库一致 "你的密码".toCharArray() ); // 7. 建立连接 ServerAddress serverAddr = new ServerAddress("ec2-xx-xx-xxx-xx.xx-xxxx-1.xxxxxx.amazonaws.com", 27017); MongoClient mongoClient = new MongoClient(serverAddr, Arrays.asList(credential), clientOptions); // 测试连接 DB db = mongoClient.getDB("userDB"); System.out.println("成功连接到数据库:" + db.getName()); // 记得用完关闭连接 mongoClient.close(); } catch (Exception e) { e.printStackTrace(); } } }
情况2:通过SSH隧道访问MongoDB(更安全,适合生产环境)
如果你的MongoDB还是绑定127.0.0.1(只允许EC2本地访问),你用Putty是通过SSH隧道转发端口来访问的,那Java里也需要先建立SSH隧道,再连接本地转发的端口:
首先要引入JSch库(用来实现SSH隧道),然后代码如下:
import com.mongodb.MongoClient; import com.mongodb.DB; import com.jcraft.jsch.JSch; import com.jcraft.jsch.Session; import java.util.Properties; public class MongoDbSshTunnelConnection { public static void main(String[] args) { Session sshSession = null; MongoClient mongoClient = null; try { // 1. 配置SSH连接信息 JSch jsch = new JSch(); // 加载你的EC2 PEM密钥文件 jsch.addIdentity("/绝对路径/your-ec2-key.pem"); // SSH用户名一般是ec2-user(Amazon Linux)或者ubuntu(Ubuntu系统) sshSession = jsch.getSession("ec2-user", "ec2-xx-xx-xxx-xx.xx-xxxx-1.xxxxxx.amazonaws.com", 22); // 跳过主机密钥校验(测试用,生产环境建议配置正确的校验) Properties config = new Properties(); config.put("StrictHostKeyChecking", "no"); sshSession.setConfig(config); // 建立SSH连接 sshSession.connect(); // 2. 端口转发:本地27017端口转发到EC2的127.0.0.1:27017 int localPort = 27017; String remoteHost = "127.0.0.1"; int remotePort = 27017; sshSession.setPortForwardingL(localPort, remoteHost, remotePort); // 3. 连接MongoDB(此时连本地的27017端口即可) mongoClient = new MongoClient("localhost", localPort); DB db = mongoClient.getDB("userDB"); System.out.println("成功通过SSH隧道连接到数据库:" + db.getName()); } catch (Exception e) { e.printStackTrace(); } finally { // 关闭资源 if (mongoClient != null) { mongoClient.close(); } if (sshSession != null && sshSession.isConnected()) { sshSession.disconnect(); } } } }
最后提醒
- 生产环境别用
0.0.0.0/0开放27017端口,一定要限制为固定的客户端IP。 - 如果用SSH隧道,记得给JSch库添加依赖(比如Maven里加
com.jcraft:jsch:0.1.55)。 - 确认MongoDB已经开启了认证(在
mongod.conf里设置security.authorization: enabled),不然用户名密码配置了也没用。
内容的提问来源于stack exchange,提问作者weknowthe
相关产品推荐
相关产品推荐

