如何解决HAProxy基于套接字的运行时API的 set ssl cert命令出现的错误:“该事务必须至少包含一个证书和一个私钥”?

后端开发 2026-07-08

我为我的站点使用HAProxy进行TLS终止。今天稍早我用一种简单的方法更新了证书:下载新证书,复制到我为HAProxy配置查找的路径,并使用 systemctl reload haproxy

这办法管用,但我对尝试Runtime API以实现真正的零停机、零丢包来更新证书很感兴趣。我跟随该链接以及Runtime API "安装" 指南(即一个配置改动)来创建一个socket。

然而,当我按照说明用 set ssl cert ... 上传新证书,然后再用 commit ssl cert ...,在“恰好与HAProxy启动时读取的my-site.pem文件完全相同”的情况下,出现题目所述的错误信息:

事务必须至少包含一个证书和一个私钥

我确认它确实包含证书(实际上包括到根的完整信任链!)以及私钥。并且这也是同一个HAProxy读取并正常使用的文件。

有何想法?

解决方案

如果你认真查看我链接的指令,你会发现确切的放置位置和返回存在与否非常重要:

echo -e "set ssl cert /etc/hapee-3.3/certs/site.pem <<\n$(cat ./new_certificate.pem)\n" | \
  sudo socat stdio tcp4-connect:127.0.0.1:9999

echo "commit ssl cert /etc/hapee-3.3/certs/site.pem" | \
  sudo socat stdio tcp4-connect:127.0.0.1:9999

如果.pem文件中存在任何空行,那么set命令就无法正常工作。

有趣的是,当有回车换行时,它并不会报错。

Runtime API将一个回车换行视为 set ssl cert 命令的“请求结束”。我的文件格式是

----BEGIN CERTIFICATE-----
first cert
----END CERTIFICATE-----

----BEGIN CERTIFICATE-----
second cert in chain, the blank line above causes the error
----END CERTIFICATE----
....

因此Runtime API只要输入到第一个 END CERTIFICATE 就通过,看到一个空行,就将其解读为“输入结束”,并且在流中根本没有登记其他内容。

随后当然是 commit ssl cert 命令失败,因为set命令只加载了链中的第一张证书,忽略了第一行之后的其余信任链以及私钥。

显然HAProxy的文件解析与Runtime API的套接字端点有显著差异。 事后看来并不特别令人意外,因为套接字只是接收字节,无法知道输入何时结束。因此基于套接字的Runtime API需要一个“输入结束”的信号。他们选择了类似HTTP的空行。相对地,文件解析器则直接读取整份文件(显而易见),忽略证书之间以及密钥之间的空行,因为它不需要除了到达文件末尾之外的“输入结束”信号。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章