TL;DR
SAN 证书(Subject Alternative Name Certificate)是一种支持在单个证书中绑定多个域名(主域名和多个附加域名)的 SSL/TLS 证书,可同时为多个域名提供加密和身份验证服务。

acme.sh --issue -d zzxxxc.com -d *.zzxxxc.com --dns <dns_api>

就这? 就这!

0x1
vps 上面跑了一些 web 服务. 每个服务的tls证书之前是个让人头疼的问题. 后面发现 nginxproxy/acme-companion 管理 tls 证书, 使用 nginxproxy/nginx-proxy 作为反向代理服务, 配合 docker-compose 管理这些服务还是挺方便. 下面的 certs 都指的是 acme-companion 挂载到本地的文件夹,这个文件夹共享给 nginx-proxy 使用.

0x2
今天在折腾的时候发现想给博客添加 zzxxx.com 的证书以及www.zzxxxc.com 的证书,按照官方文档也就是添加两个环境变量的事情. 可是事情要是这么简单就不用写这篇文章了. nginx-proxy 读到 VIRTUAL_HOST 变量会创建两个 nginx virtual host,也就是 NGINX 配置文件里面的 server {},这没问题. nginxproxy/acme-companion 通过读取 LETSENCRYPT_HOST 来通过 acme.sh 脚本申请证书. 服务启动了, certs 文件夹中有 zzxxxc.com,*.zzxxxc.com 这两个域名对应的证书. 看起来也没啥问题. 浏览器访问 www.zzxxxc.com 正常, 访问 zzxxxc.com 显示证书不匹配,使用的 *.zzxxxc.com, 看起来事情并不简单.

typecho:
image: joyqi/typecho:nightly-php8.2-apache
restart: always
volumes:
  - ./typecho-data:/app
  - ./typecho-data/favicon.ico:/app/favicon.ico:ro
environment:
  - TZ=Asia/Shanghai
  - VIRTUAL_HOST=zzxxxc.com,www.zzxxxc.com
  - LETSENCRYPT_HOST=zzxxxc.com,*.zzxxxc.com
  - LETSENCRYPT_EMAIL=不给看

0x3 首先我们知道, nginx-proxy 通过 docker-gen 从环境变量获取信息,然后渲染 nginx.tmpl 文件,产生一个 default.conf 这个 nginx-proxy 使用的nginx 配置. 看 zzxxxc.com 这块的配置,

server {
server_name zzxxxc.com;
access_log /var/log/nginx/access.log vhost;
http2 on;
listen 443 ssl ;
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
ssl_certificate /etc/nginx/certs/zzxxxc.com.crt;
ssl_certificate_key /etc/nginx/certs/zzxxxc.com.key;
ssl_dhparam /etc/nginx/certs/zzxxxc.com.dhparam.pem;
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/nginx/certs/zzxxxc.com.chain.pem;
set $sts_header "";
if ($https) {
    set $sts_header "max-age=31536000";
   }
add_header Strict-Transport-Security $sts_header always;
location / {
    proxy_pass http://zzxxxc.com;
    set $upstream_keepalive true;
   }
}

查看 certs 目录下的那几个文件,他们其实都是软连接文件, 指向 wildcard.zzxxxc.com. 其他的子域名也是和zzxxxc.com 的 tls 配置一样.这就很难搞了, 我又不想改 acme-companion或者ginx-proxy. 经过一通谷歌搜索,其他可能得环境变量也是过了,就是不 work, 其中包括但不限于 CERT_NAME, LETSENCRYPT_SINGLE_DOMAIN_CERTS=true zzxxxc.com 证书始终不对.

0x4 既然 acme-companion 生成的不太对,那我们就自己生成. 使用 acme.sh 生成一个同时支持两个域名的证书.

acme.sh --issue -d zzxxxc.com -d *.zzxxxc.com --dns <dns_api>

然后使用 acme.sh --install-cert 命令安装证书到 certs 指定的目录下.然后测试,zzxxxc.com 的证书没问题了.

总结

  1. 主要是 nginx-proxy 里面的配置文件的模版太复杂了. 不太好改.改这个能很轻易的解决问题.
  2. acme-companion 这个创建证书软链接这块有点意思.估计是为了配合僵硬的模版吧.
最后修改:2025 年 06 月 14 日
如果觉得我的文章对你有用,请随意赞赏