终于有人把SSL证书申请做成了Python SDK:fastssl 项目体验记
兄弟们,我搞网站这么多年,最头疼的一件事就是给域名搞SSL证书。你说Let‘s Encrypt吧,免费是免费,但那套命令行工具、各种参数、环境变量,每次都得翻文档,稍微不注意就报错。特别是要搞泛域名证书,还要手动去DNS解析服务商那里加TXT记录,来回切换页面,眼睛都看花了。
直到前两天,我在逛GitHub的时候发现了一个叫 fastssl 的Python SDK项目,官网是 xinssl.com。好家伙,这玩意儿直接把证书申请、验证、下载变成几行Python代码了。我今天就用它申请了一个 *.test.api.xinssl.com 的泛域名证书,整个过程丝滑得像德芙巧克力。
它到底是个啥?
简单说,fastssl 就是 XinSSL 平台开放出来的Python工具包。你不需要在服务器上装乱七八糟的证书管理工具,也不用去搞什么复杂的ACME协议配置,只要在Python环境里 pip 装上这个包,拿着API Key就能干活了。它背后接了好几家CA机构,像Let‘s Encrypt、Google Trust Services、ZeroSSL都能选,自由度很高。
对我来说,最大的好处是——终于可以把证书申请流程写进自动化脚本里了。以前每次证书快到期,都得手动操作一遍,现在直接脚本跑起来,甚至还能集成到CI/CD流水线里,省心省力。
第一步:申请证书,拿到订单号
拿到API Key之后,我第一件事就是跑申请流程。下面这段代码就是干这个活的,它会把订单创建好,然后把需要配置的DNS验证信息打印出来给你看。
from fastssl import FastSSLClient
client = FastSSLClient(api_key="xssl_9b3ae12dc3dcf21ae64f8e22646f225f573f86df31d9545d")
domain = "*.test.api.xinssl.com"
# 1. 申请证书(创建订单)
order = client.create_certificate(
certificate_domain=domain,
channel_type="letsencrypt", # letsencrypt / google / zerossl
validation_method="dns", # dns / file
days=90,
)
if not order.get("success"):
raise SystemExit(f"申请失败:{order.get('message')}")
data = order["data"]
order_id = data["order_id"]
print(f"订单已创建:{order_id}")
print(f"品牌:{data.get('brand_name')}")
print(f"验证方式:{data.get('validate')}")
# 2. 获取验证值(DNS TXT 记录 或 文件验证信息)
challenge = client.get_challenge(order_id)
print("\n请按以下记录配置 DNS / 文件:")
for r in challenge.get("data", {}).get("records", []):
print(f" 类型:{r.get('auth_type')}")
print(f" 主机记录:{r.get('host_record')}")
print(f" 完整记录:{r.get('host_full')}")
print(f" 记录值:{r.get('value')}")
print()
print(f"配置完成后,运行 step2_verify.py,并传入该 order_id:{order_id}")
这里有个小细节,order_id 一定要保存好,后面验证和下载证书都得靠它。我一般直接复制粘贴到记事本里,或者干脆就把这个ID写死在下一阶段的脚本里,省事。
第二步:配置解析,触发验证
拿到DNS记录值之后,我就去我的域名解析控制台加了一条TXT记录。这里提醒一下各位,泛域名证书的验证记录主机名一般是 _acme-challenge 开头的,别搞错了。记录加好之后,等个一两分钟让解析生效,然后跑下面这个验证脚本。
import sys
from fastssl import FastSSLClient
client = FastSSLClient(api_key="xssl_9b3ae12dc3dcf21ae64f8e22646f225f573f86df31d9545d")
# 从命令行读取,或直接写死
order_id = sys.argv[1] if len(sys.argv) > 1 else "XSSL799BF68FA3724283"
# 触发 CA 校验域名权属
verify = client.verify_certificate(order_id)
if not verify.get("success"):
raise SystemExit(f"请求失败:{verify.get('message')}")
data = verify.get("data", {})
if data.get("verified"):
print(f"✓ 验证通过,证书已签发,状态:{data.get('status')}")
print(f" 到期时间:{data.get('expires_at')}")
print(f" 运行 step3_get.py 获取证书内容:py example_step3_get.py {order_id}")
else:
print(f"✗ 验证未通过,状态:{data.get('status')}")
print("请按以下 challenge 记录继续配置后重试 (若解析添加成功请稍等几分钟和再尝试):")
for r in data.get("challenge", []):
print(f" {r.get('auth_type')} | {r.get('host_record')} = {r.get('value')}")
第一次跑的时候我没等解析生效就急着验证了,结果返回的是验证未通过。后来等了两分钟再跑,马上就提示 ✓ 验证通过,证书已签发,那种感觉还是挺爽的。
第三步:下载证书,拿到PEM和私钥
验证通过之后,证书就已经在CA那边签好了。最后一步就是把证书内容拉回来,fastssl 提供了两种方式:一种是直接输出证书PEM、证书链和私钥的文本,另一种是直接下载ZIP包。我比较喜欢直接拿文本,方便放到Nginx或者Apache的配置文件里。
import sys from fastssl import FastSSLClient client = FastSSLClient(api_key="xssl_9b3ae12dc3dcf21ae64f8e22646f225f573f86df31d9545d")order_id = sys.argv[1] if len(sys.argv) > 1 else "XSSL799BF68FA3724283" # 1. 获取证书 PEM / Bundle / 私钥 cert = client.get_certificate(order_id) if not cert.get("success"): raise SystemExit(f"获取失败:{cert.get('message')}") data = cert["data"] print(f"订单:{data.get('order_id')}") print(f"域名:{data.get('domain')}") print(f"状态:{data.get('status')}") print(f"到期:{data.get('expires_at')}") print("\n证书(certificate):") print(data.get("certificate", "")) print("\n证书链(certificate_bundle):") print(data.get("certificate_bundle", "")) print("\n私钥(private_key):") print(data.get("private_key", "")) # 2. 也可下载 ZIP 包(取消注释即可) # client.download_certificate(order_id, f"{data.get('domain')}.zip") # print(f"\nZIP 已下载到 {data.get('domain')}.zip")
跑完这段脚本,证书和私钥就整整齐齐地打印在屏幕上了。我直接复制粘贴到服务器的证书文件里,重启一下Nginx,网站秒变绿锁。

