今天线上业务由于SSL证书问题导致业务异常,得知是因为SSL证书问题,登录到阿里控制台查看之前的通配符 *.erlang.com(保密需要,给域名来个化名)快到期,所以同事手动吊销,然后使用了阿里免费的SSL证书。免费的唯一好处就是不花钱,但是不提供免费的通配符SSL证书,所以需要将*.erlang.com的所有子域名都手动申请证书,将今天受影响的业务的域名plugin.erlang.com给遗漏了,导致的业务异常。用户访问plugin.erlang.com时某些业务无法访问。
折腾了挺长时间,事后回想起来还是挺容易跳坑的,所以想记录下来, 一是留作以后查看,二来也许可以帮助一帮跳坑的小伙伴。
首先去阿里云控制台申请免费的SSL证书,第一次申请是20个免费的,所以基本够用,就是麻烦些!!
环境介绍:
单台服务器上使用nginx跑了三个域名,分别为plugin.erlang.com,spider.erlang.com,asset.erlang.com
这三个域名在使用免费SSL证书时遗漏。没有申请,然后直接将\*.erlang.com这个通配符SSL证书给注销,导致现在这三个业务受影响。
解决:
1.首先使用阿里免费的SSL证书,申请这三个域名的SSL证书,然后下载到本地电脑后给文件改名并做区分
如:将下载后的证书改名以容易区分
plugin.erlang.com.pem
plugin.erlang,com.key
spider.erlang.com.pem
spider.erlang,com.key
asset.erlang.com.pem
asset.erlang.com.key
2.本来想的挺简单,以为直接在这三个域名的虚拟主机文件中直接指定 ssl_certificate /etc/nginx/xxx/xxx.pem; ##证书名称.pem ssl_certificate_key /etc/nginx/xxx/xxx.key; ##证书名称.key指定各自的文件路径就完美解决了,但是接着问题来了~~~
之前使用的是通配符SSL。也就是说这三个域名共用一个整数,然后直接在/etc/nginx/目录中写了一个ssl_erlang.com.conf文件。
文件内容如下:
ssl on;
ssl_certificate /etc/nginx/ssl/fullchain.pem; #(证书公钥)
ssl_certificate_key /etc/nginx/ssl/privkey.key; #(证书私钥)
ssl_session_timeout 5m;
ssl_protocols TLSv1.1 TLSv1.2;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_stapling on;
ssl_stapling_verify on;
ssl_prefer_server_ciphers on;
ssl_stapling_verify on;
ssl_session_cache shared:SSL:20m;
add_header Strict-Transport-Security max-age=63072000;
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
看到这里,这个文件应该是专门指定SSL证书位置,然后被nginx.conf直接引用,公用给这三个域名。
所以现在使用免费SSL,需要给三个域名的虚拟主机文件分别指定各自的证书。然后将改文件所有注释。
3.三个域名指定各自的SSL证书位置
### cat plugin.erlang.com.conf
server {
listen 443 ssl;
server_name plugin.erlang.com;
ssl_certificate /etc/nginx/ssl/plugin.erlang.com.pem; ##证书名称.pem
ssl_certificate_key /etc/nginx/ssl/plugin.erlang.com.key; ##证书名称.key
ssl_session_timeout 5m;
ssl_protocols TLSv1.1 TLSv1.2;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_prefer_server_ciphers on;
}
### cat spider.erlang.com.conf
server {
listen 443 ssl;
server_name plugin.erlang.com;
ssl_certificate /etc/nginx/ssl/spider.erlang.com.pem; ##证书名称.pem
ssl_certificate_key /etc/nginx/ssl/spider.erlang.com.key; ##证书名称.key
ssl_session_timeout 5m;
ssl_protocols TLSv1.1 TLSv1.2;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_prefer_server_ciphers on;
}
### cat asset.erlang.com.conf
server {
listen 443 ssl;
server_name plugin.erlang.com;
ssl_certificate /etc/nginx/ssl/asset.erlang.com.pem; ##证书名称.pem
ssl_certificate_key /etc/nginx/ssl/asset.erlang.com.key; ##证书名称.key
ssl_session_timeout 5m;
ssl_protocols TLSv1.1 TLSv1.2;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_prefer_server_ciphers on;
}
4.修改完成后,nginx -t检查nginx语法
nginx: [emerg] no "ssl_certificate" is defined for the "listen ... ssl" directive in /etc/nginx/conf.d/plugin.erlang.com.conf:33
意思是ssl_certificate没有配置,可是ssl_certificate和ssl_certificate_key都已经配置,
网上搜索ssl_certificate必须在http段中先定义, 在server段才配置ssl_certificate已经来不及了,
检查我的nginx配置,ssl_certificate确实只在server段定义,而在http段未定义。
于是将/etc/nginx/目录中ssl_erlang.com.conf文件修改为如下:
ssl on;
ssl_certificate /etc/nginx/ssl/plugin.erlang.com.pem; #(证书公钥) 该行修改
ssl_certificate_key /etc/nginx/ssl/plugin.erlang.comkey; #(证书私钥) 该行修改
ssl_session_timeout 5m;
ssl_protocols TLSv1.1 TLSv1.2;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_stapling on;
ssl_stapling_verify on;
ssl_prefer_server_ciphers on;
ssl_stapling_verify on;
ssl_session_cache shared:SSL:20m;
add_header Strict-Transport-Security max-age=63072000;
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
修改后访问这三个域名,提示错误,因为这里引用的是plugin.erlang.com的SSL证书,所以访问其他两个时网页会提示危险:要访问的网站与证书不符!!
5.事后分析
为什么我会要把ssl_certificate放到server段?
因为申请的证书是每个子域名的证书,所以并不是全站试用,所以感觉没必要放到http中作为全局配置,只在子域名的单独配置文件中声明了。
既然这样,ssl_certificate还有必要写到server段吗?
答案是肯定的,比如我的情况就必须在server段写ssl_certificate,
因为我几个子域名的SSL证书都不同,必须在每个server不同的域名下指定不同的证书。 而且事实证明,虽然在http声明了全局的SSL证书,
但是可以再不同的server段为不同子域名再重写SSL证书路径,所以在我的配置中, http中声明的全局SSL证书只是个打酱油的,
只是为了不让nginx报上述no “ssl_certificate” is defined的错误,真正生效的证书配置还是在server段。