通过Elastic Beanstalk的Django API连接LND节点时SSL握手失败求助
以下是我用于连接LND节点的Django Rest API代码:
@swagger_auto_schema(tags=['Payment']) def get(self, request): url = "<instance address>" macaroon = connect.encoded_hex TLS_PATH = 'tls.cert' headers = {"Grpc-Metadata-macaroon": macaroon} r = requests.get(url, headers=headers, verify=TLS_PATH) return Response(json.loads(r.text))
本地机器发送请求时可成功连接并获取节点信息,但部署到带负载均衡的Elastic Beanstalk环境(t3a.large型EC2实例)时请求失败,错误如下:
HTTPSConnectionPool(host='<host>', port=8080): Max retries exceeded with url: /v1/getinfo (Caused by SSLError(SSLError(1, '[SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:1131)')))
可能的解决方案
检查TLS证书的路径与权限
确保tls.cert文件存在于Elastic Beanstalk实例的指定路径下,且运行Django应用的进程用户(如webapp、nginx)拥有读取该文件的权限。建议使用绝对路径指定证书位置,避免相对路径导致的查找失败。强制指定兼容的TLS版本
LND节点可能禁用了旧版SSL协议,而Elastic Beanstalk环境中的Python默认SSL配置可能不匹配。可以显式指定TLS 1.2或更高版本:import ssl # 修改请求代码 r = requests.get(url, headers=headers, verify=TLS_PATH, ssl_version=ssl.PROTOCOL_TLSv1_2)若Python版本中
ssl_version已被弃用,可改用适配器方式:from requests.adapters import HTTPAdapter from urllib3.poolmanager import PoolManager import ssl class TLSAdapter(HTTPAdapter): def init_poolmanager(self, connections, maxsize, block=False): self.poolmanager = PoolManager( num_pools=connections, maxsize=maxsize, block=block, ssl_version=ssl.PROTOCOL_TLSv1_2 ) # 挂载适配器后发送请求 session = requests.Session() session.mount("https://", TLSAdapter()) r = session.get(url, headers=headers, verify=TLS_PATH)排查负载均衡的SSL配置
如果负载均衡启用了SSL终止,需确认其SSL策略是否与LND节点兼容,且是否正确转发了请求的SNI(Server Name Indication)信息。必要时可尝试绕过负载均衡,让EC2实例直接访问LND节点,验证问题是否由负载均衡导致。验证LND节点的访问控制与日志
检查LND节点的防火墙或访问控制列表,确保Elastic Beanstalk实例的公网IP被允许访问。同时查看LND节点的日志,获取握手失败的具体细节(如证书不匹配、SNI错误等),精准定位问题原因。在EC2实例上直接测试连接
登录到EC2实例,使用curl命令直接测试LND节点API,排除代码层面的问题:curl -v --cacert /path/to/tls.cert -H "Grpc-Metadata-macaroon: <your_macaroon_value>" https://<lnd_instance_address>:8080/v1/getinfo
内容的提问来源于stack exchange,提问作者Riccardo

