很久不写东西了,自己都感觉自己太懒了,有深深的罪恶感了。 今天刚刚好遇到一个 Nginx 的问题,就硬逼着自己一定要写点什么记录一下。

今天在突然发现自己的博客打不开了,提示很奇怪,提示内容是 此网站无法提供安全连接 . 回想了一下这两样的的操作,就是昨晚给服务器加了一个 https 的站点。

假设1:SSL 证书过期了

刚刚开始以为是 SSL 证书问题,看了一下证书的到期,也还有几天就到期了。脆重新去签发一个证书试试,但是重新签发后,发现问题依旧。

再开 B 站点,都是正常的。唯独博客这个站点 A 有问题。

假设2:SSL 证书冲突

那么应该就是配置文件的问题了,首先想到的是是 SSL 证书冲突。

一般来说一个 IP 只能支持一个 SSL 证书,但是在 Nginx 我们可以通过开启 TLS SNI support 来让 Nginx 支持多SSL证书。

xxxx@xxxxxxx> /usr/local/nginx/sbin/nginx -V
nginx version: nginx/1.12.2
built with OpenSSL 1.0.1f 6 Jan 2014
TLS SNI support enabled
configure arguments: --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module --with-http_gzip_static_module --with-ipv6 --with-http_sub_module --with-stream --with-http_dav_module --add-module=/root/nginx-dav-ext-module-0.0.3

经过查看, Nginx 是已经开启了 TLS SNI support 了的。那么排除了 Nginx 不支持多个 SSL 证书的问题。

主观和事实需要经过辩证的

两个假设的问题都不对,只能来看余下的配置:

server
    {
     listen 443;
        server_name cong5.net www.cong5.net;
     index index.html index.htm index.php default.html default.htm default.php;
     root  /xxxx/xxxxx/public;

        ssl on;
        ssl_certificate /etc/ssl/fullchain.pem;
        ssl_certificate_key /etc/ssl/privkey.pem;
        ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout  10m;
        ssl_session_tickets on;
        ssl_stapling on;
        ssl_stapling_verify on;

        fastcgi_hide_header X-Powered-By;

        add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
        add_header Public-Key-Pins 'pin-sha256="FankyFNJUnHYf737yBalLqkC8bWTxZGTCeoMezFgNX0="; pin-sha256="YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg="; max-age=2592000; includeSubDomains';
        add_header X-Frame-Options DENY;
        add_header X-Content-Type-Options nosniff;

        #......
    }

从配置信息里面,我设置了 ssl_session_... 这部分是用来 Nginx 共享 session,优化 https 使用的,详细的解释可以看这个: ngx_http_ssl_module

经过一项项排除,发现这里面存在着 ssl_session_tickets 这一项是, ssl_session_tickets 是用来开启浏览器的 Session Ticket 缓存,联想到多个 https 站点,然后感觉有问题部分最大可能性就是它了。

到这一步呢开始进行配置文件对比, 发现博客开启了 Session Ticket: ssl_session_tickets on; ,然后 B 站点没有配置 ssl_session_tickets

把两个站点的 ssl_session_tickets 都进行关闭:

ssl_session_tickets off ;

然后重启 Nginx :

/etc/init.d/nginx restart

发现问题解决。

找 Google 大叔去

当我们在 Nginx 里面配置多个 https 的站点的时候,如果有一个站点开启了 ssl_session_tickets ,那么浏览器的就会缓存Session Ticket,然后在下一个请求使用当前的Session Ticket,提升性能;
而然后再新增站点的时候,无论是否设置了 ssl_session_tickets 了。那么都会导致浏览器复用前一个的Session Ticket。
于是就产生了 “此网站无法提供安全连接” 的问题。

信息来源:errors-from-browsers-with-ssl-session-tickets-off-nginx

问题的方法有2种:

第一种:如果 Nginx 的站点配置文件都包含在一个 http{ ... } 里面的,那么可以关闭 ssl_session_tickets: ssl_session_tickets off;

第二种:创建多个 http{ ... },然后在每个独立的 http{ ... } 里面就可以分别开启 ssl_session_tickets 了。

最后不得不再次感叹,懒的时候需要逼一逼才能有所产出的。