几个我觉得很爽的点
用了一天下来,fastssl 有几个地方让我觉得特别舒服:
- 代码够简单:整个流程就是 申请 → 验证 → 下载,三步走,每个阶段就几行代码,几乎没有学习成本。
- 支持多家CA:可以在 Let‘s Encrypt、Google、ZeroSSL 之间切换,万一哪家出问题了还能随时换。
- 验证方式灵活:除了DNS验证,还支持文件验证,内网或者不方便改DNS的场景也能用。
- API Key管理方便:在 xinssl.com 后台可以随时创建和吊销Key,权限控制做得很细。
一点小建议
如果你跟我一样经常跟证书打交道,或者想把证书申请流程自动化,fastssl 绝对值得一试。尤其是配合上Python的定时任务,每三个月自动续签一次,再也不用半夜爬起来折腾证书了。
不过也要提醒一下,API Key 千万别直接写在代码里传到公开仓库,最好用环境变量或者配置文件单独管理。安全第一嘛。
好了,我要去把剩下的几个子域名也配上证书了。各位如果感兴趣,可以直接去 xinssl.com 看看,注册个账号就能拿到API Key开始玩耍了。下一篇我准备研究一下怎么把它集成到Docker容器启动脚本里,到时候再来分享。
order_id = sys.argv[1] if len(sys.argv) > 1 else "XSSL799BF68FA3724283"
# 1. 获取证书 PEM / Bundle / 私钥
cert = client.get_certificate(order_id)
if not cert.get("success"):
raise SystemExit(f"获取失败:{cert.get('message')}")
data = cert["data"]
print(f"订单:{data.get('order_id')}")
print(f"域名:{data.get('domain')}")
print(f"状态:{data.get('status')}")
print(f"到期:{data.get('expires_at')}")
print("\n证书(certificate):")
print(data.get("certificate", ""))
print("\n证书链(certificate_bundle):")
print(data.get("certificate_bundle", ""))
print("\n私钥(private_key):")
print(data.get("private_key", ""))
# 2. 也可下载 ZIP 包(取消注释即可)
# client.download_certificate(order_id, f"{data.get('domain')}.zip")
# print(f"\nZIP 已下载到 {data.get('domain')}.zip")