Tomcat、Spring Boot 的证书还在手动换?教你自动续期和部署

简介: Java 应用换证书比 Nginx 多两步:转成 keystore,再重启应用。证书有效期缩短到 100 天、47 天以后,这两步也得自动化。别名、密码、重启检查有一处没处理好,应用就会在续期后第一次重启时起不来。

Java 应用换证书比 Nginx 多两步。Nginx 拿到 PEM 文件,reload 一下就生效;Tomcat 和 Spring Boot 通常读的是 keystore(.jks 或 .p12),每次续期都要从云厂商控制台下载 Tomcat 格式的证书,或者自己用 openssl pkcs12、keytool 把证书和私钥转成 keystore,替换文件,再重启应用。证书一年换一次时,这些步骤手动做没什么问题。现在新签发的公开证书最长只有 200 天,2027 年 3 月 15 日起降到 100 天,2029 年 3 月 15 日起降到 47 天,到那时差不多每个月都要换一次。

这篇讲 Java 应用的证书怎么做成自动续期和部署:先确认证书由谁加载,再分别说 Tomcat 和 Spring Boot 的配置,然后是换证时最常见的三个错误,最后是两种自动化做法:自己写 Certbot hook,或者交给 LapseZero 托管。

先确认证书配在 Nginx 还是 Java 应用上

很多 Java 项目前面有 Nginx 或负载均衡,由它们处理 HTTPS,Tomcat 只监听 8080。这种情况下证书和 Java 没有关系,按 Nginx 或云产品的方式续期就行,keystore 那一套用不上。

判断方法很直接:Tomcat 看 conf/server.xml 里有没有带 SSLHostConfig 的 Connector,Spring Boot 看 application.yml、application.properties 和启动参数里有没有 server.ssl。都没有,一般就是 Java 应用不加载证书。下面的内容只针对 Java 自己加载证书的情况。

Tomcat 的证书配置

Tomcat 8.5 以后(包括 9、10、11)的写法相同,都是在 Connector 里放一个 SSLHostConfig:

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" SSLEnabled="true">
  <SSLHostConfig>
    <Certificate certificateKeystoreFile="/opt/tomcat/ssl/tomcat.p12"
                 certificateKeystorePassword="changeit"
                 certificateKeystoreType="PKCS12" />
  </SSLHostConfig>
</Connector>

自动化只关心 Certificate 上的几个属性:

  • certificateKeystoreFile:keystore 文件路径,续期后的新文件就写到这里。
  • certificateKeystorePassword:keystore 密码,新文件必须用同一个密码生成。
  • certificateKeystoreType:不写时默认是 JKS。现在建议用 PKCS12,并显式写出来。
  • certificateKeyAlias:示例里没写。不写时 Tomcat 用 keystore 里读到的第一个密钥,keystore 里只有一张证书时这样最省事。

如果不想转 keystore,Tomcat 8.5 起也能直接读 PEM 文件,用 certificateFile、certificateKeyFile、certificateChainFile 三个属性分别指向证书、私钥和中间证书。已经在用 keystore 的不必为了自动化改成 PEM,两种都能自动部署。

文件换好以后要让 Tomcat 重新加载。最简单的是重启,代价是重启期间 HTTPS 不可用:一台小内存测试机上,Tomcat 10.1 正常重启时 HTTPS 中断了大约 7 秒。不想中断可以用 Manager 应用的 sslReload,它只重新读取证书和私钥文件,不重新解析 server.xml:

curl -fsS -u deployer:password "http://localhost:8080/manager/text/sslReload" | grep -q '^OK'

用这个命令要先启用 Manager 应用,并给账号分配 manager-script 角色。Manager 执行失败时返回的是以 FAIL 开头的文本,curl 本身仍然成功,所以要用 grep 检查结果,失败时命令才会返回非 0。

Spring Boot 的证书配置

Spring Boot 内嵌 Tomcat,证书写在应用配置里:

server:
  port: 8443
  ssl:
    key-store: file:/opt/app/ssl/app.p12
    key-store-type: PKCS12
    key-store-password: changeit

Spring Boot 2.7 和 3.x 都是这个写法。这里最需要注意的是 file:。很多教程写的是 classpath:keystore.p12,keystore 和代码一起打进 jar 包,换证书就要重新打包发布,没法在服务器上自动替换。要自动化,先把 keystore 挪到 jar 外面,改成 file: 开头的绝对路径。

Spring Boot 同样可以直接用 PEM:server.ssl.certificate 指向证书链,server.ssl.certificate-private-key 指向私钥。

Spring Boot 3.2 起可以不重启换证。把证书配置成 SSL bundle 并打开 reload-on-update,Spring Boot 会在后台监视文件,内容变了就重新加载:

spring:
  ssl:
    bundle:
      jks:
        web:
          reload-on-update: true
          keystore:
            location: file:/opt/app/ssl/app.p12
            password: changeit
            type: PKCS12
