0%

HTTPS泛域名证书申请之二-Nginx配置

在申请成功https的泛域名证书账号,接下来就是为主域名以及二级域名配置添加证书文件,以让“小绿锁” 显示出来。

显示小绿锁却提示404NotFound

上篇文章末尾,我为二级域名 gogit.itfanr.cc 的Nginx配置中指定了证书目录,网站也正常应用上了https:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
server {
listen 443 ssl;
server_name gogit.itfanr.cc;

ssl_certificate /etc/acme.sh/itfanr.cc/fullchain.cer;
ssl_certificate_key /etc/acme.sh/itfanr.cc/itfanr.cc.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;

location / {
proxy_pass http://127.0.0.1:3000/;
}
}

server {
listen 80;
server_name gogit.itfanr.cc;
return 301 https://$server_name$request_uri;
}

但当我按照上面的配置为主域名 www.itfanr.cc 也指定https证书后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
server {
listen 443 ssl;
server_name www.itfanr.cc;

ssl_certificate /etc/acme.sh/itfanr.cc/fullchain.cer;
ssl_certificate_key /etc/acme.sh/itfanr.cc/itfanr.cc.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;

location / {
proxy_pass http://localhost:8080/;
}
}

server {
listen 80;
server_name www.itfanr.cc;
return 301 https://$server_name$request_uri;
}

结果,页面却显示了 404 Not Found 的错误。

解决多域名下设置证书

通过相关问题的搜索,结果却没有找到什么有效的解决方法。另外由于我对Nginx的配置也不是特别精通,所以一下子陷入了迷茫中。

后来,在一篇相关文章 Let’s Encrypt 泛域名证书申请及配置 中找到了一种方法。

第一步

在Nginx的 snippets 目录下,创建一个配置文件,我这里命名为 ssl-itfanr.conf,内容用来设置SSL相关的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# /etc/nginx/snippets/ssl-itfanr.conf

server_tokens off;

ssl_session_cache shared:SSL:10m;
ssl_session_timeout 60m;

ssl_session_tickets on;

ssl_stapling on;
ssl_stapling_verify on;

resolver 8.8.4.4 8.8.8.8 valid=300s;
resolver_timeout 10s;
ssl_prefer_server_ciphers on;

# 证书路径 绝对地址
ssl_certificate /etc/acme.sh/itfanr.cc/fullchain.cer;
ssl_certificate_key /etc/acme.sh/itfanr.cc/itfanr.cc.key;

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384: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";

add_header Strict-Transport-Security "max-age=31536000;includeSubDomains;preload";
add_header X-Frame-Options deny;
add_header X-Content-Type-Options nosniff;
add_header x-xss-protection "1; mode=block";
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob: https:; connect-src 'self' https:; img-src 'self' data: https: blob:; style-src 'unsafe-inline' https:; font-src https:";
第二步

然后在 Nginx 主配置文件中开启 SSL 支持:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# /etc/nginx/nginx.conf

http {
...
...
##
# SSL Settings
##

ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
...
...
}

我的配置文件中 SSL配置 这里默认是启用状态,所以保持默认即可。

第三步

修改域名的配置文件。

比如,修改我的网站主域名 itfanr.cc 配置文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# /etc/nginx/conf.d/itfanr.conf

server {
listen 80;
listen [::]:80;

server_name itfanr.cc www.itfanr.cc;
return 301 https://$server_name$request_uri;
}

server {
listen 443 default_server;
listen [::]:443 default_server;
server_name itfanr.cc www.itfanr.cc;

include snippets/ssl-itfanr.conf;

location / {
proxy_pass http://localhost:8080/;
}
}

同时,修改二级域名 gogit.itfanr.cc 的配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# /etc/nginx/conf.d/gogit.conf

server {
listen 80;
server_name gogit.itfanr.cc;
return 301 https://$server_name$request_uri;
}

server {
listen 443 ssl;
listen [::]:443 ssl;
server_name gogit.itfanr.cc;

include snippets/ssl-itfanr.conf;

location / {
proxy_pass http://127.0.0.1:3000/;
}
}

其中,关键的一点就是在配置文件中包含SSL的配置文件:

1
include snippets/ssl-itfanr.conf;
第四步

如果还有其他的二级域名,同样依照上面的方法进行配置,然后重新载入Nginx配置文件。

在重载之前,可以先验证一下刚刚修改的配置文件是否有误:

1
2
3
$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

无误后,再执行重载操作:

1
$ sudo nginx -s reload

此时,再次访问两个域名地址,可以发现都能够正常访问且都是https安全连接了。

itfanr.cc:

gogit.itfanr.cc:

