SSH隧道连接MongoDB出现SSL握手失败错误求助
解决SSH隧道连接MongoDB时的SSL握手失败问题
针对你遇到的pymongo.errors.ServerSelectionTimeoutError: SSL handshake failed: localhost:27017: [WinError 10054]错误,以下是几个针对性的修复步骤:
1. 移除本地Mongo连接的TLS配置
通过SSH隧道通信时,隧道本身已提供加密通道,无需再对本地到localhost的连接启用TLS。Mongo Atlas的证书仅对应其官方域名,连接localhost时会因域名不匹配触发SSL握手失败,即使开启tlsAllowInvalidCertificates=True也可能在Windows环境下报错。
修改MongoClient初始化代码:
client = pymongo.MongoClient( 'localhost', server.local_bind_port, username=params['username'], password=params['password'], retryWrites=False )
2. 避免端口冲突,使用随机本地端口
- 检查本地27017端口是否被其他服务占用(比如本地MongoDB实例),执行命令排查:
netstat -ano | findstr :27017 - 移除
local_bind_address配置,让sshtunnel自动分配未被占用的随机端口,确保隧道正常建立:with SSHTunnelForwarder( (SSH_HOST, SSH_PORT), ssh_username=SSH_USER, ssh_pkey=SSH_KEY, remote_bind_address=(MONGO_HOST, MONGO_PORT), ) as server: # 使用自动分配的端口连接 client = pymongo.MongoClient( 'localhost', server.local_bind_port, username=params['username'], password=params['password'], retryWrites=False )
3. 验证SSH隧道状态
在代码中添加隧道启动检查,确认隧道成功建立后再连接MongoDB:
with SSHTunnelForwarder( (SSH_HOST, SSH_PORT), ssh_username=SSH_USER, ssh_pkey=SSH_KEY, remote_bind_address=(MONGO_HOST, MONGO_PORT), ) as server: server.start() print(f"隧道已启动,本地绑定端口:{server.local_bind_port}") # 后续Mongo连接操作
4. 确保SSH私钥正确加载
如果SSH_KEY是文件路径,尝试手动加载私钥,避免sshtunnel加载异常:
from paramiko import RSAKey import pymongo from sshtunnel import SSHTunnelForwarder import json with open("config.json") as f: config = json.load(f) config_params = config["dev_db"] SSH_HOST = config_params['host_name'] SSH_PORT = 22 SSH_USER = config_params['host_username'] # 手动加载私钥 ssh_key = RSAKey.from_private_key_file(config_params['private_key']) MONGO_HOST = config_params["db_uri"] MONGO_PORT = 27017 params = config_params['params'] with SSHTunnelForwarder( (SSH_HOST, SSH_PORT), ssh_username=SSH_USER, ssh_pkey=ssh_key, remote_bind_address=(MONGO_HOST, MONGO_PORT), ) as server: client = pymongo.MongoClient( 'localhost', server.local_bind_port, username=params['username'], password=params['password'], retryWrites=False ) print(client) print(client.list_database_names())
内容的提问来源于stack exchange,提问作者AsyncKilla
相关产品推荐
相关产品推荐