server:
  ssl:
    bundle: web

bundle 的类型名叫 jks,但里面也能放 PKCS12 文件,由 type 决定。server.ssl.bundle 不能和 server.ssl.key-store 这些属性混用,改成 bundle 时要把原来的删掉。版本低于 3.2 的只能重启。Spring Boot 应用启动比 Tomcat 慢,同一台测试机上一个很小的 Spring Boot 3.5 应用重启时,HTTPS 中断约 15 秒;业务应用通常更久。

换证时最常见的三个错误

别名对不上

很多 Tomcat 教程生成 keystore 时用 keytool -alias tomcat,配置里也跟着写 certificateKeyAlias="tomcat"(Spring Boot 是 server.ssl.key-alias: tomcat)。续期后换一个工具生成 keystore,别名很可能变了,应用重启时就会报:

java.io.IOException: Alias name [tomcat] does not identify a key entry

这个错误平时看不到,因为应用正在运行,用的是内存里的旧证书。等到续期后第一次重启,应用才起不来。解决方法有两个:生成新 keystore 时指定同一个别名(openssl pkcs12 -export 加 -name tomcat),或者在 keystore 里只有一张证书时删掉配置里的别名。

密码对不上

新 keystore 的密码必须和配置里的 certificateKeystorePassword 或 server.ssl.key-store-password 一致,否则启动时报:

Failed PKCS12 integrity checking

从云厂商下载的 JKS,私钥密码有时和 keystore 密码不同,配置里会多一项 certificateKeyPassword(Spring Boot 是 server.ssl.key-password)。换成自动生成的 PKCS12 后,私钥密码和 keystore 密码相同,这一项要删掉,或者改成和 keystore 密码一致。

重启“成功”了,应用却没起来

这一个最容易漏。用 systemd 管理的 Java 服务大多是 Type=simple,systemctl restart 在进程启动后就返回,不等 Java 加载完证书。别名或密码错了的时候,systemctl restart 照样返回 0:Tomcat 进程还在,HTTPS Connector 却没有起来;Spring Boot 则是过几秒自己退出。部署脚本看到命令成功,以为换证完成,其实服务已经挂了。

所以重启命令要等到 HTTPS 真正可用才算成功,等不到就返回非 0,让自动化流程知道出了问题:

#!/bin/sh
# 用法:restart-and-wait.sh <服务名> <HTTPS 端口>
set -eu
systemctl restart "$1"
for attempt in $(seq 1 30); do
  if curl --insecure --fail --silent --max-time 1 "https://127.0.0.1:$2/" >/dev/null; then
    exit 0
  fi
  sleep 1
done
echo "$1 did not become HTTPS-ready" >&2
exit 1

--insecure 只用于本机检查端口是否起来;探测的路径换成你的应用里不需要登录、能返回 200 的地址。

第一次自动化时还要检查文件权限:Java 进程通常以非 root 用户运行,新写入的 keystore 文件要让这个用户能读。

自己写脚本:Certbot 的 deploy hook

证书由本机的 Certbot 签发时,可以把转换、替换和重启写进 deploy hook。Certbot 每次续期成功后执行它,并通过 RENEWED_LINEAGE 传入证书目录:

#!/bin/sh
set -eu
openssl pkcs12 -export \
  -in "$RENEWED_LINEAGE/fullchain.pem" \
  -inkey "$RENEWED_LINEAGE/privkey.pem" \
  -name tomcat -passout file:/etc/tomcat/keystore.pass \
  -out /opt/tomcat/ssl/tomcat.p12.new
mv /opt/tomcat/ssl/tomcat.p12.new /opt/tomcat/ssl/tomcat.p12
/usr/local/bin/restart-and-wait.sh tomcat 8443

用 acme.sh 时,先用 --install-cert 指定证书链和私钥的输出路径,把脚本里的 $RENEWED_LINEAGE/... 换成这两个路径,再通过 --reloadcmd 调用脚本。

一台服务器、一个应用时,这样就够了。服务器和应用多了以后,下面几件事都要自己补:

  • 失败恢复:上面的脚本在重启失败时,旧 keystore 已经被覆盖。要先备份,失败时换回去再重启,否则应用就停在报错状态等人处理。
  • 多台分发:Certbot 在哪台机器上续期,新证书就只在哪台。多台服务器要么各装一套 Certbot 和 hook,要么自己把证书同步过去,每台执行一遍。
  • 失败通知:Certbot 默认不发通知,hook 失败只记在日志里,没人看日志就不会知道。

用 LapseZero 自动部署到 Java 应用

LapseZero 是一个托管服务,负责签发证书、到期前自动续期,并部署到服务器和云产品上。证书是免费的 DV 证书,支持通配符,通过 DNS 验证签发:可以填 DNS 服务商的 API 密钥,也可以只加一条 CNAME。现在用的证书不用迁移,第一次部署就会把新证书写到原来的 keystore 路径上。