设置默认站点

因为我的域名设置了支持泛域名,所以支持的二级域名都会跳转到我的服务器的IP地址。

那么,对于一些我们没有添加到二级域名在没有进行定义时,会返回什么呢?这就需要设置 默认站点 了。

也就是通过参数 default_server 来指定。

我们可以查看一下 /etc/nginx/sites-available/default 文件:

1
2
3
4
5
6
7
server {
listen 80 default_server;
listen [::]:80 default_server;
...
...
root /var/www/html;
}

上面的设置说明,当访问域名是没有匹配到我们添加的域名,那么就会返回默认的地址。也就是这里的 Nginx默认的页面。

比如,我访问 http://abc.itfanr.cc 时:

而该文件中并没有配置当使用 https 方式访问时,要返回什么默认页面。所以我在上面的 itfanr.conf配置中添加了一项:

1
2
3
4
5
...
listen 443 default_server;
listen [::]:443 default_server;
server_name itfanr.cc www.itfanr.cc;
...

默认返回我的博客地址。比如访问 https://abc.itfanr.cc 时:

另外,要注意的是:只能设置一个网址为默认地址,当设置了多个时会提示错误:

1
2
3
$ sudo nginx -t
nginx: [emerg] a duplicate default server for 0.0.0.0:80 in /etc/nginx/sites-enabled/default:17
nginx: configuration file /etc/nginx/nginx.conf test failed

解决网站中的 data 类型字体图片无法载入问题

配置好Nginx的 https 配置后,再次请求网址 https://gogit.itfanr.cc,发现浏览器地址栏中已经显示了安全的 “小绿锁” 标志。但是一打开Chrome浏览器的F12调试工具,发现有一些请求是报错的。

可以发现,报错的基本都是前缀为 data:application 类型的字体图片文件。

通过查询,在 Content-Security-Policy 段中应该包含以下内容:

1
font-src 'self' data:;

所以只需要在 font-srchttps 之间添加 :'self' data: 即可。注意前后之间要用空格分隔。

原:

1
2
3
# /etc/nginx/snippets/ssl-itfanr.conf

add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob: https:; connect-src 'self' https:; img-src 'self' data: https: blob:; style-src 'unsafe-inline' https:; font-src https:";

修改后:

1
2
3
# /etc/nginx/snippets/ssl-itfanr.conf

add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob: https:; connect-src 'self' https:; img-src 'self' data: https: blob:; style-src 'unsafe-inline' https:; font-src 'self' data: https:";

修改完成后,重新载入Nginx配置,再次刷新网站,发现已经没有 data:application 红色的错误请求链接了:


解决七牛云图片外链http无法载入的问题

访问我的博客网址 https://www.itfanr.cc ,发现有些文章中的七牛云外链图片都不显示了。查看F12调试工具:

发现所有的七牛云 http 外链图片均不加载。

然后我又去七牛云的网站中查看了一下配置,发现如果按照官方的方法切换成 https 的链接,是需要收费的,此时心里是一万头草泥马狂奔的景象…

无奈只能找寻其他的解决方法了。

查看F12的Console中的错误信息:

1
Refused to load the image 'http://ouej55gp9.bkt.clouddn.com/blog/20180917193602.png' because it violates the following Content Security Policy directive: "img-src 'self' data: https: blob:".

搜索到 Content-Security-Policy 介绍页面:Content Security Policy CSP Reference & Examples

参照里面的介绍,尝试把七牛云图片的域名加到 img-src 中,更改如下:

1
2
3
4
5
img-src 'self' data: https: blob:;

# 更改为:

img-src 'self' ouej55gp9.bkt.clouddn.com data: https: blob:;

再次刷新页面后,发现如果页面中没有引用到七牛云的图片链接,地址栏中是显示“小绿锁”的,比如首页;而到了文章详情页中,引用了七牛云的图片链接后,地址栏中就会显示“叹号”的不安全标志。

访问首页,提示“安全连接”:

访问带有http外链图片的文章详情,提示“连接并非完全安全”:

根据上面的验证发现,必须得整站的链接都是 https 的情况下,才会是一直处于“小绿锁”的安全模式下。那么接下来就是解决整站https的问题了。目前来看,也就是解决七牛云图片链接如何从 httphttps 的问题。

遗留的问题

虽然通过独立出SSL配置,然后在需要启用 https 的域名配置文件 server{}include 的方式能够正常运行,但我心里一直还是有个疑问的:为什么分别指定证书文件地址时配置却不生效?

由于目前还未找到原因,这个问题暂留,以待后续解答。

如有疑问或需要技术讨论,请留言或发邮件到 service@itfanr.cc