0x0 前言
一年前,总想写点什么作为生活记录。在比对众多类型博客之后,简洁高效的 hexo 脱颖而出,它适合你体会写博客的每一个阶段。本博客采用 Nginx + Hexo + Let‘s Encrypt + Cloudflare 组件,架设在 vps 上,采用了 Let‘s Encrypt 的免费证书和 Cloudflare 的 CDN 服务。如果你是利用 github pages 搭建博客,仅需阅读 1x0 章节,内容不包括上传部分。
0x1 部署 SSL 的准备工作
谷歌宣布从2018年7月即 Chrome 68 发布开始,将把所有 HTTP 站点标记为不安全。
作为信息安全工作者,我深知 SSL 存在的必要性和复杂性,但无论因为何种原因导致你需要部署 SSL ,都需要先考虑下面几个问题:
- 你是否基本明白 SSL 的工作原理;
- 网站是否计划 HTTP 和 HTTPS 并存;
- 新增的 SSL 开销是否影响性能或体验;
- 能否接受 SSL 对运维和原有组件的影响;
1x0 部署 Hexo
关于 Hexo 的介绍请前往官网了解。Hexo 博客可以像传统建站一样通过购买服务器和域名实现,也可以利用 github pages,将源码托管到 github 实现,后者需要依赖 git ,因此部分发行版的 Linux 需要更新自带的 git,无论哪种方式都需要安装 node.js。
1 | [root@H0u5er ~]# yum -y install gcc zlib-devel openssl-devel perl cpio expat-devel gettext-devel curl autoconf |
命令执行不出现问题的话,Hexo 已经安装完成。Hexo 主配置文件 _config.yml 有严格的缩进要求,通过在官方或者 github 寻找心仪的主题设计,下载主题文件到 theme 文件夹,并且将 _config.yml 的 theme 修改为对应文件夹名字,即可替换 Hexo 主题风格。
如果你是利用 github pages 搭建博客,还需要配置 git ,如上传密钥等请自行解决。
1 | [root@h0u5er blog]# cat _config.yml | grep git |
2x0 申请证书
如果你是利用 github pages 搭建博客,本小节不适用。
Let‘s Encrypt 是这几年很热门的免费 SSL/TLS 证书供应商,在为我们提供便利的同时,也为许多网络犯罪提供了温床。今年 3 月开始,Let’s Encrypt 发布的ACME v2 现已正式支持通配符证书。
2x1 安装 Certbot
https://certbot.eff.org/lets-encrypt/centosrhel7-nginx
打开 Let’s Encrypt 和 Certbot 的合作网页,根据使用情况选择 Web 中间件和系统版本,页面会生成对应的安装指引。
1 | [root@H0u5er ~]# yum install python2-certbot-nginx // 这里我的环境是 Centos7 + Nginx |
2x2 身份认证
1 | [root@H0u5er ~]# certbot --help // 查看大致使用语法 |
申请证书方式包括Run(默认),Certonly 和 Renew,这里我建议使用 certonly 获取证书,然后通过手工配置证书的方式实现 SSL。另外 Certbot 支持 Standalone,Nginx,Webroot,Manual 等身份认证,都是为了验证域名所有者是你本人,详细区别查看这里的官方解释,使用哪种方式取决于实际网络情况和需求,下面举几个例子,更多细节问题请查阅官方资料。如果你已经使用了 CDN 服务,那么请务必采用 Webroot 的方式进行认证,因为 Let’s Encrypt 的认证服务器并不知道你的原始服务器 IP 地址。
- 通过 DNS 的交互验证方式:
1 | [root@H0u5er ~]# certbot --manual --perferred-challenges dns certonly |
此方式基于 DNS 的解析。在交互过程中,根据你的实际情况回答。这种方式需要你拥有对域名的解析控制权,添加一条 TXT 类型的记录,主机名为 _acme-challenge,内容为 Let’s Encrypt 在交互时产生的随机字符串,此处是 uckdcWCoXW46RkFf630ymzjj_y5E0mE47S2VK8l3rRA。在 DNS 记录添加完毕并生效之后,按 Enter 即可获得证书。
- 通过 Webroot 验证方式
1 | [root@H0u5er ~]# certbot certonly --webroot --agree-tos -v -t --email [email protected] -w /var/www/ -d example-h0u5er.com |
此方式基于网站目录访问。参数 -d 是需要验证的域名,系统会在 -w 参数设置的网站根目录下会创建临时文件,/网站根目录/.well-known/acme-challenge,shell 脚本会自动访问该目录,如果能访问说明你是域名的所有者,特别需要注意 DNS 的解析是否可达,可根据返回的消息进行排错。出现下述内容的时候,说明验证通过。
1 | - Congratulations! Your certificate and chain have been saved at |
- 通过 Nginx 验证方式
1 | [root@H0u5er ~]# certbot --nginx --agree-tos --redirect --uir --hsts --staple-ocsp --must-staple -d www.example-h0u5er.com,example-h0u5er.com --email [email protected] |
此方式基于 Nginx 插件。上述语句因为没有带 certonly 的参数,所以使用了默认的 run 参数代替,即在申请证书的同时自动配置好 Nginx 的 SSL 设置,还可以包括 301 重定向,CSP,HSTS,OCSP Stapling 的安全优化,但是自动配置的前提是网站并没有采用 CDN 服务。-d 参数后面如有多个子域名,可以使用逗号隔开。
- 通过 standalone 验证方式
1 | [root@H0u5er ~]# certbot certonly --standalone --email [email protected] -d example-h0u5er.com |
此方式基于网络。这种验证方式不依赖 Web 组件。后续可添加 –preferred-challenges http 或者–preferred-challenges tls-sni 参数,分别指定使用 80 或 443 端口进行验证,这样的话就需要保证服务器能接收互联网的请求。
2x3 自动续期
Let‘s Encrypt 默认提供的证书只有 90 天有效期,在没有 Certbot 之前,用户需要运行特定的 python 脚本使得证书可以自动续期。Let’s Encrypt 和 Certbot 合作之后,证书自动续期的事情变得非常简单,只需要利用 renew 参数,certbot 即可自动调用 /etc/letsencrypt/renewal 下的配置文件进行续期操作。如果你使用系统定时任务执行续期,请需要注意 certbot 指令在 crond 进程下的环境变量是否能够被调用。
1 | [root@h0u5er ~]# certbot renew |
3x0 配置 Nginx
如果你是利用 github pages 搭建博客,本小节不适用。
如果你是通过购买服务器搭建博客,那么你需要 Apache 或 Nginx 等等承载 Web 服务的组件。由于 Hexo 默认工作在 4000 端口,我们可以将写好的博客转换成静态文件:
1 | [root@h0u5er blog]# hexo generate // 自动将 hexo 生成静态文件,如 HTML |
静态文件会保存在 Hexo 的主目录下,文件夹的名字取决于配置文件,此处为 public 文件夹,配置 Apache 或 Nginx 使得 public 文件夹内容在 80 端口展示。还有另外一种不推荐的做法,那就是利用 Nginx 的反向代理,网站的访客如往常一样在浏览器直接输入 IP 或者域名访问默认的 80 端口,Nginx 收到请求之后将访问指向本地 4000 端口,这样做使得 Hexo 在利用 4000 端口进行本地调试的信息,也会直接暴露在 80 端口,反向代理的 nginx 配置如下:
3x1 拥有证书后的 Nginx
申请证书成功之后,默认是放在 /etc/letsencrypt/live/你的域名/ 的这个文件夹下面,在原先的配置基础上 server 部分加入 SSL 的配置就完成了基本的 SSL 支持。
1 | server { |
关于 Nginx 的配置,我部署的过程出现过许多错误,同时这样简单的配置有许多不足,如 HTTP 依然可以在网页内使用、没有启用迪菲-赫尔曼密钥交换(英语:Diffie–Hellman key exchange,缩写为D-H) 等等问题。Nginx 的 SSL 配置指南 中提及的内容很适合学习。
4x0 启用 CDN(可选)
对于不了解 CDN 加速原理的读者,建议先看看相关资料。演示采用 Cloudflare CDN 免费服务,但针对国内节点的加速效果较差,慎用。
如果你是利用 github pages 搭建博客,它同样支持 CDN 加速,但本文仅考虑且保证能在自建服务器的情况下使用该方式。
在使用 Cloudflare 的 CDN 服务之前,你需要将 DNS 的解析权交给 Cloudflare,网上有方法可以绕过,至于为什么需要把解析权交给 Cloudflare ,我推测是为了实现在不掌握用户 SSL 私钥的情况下进行 CDN 加速。首先登录到 Cloudflare 的官网, 在 DNS 菜单中选择涉及的 DNS 记录开启 CDN,同时在 Crypto 的 SSL 选项卡中开启 Full strict 模式,当 SSL 选项卡出现 Universal SSL Status Active Certificate 则完成了 CDN 加速配置,激活过程一般只需要几分钟。
关于 Full strict 模式和其他三种模式的解释对比,请翻阅官方资料,由于 Let‘s Encrypt 的有效时间较短并且属于权威机构认可的证书,因此选择 Full strict 模式。
5x0 排错与优化
错误1:浏览器提示 The plain HTTP request was sent to HTTPS port;
一般是由于中间件的配置不当导致,在我关闭 Nginx 配置中的 ssl 参数并重启 nginx 后即可解决。
1 | #ssl on // 或者改为 off |
错误2:www.h0u5er.com redirected you too many times;ERR_TOO_MANY_REDIRECTS;
一般是由于中间件的配置不当导致,在我调整了 Nginx 中的 301 重定向并重启 nginx 后即可解决。
错误3: Cloudflare 的Crypto SSL 一直处于 initializing Certificate 状态;
情况一,属于先部署 SSL 证书完成,再开启 CDN 的。则打开 Cloudflare CDN 功能和 SSL 的 Full strict 模式即可, initializing Certificate 一般只会持续几分钟就会转为 Active Certificate 。
情况二,属于先开启了 CDN,再从原始服务器申请 SSL 证书的。那么证书务必才用 Webroot 方式认证,同时可以使用 Nginx 的自动配置,参考如下:
1 | [root@h0u5er ~]# certbot --authenticator webroot --installer nginx -w /网站主目录 --agree-tos --redirect --uir --hsts --staple-ocsp --must-staple -d www.example-h0u5er.com,example-h0u5er.com --email [email protected] |
错误4:网站页面无法打开,error 526;
点击转跳到官方知识库页面,搞清楚 Full strict 模式和 Full 模式的应用范围与区别。
错误5: ERR_SSL_VERSION_OR_CIPHER_MISMATCH
优化1:部分页面在 Chrome 显示为不安全;
拿我自身的博客举例,因为之前采用 HTTP 协议的图床,所以手工替换了支持 https 的图床。目前本博客已经实现全站 HTTPS 且全站符合 Chrome 小绿锁标准,强迫症患者的福音。
优化2:Cloudflare 的 CDN 在国内效果并不好;
国内的大部分情况下 Cloudflare 是一个减速的 CDN。因为本站的服务器在国内连接速度还算不错,所以采用关闭资源自动压缩、调整缓存等级( No Query String )、开启 HTTP2、调整防火墙等级( Low ) 、关闭手机端加速等等迷之优化方式。优化后,部分地区加载网页的速度与原始 IP 访问页面的加载速度差别在毫秒级以内。
优化3:网站加固;
主机安全方面,本次采用的 CDN 虽然加速效果不怎么样,但是减少了真实 IP 暴露所带来的危害。其次建议开启服务器内的防火墙,控制端口流量,增强 RDP 或 SSH 的验证方式,合理分配系统的权限。
Web 服务方面,可以通过配置文件隐藏中间件的版本号,增加中间件的安全配置,如:
1 | add_header Content-Security-Policy upgrade-insecure-requests; |
优化4:CAA 记录配置
CAA (Certification Authority Authorization)是在 2013 年由 RFC 6844 定义的一个标准,旨在于通过控制哪些 CA 能给一个域名签发证书提升 PKI 体系的生态圈强度。 因为每一个 CA 都能给任意域名签发证书,这样会导致 CA 的证书容易被劫持,因此我们可以在 DNS 解析记录中,添加类型为 CAA 的记录,名字为 example-h0u5er.com,对应的值为 letsencrypt.org,如果是采用其他 CA 签发的证书,则替换为类似digicert.com、globalsign.com。添加一个联系邮箱,便于 CA 中心发现异常恶意签发证书时通知管理员。
1 | [root@h0u5er conf.d]# dig h0u5er.com CAA |
6x0 参考资料
Ubuntu 利用Let‘s Encrypt 部署 HTTPS
7X0 更新
[2019 Feb 20] 前几天都到 Let‘s Encrypt 的邮件提醒,证书即将过期,于是到服务器执行
1 | [root@h0u5er letsencrypt]# certbot renew |
命令执行之后没有报错就是重新申请完成, 重启 Nginx 之后浏览器就会显示新证书了. 新证书会自动用新的数字命名,比如原本使用的是01,那么新证书就会命名成02, 并且自动以用02作为新的证书.下面这个链接文件我不知道是默认还是我自己手动改了的原因,但是也会自动指向较新的证书文件.
1 | [root@h0u5er www.h0u5er.com]# pwd |