昨晚花了几个钟头,把 blog 的 HTTP 升级成 HTTPS 了,虽然这件事做的晚了一点。为什么要升级,不是我说明的重点,想了解的朋友可以阅读这篇文章。我记录的是我升级的过程,踩到的坑。
备份
首先,文章中有许多以 http://www.raychase.net 开头的 URL,比如某些图片和链接,可以把它们改成 https 的,也可以全部改成相对路径,这样的适用性更广。
代码语言:javascript复制UPDATE xx_posts SET post_content = REPLACE(post-content, 'http://www.raychase.net/', '/');
到浏览器里面访问看看,似乎没有什么问题。
安装
WordPress 管理台
在 Wordress 管理台的设置里面,把本站 URL 中的 http 替换成 https。
证书申请安装
在 certbot 申请证书,选好了代理和操作系统一个,照着 guide 操作。
代码语言:javascript复制wget https://dl.eff.org/certbot-auto
sudo mv certbot-auto /usr/local/bin/certbot-auto
sudo chown root /usr/local/bin/certbot-auto
sudo chmod 0755 /usr/local/bin/certbot-auto
接着自动安装,中途退出了:
代码语言:javascript复制sudo /usr/local/bin/certbot-auto --nginx
...
To use Certbot, packages from the EPEL repository need to be installed.
Enable the EPEL repository and try running Certbot again.
EPEL
既然是没有 EPEL,那就安装一个:
代码语言:javascript复制sudo yum install epel-release
Loaded plugins: fastestmirror
Setting up Install Process
Loading mirror speeds from cached hostfile
Error: Cannot retrieve metalink for repository: epel. Please verify its path and try again
失败了,从错误中看是 mirror 地址上没法访问到,于是研究了一下,修改 /etc/yum.repos.d/epel.repo 和 /etc/yum.repos.d/epel-testing.repo ,注释掉全部以 mirrorlist= 开始的行,再还原全部以 baseurl= 开始的行。这样就去原始地址,而不是镜像地址下载了。
果然就安装成功了。
Nginx 配置
于是继续刚才失败的操作:
代码语言:javascript复制sudo /usr/local/bin/certbot-auto --nginx
挂在了真正安装配置的过程中:
代码语言:javascript复制Error while running nginx -c /etc/nginx/nginx.conf -t.
nginx: [emerg] open() "/etc/nginx/nginx.conf" failed (2: No such file or directory)
nginx: configuration file /etc/nginx/nginx.conf test failed
原来是找不到 nginx 的配置文件,因为 nginx 安装的路径并非/etc 下面。于是就干脆建立一个软链接:
代码语言:javascript复制ln -s /usr/local/nginx/conf /etc/nginx
这一步过了,结果又挂在了证书 challenge 的过程(challenge 是域名验证的一环,在这里有介绍):
代码语言:javascript复制Performing the following challenges:
http-01 challenge for www.raychase.net
Waiting for verification...
Challenge failed for domain www.raychase.net
研究一下发现,它需要占用 80 端口,因为这个 challenge 的路径是 http://www.raychase.net/.well-known/acme-challenge/xxxxx,而网站应用已经占了 80,于是把 lnmp 先停掉,再操作。
终于提示成功了,注意到它在 nginx 的配置文件目录下的子目录 vhost 下面生成了一个增量配置文件:www.raychase.net.conf,里面配置了一些 ssl_cewrtificate 之类的 key 的路径,把它放到 nginx 的配置目录里面。
验证
命令行验证
尝试了一下 curl https://www.raychase.net 可以访问,于是就在 SSL Labs 可以验证证书的情况,结果提示失败。
接着在外网使用上述的 curl HTTPS 命令,但是却 timeout,可是 curl http://www.raychase.net,得到了正确的 301 重定向的响应。
首先怀疑 nginx,仔细研究了 nginx 的配置,没发现有什么问题。接着就怀疑防火墙,查看 /etc/sysconfig/iptables 发现可能是防火墙的问题。于是命令行添加规则:
代码语言:javascript复制iptables -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
果然,可以访问了。
再 curl http://www.raychase.net,得到了 301 重定向的响应。
浏览器验证
接着再到浏览器里面访问验证,大致没问题,可是,我注意到访问网站首页的时候,URL 左侧的小图标不是一般 HTTPS 的 “锁” 的图标,而是一个圈 “i” 的图标,点击以后可以看到 “Your connection to this site is not fully secure” 这样的文字。
原来是因为网页上包含了 “mixed content”,即有指向当前站的 http 的链接。查看源代码,原来在网站中还有一些其它配置包含有当前站的 http 链接,逐一修复,果然,小锁图标出来了,而文字变成了 “Connection is secure”。
改进
HTTP2
在 nginx 中配置打开 http2:
代码语言:javascript复制listen 443 ssl http2;
可是在修改完毕,重新加载 nginx 的时候,它提示 http2 不认识,于是就检查了,发现是 nginx 版本太老的原因。
于是使用 yum 来升级,之后提示已经是最新版本了,还是不支持。
原来 yum 的默认 repo 版本还是太老,必须要使用 nginx 自己的 repo。于是增加文件:
代码语言:javascript复制/etc/yum.repos.d/nginx.repo
写入:
代码语言:javascript复制[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=0
enabled=1
再重启 nginx 就好了。
证书 renew 自动化
证书每几个月就会过期,因此必须自动续上,而不是手动登上服务器来操作。我尝试了一下 renew 证书的过程:
代码语言:javascript复制/usr/local/bin/certbot-auto renew
发现又出现了前面 challenge 的过程。当时我停掉了 lnmp,可是我总不能为了续个证书停掉网站吧?于是考虑解决 challenge 的端口冲突问题。发现其实可以用 HTTP 的 80 端口,但是 challenge 的 URI 冲突才是问题的核心。这样问题就好解决了,把导致冲突的 URI 放进来就好了,在 nginx 里面配置:
代码语言:javascript复制location /.well-known/acme-challenge/.* {
proxy_pass http://127.0.0.1:80;
}
接着配置 cron task,使得这个过程自动化:
代码语言:javascript复制crontab -e
加入:
代码语言:javascript复制0 0 25 * * /usr/local/bin/certbot-auto renew
昨天是 25 号,因此我设置成每天的 25 号来尝试 renew。如果证书还远没到期,它会提示 “Cert not yet due for renewal” 并会退出这个过程,因此这个命令可以安全地运行。
可是我并不知道运行结果啊,总不能每次都登陆上来,跑到/var/log/cron 去看日志吧?
其中一个解决办法是发 email,把运行输出发 email 给我。
Email 通知结果
于是先要配置 ssmtp,编辑/etc/ssmtp/ssmtp.conf:
代码语言:javascript复制root=xxx@gmail.com
mailhub=smtp.gmail.com:587
RewriteDomain=gmail.com
Hostname=xxx
FromLineOverride=YES
UseTLS=Yes
UseSTARTTLS=Yes
TLS_CA_File=/etc/pki/tls/certs/ca-bundle.crt
AuthUser=xxx@gmail.com
AuthPass=yyy
AuthMethod=LOGIN
接着把地址信息添加到/etc/ssmtp/revaliases。
我使用的是 Gmail 的 SMTP,为了让 gmail 允许这样的操作,还必须在账户选项的 security 里面,开启 less secure app access 的设置。
搞定以后尝试发一封邮件试试:
代码语言:javascript复制echo -n 'test' | sendmail -v xxx@gmail.com
没问题!那就可以配置 cron task 让它发邮件了,加上:
代码语言:javascript复制MAILTO=xxx@gmail.com
这个变量加上以后,应该就可以自动发邮件了。
crontab 没有立即执行,从而验证的功能,于是为了立即验证,加了一行(每分钟都会执行一次):
代码语言:javascript复制* * * * * echo "test"
验证以后把这行删掉就好了。
文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《四火的唠叨》