TL;DR

/etc/nginx/conf.d/ssl_map.conf
1
2
3
4
5
6
7
8
9
10
map $ssl_server_name $MatchedCert {
default '/etc/nginx/ssl/localhost_P256/localhost.crt';
~*^([^.]+)\.xiaoxuan010\.top$ '/etc/nginx/ssl/#.xiaoxuan010.top_xiaoxuan010.top_P256/fullchain.cer';
~*^([^.]+)\.r\.xiaoxuan010\.top$ '/etc/nginx/ssl/#.r.xiaoxuan010.top_r.xiaoxuan010.top_P256/fullchain.cer';
}
map $ssl_server_name $MatchedKey {
default '/etc/nginx/ssl/localhost_P256/localhost.key';
~*^([^.]+)\.xiaoxuan010\.top$ '/etc/nginx/ssl/#.xiaoxuan010.top_xiaoxuan010.top_P256/private.key';
~*^([^.]+)\.r\.xiaoxuan010\.top$ '/etc/nginx/ssl/#.r.xiaoxuan010.top_r.xiaoxuan010.top_P256/private.key';
}
/etc/nginx/conf.d/ssl.conf
1
2
3
4
5
server {
include /etc/nginx/conf.d/ssl_map.conf;
server_name example.xiaoxuan010.top;
...
}

问题

在一个 Nginx 实例中,持有多个域名通配符证书,传统做法需要为每个网站的 server 块配置证书路径,手动选择证书:

1
2
3
4
5
6
7
8
9
10
11
12
13
server {
server_name example.xiaoxuan010.top;
ssl_certificate '/etc/nginx/ssl/#.xiaoxuan010.top_xiaoxuan010.top_P256/fullchain.cer';
ssl_certificate_key '/etc/nginx/ssl/#.xiaoxuan010.top_xiaoxuan010.top_P256/private.key';
...
}

server {
server_name example.r.xiaoxuan010.top;
ssl_certificate '/etc/nginx/ssl/#.r.xiaoxuan010.top_r.xiaoxuan010.top_P256/fullchain.cer';
ssl_certificate_key '/etc/nginx/ssl/#.r.xiaoxuan010.top_r.xiaoxuan010.top_P256/private.key';
...
}

每次新增网站,都要手动配置长长的证书路径,非常繁琐。

解决方案

在 Nginx 配置目录中,创建一个 ssl_map.conf 文件,用于配置域名和证书的映射关系:

/etc/nginx/conf.d/ssl_map.conf
1
2
3
4
5
6
7
8
9
10
map $ssl_server_name $MatchedCert {
default '/etc/nginx/ssl/localhost_P256/localhost.crt';
~*^([^.]+)\.xiaoxuan010\.top$ '/etc/nginx/ssl/#.xiaoxuan010.top_xiaoxuan010.top_P256/fullchain.cer';
~*^([^.]+)\.r\.xiaoxuan010\.top$ '/etc/nginx/ssl/#.r.xiaoxuan010.top_r.xiaoxuan010.top_P256/fullchain.cer';
}
map $ssl_server_name $MatchedKey {
default '/etc/nginx/ssl/localhost_P256/localhost.key';
~*^([^.]+)\.xiaoxuan010\.top$ '/etc/nginx/ssl/#.xiaoxuan010.top_xiaoxuan010.top_P256/private.key';
~*^([^.]+)\.r\.xiaoxuan010\.top$ '/etc/nginx/ssl/#.r.xiaoxuan010.top_r.xiaoxuan010.top_P256/private.key';
}

这段代码创建了两个 map 块,分别用于匹配证书路径和私钥路径。$ssl_server_name 是 Nginx 内置变量,表示当前请求的域名。$MatchedCert$MatchedKey 这两个变量的值取决于 $ssl_server_name 的值,会根据正则表达式匹配域名,选择对应的证书和私钥路径。

之后,在每个网站配置的 server 块中,引入 ssl_map.conf 文件,并设置 server_name

/etc/nginx/conf.d/ssl.conf
1
2
3
4
5
server {
include /etc/nginx/conf.d/ssl_map.conf;
server_name example.xiaoxuan010.top;
...
}

大功告成,以后新增域名只需要在 ssl_map.conf 中添加两行映射关系即可,新增网站也不需要再配置证书路径。