You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python Socket服务器上配置多SSL证书及SNI支持

Python SSL实现多域名SNI配置方案

问题根源

你之前尝试的两种方法都无法实现多域名证书动态切换:重复调用load_cert_chain会直接覆盖之前的证书配置;合并证书文件后,服务器只会优先使用第一个匹配的证书,无法根据客户端请求的域名动态选择。

SNI实现步骤

Python的ssl模块从3.2版本开始支持服务器端SNI配置,核心是通过自定义SNI回调函数,在SSL握手阶段捕获客户端发送的域名,动态加载对应证书。

1. 预加载所有域名的证书上下文

先把每个域名的证书和密钥对应起来,预生成各自的SSL上下文:

import ssl
import socket

# 映射域名到对应的证书、密钥文件路径
domain_cert_map = {
    "domain1.com": ("domain1_cert.pem", "domain1_key.pem"),
    "domain2.com": ("domain2_cert.pem", "domain2_key.pem")
}

# 为每个域名预创建并加载SSL上下文
domain_contexts = {}
for domain, (cert_path, key_path) in domain_cert_map.items():
    ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
    ctx.load_cert_chain(certfile=cert_path, keyfile=key_path)
    domain_contexts[domain] = ctx

2. 编写SNI回调函数

这个函数会在SSL握手的Client Hello阶段被触发,根据客户端发送的域名返回对应的SSL上下文:

def sni_handler(sock, server_name, ssl_context):
    # 根据请求的域名匹配对应的上下文
    if server_name in domain_contexts:
        sock.context = domain_contexts[server_name]
    else:
        # 域名未匹配时,可返回默认证书或直接终止连接
        sock.context = domain_contexts.get("domain1.com")  # 用domain1作为默认 fallback

3. 配置并启动SNI服务器

创建基础套接字,绑定SNI回调后再进行SSL包装:

# 创建TCP监听套接字
server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_sock.bind(("0.0.0.0", 443))
server_sock.listen(5)

# 创建基础SSL上下文(仅作为占位,实际会被SNI回调替换)
base_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
# 绑定SNI回调函数
base_context.sni_callback = sni_handler

print("SNI SSL Server running on port 443...")

while True:
    client_sock, client_addr = server_sock.accept()
    # 执行SSL握手,此时SNI回调会自动触发并切换上下文
    ssl_sock = base_context.wrap_socket(client_sock, server_side=True)
    # 处理SSL连接逻辑
    try:
        req_data = ssl_sock.recv(1024)
        print(f"Received from {client_addr}: {req_data.decode()}")
        ssl_sock.send(b"Response from SNI-enabled server")
    finally:
        ssl_sock.close()

关于"提前获取客户端证书需求"的说明

客户端的SNI信息是在SSL握手的Client Hello阶段发送的,这个过程发生在wrap_socket调用内部,因此无法在wrap_socket执行前获取到服务器名称。Python的SNI回调机制正是在握手过程中捕获该信息,动态替换SSL上下文,从而实现多域名证书的动态切换。


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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 17:27:30