一台 Java 服务器只需要配置一次:添加部署目标时选「服务器」,软件选 Tomcat 或 Spring Boot,然后填三项:

  • 证书路径:配置里的 keystore 路径,Spring Boot 去掉 file: 前缀。
  • Keystore 密码:和配置里的一致。配置里写了别名的,把同一个别名也填上。
  • 部署后命令:上面的 restart-and-wait.sh。

服务器可以通过 SSH 连接,也可以装一个部署客户端,不用开放入站端口。私钥和密码都加密保存。

之后每次续期,LapseZero 自动生成 PKCS12 文件、写到原路径、执行部署后命令,前面说的三个错误都不用再操心:keystore 按你填的密码和别名生成,不会对不上;命令失败(比如应用 30 秒内没起来)时,自动换回旧 keystore 再执行一次命令,应用继续用旧证书,通知里会写明已回滚。在「生效检查」里填上应用的 HTTPS 地址,部署后还会确认线上已经换成新证书。

应用部署在多台服务器上时,每台服务器算一个部署位置,填法相同。前面的 Nginx、负载均衡和云产品也在同一个地方部署同一张证书,不用在每台机器上维护一套 hook。

目录
相关文章
|
云安全 安全 网络安全
|
15天前
|
JSON 程序员 数据格式
最新版Notepad++下载、安装、配置保姆级教程(附官网安装包)
Notepad++ 是一款免费开源、轻量快速的 Windows 文本编辑器,支持多标签、语法高亮、代码折叠与宏录制,体积小、启动快、资源占用低,兼容 x64/x32/ARM 架构,是程序员和文字工作者的高效利器。
3690 0
|
8天前
|
JavaScript 安全 前端开发
Nodejs Brotli decoder 代码执行漏洞 (CVE-2026-111497)10629
Node.js发布安全更新修复Brotli解码器高危RCE漏洞(CVE-2026-111497),建议受影响版本用户立即升级。
2048 2
|
14天前
|
人工智能 API 开发工具
DeepSeek Harness 神插件:白嫖 13 家大厂模型
`dsh-our-free-model` 是 DeepSeek Harness 神级插件:零配置、零API Key、零账号,聚合13家大厂免费模型(含DeepSeek V4.1 Flash、Kimi K3等),支持本地网关、用量看板与自动降级,真正实现“白嫖即用”。
2501 46
|
11天前
|
Web App开发 人工智能 前端开发
2026 年 AI 浏览器怎么选?Ego Lite、Tabbit、Chrome DevTools MCP 深度对比,开发者到底该用哪个?
2026年AI浏览器选型指南:Ego Lite专注多Agent协同(Mac优先),Tabbit国产首选,原生支持Windows与Codex控制;Chrome DevTools MCP非浏览器而是开发者利器,深度集成Console/Network/Performance调试能力,让AI真正“看懂并验证”前端代码。
1479 3
|
9天前
|
开发者 索引
DeepSeekHarness大肥鱼自带插件市场了?加个地址就能用
Open Plugin Market 是一个开放插件索引平台,收录800+优质DSH插件,支持分类浏览、智能推荐与随机发现。无需安装市场,粘贴索引地址即可一键接入,网页版直访 dshopen.org,助力小开发者被看见。(239字)
1983 1
DeepSeekHarness大肥鱼自带插件市场了?加个地址就能用
|
7天前
|
人工智能 Linux API
Magpie, 轻量本地AI网关!免费Token用不完!
Magpie 是开源AI编程模型调度网关,上线一月获1.8万Star。它通过本地高性能网关统一托管多平台API密钥、账号与免费额度,实现跨Agent的模型秒级切换、静默额度轮换与资源复用,显著降低碎片化管理成本。(239字)
Magpie, 轻量本地AI网关!免费Token用不完!
|
8天前
|
安全 应用服务中间件 Go
PHP2Shell 漏洞拆解:WordPress 与 nginx 为何中招
PHP2Shell 双 RCE 已遭在野利用:WordPress、Drupal 全在射程内,nginx 其实另有洞。拆成因与修复顺序
PHP2Shell 漏洞拆解:WordPress 与 nginx 为何中招
|
4天前
|
人工智能 安全 API
2026 年阿里云双 11|百炼大模型 API 指南:免费 Token 领取、API Key 生成、代码调用实战教程
对于零基础的AI开发者、技术爱好者和小型开发团队来说,低成本、低门槛调用主流大模型接口,是开启AI项目原型开发的必经之路。百炼大模型服务平台汇集了百余款主流大模型,面向新用户提供大规模免费推理额度,不需要预先充值,即可完成文本生成、逻辑推理、代码编写、多模态解析等各类开发验证工作。很多新手在初次接触平台时,常常遇到不清楚免费额度规则、不知道如何生成API‑Key、环境配置错误、调用接口持续报错等一系列问题。
612 1

热门文章

最新文章