将自签名的openssl证书与cloudflare配合使用,达到CDN效果。
let’s encrypt的证书每三个月都要续签,即便可以用脚本实现,但是我这个懒人还是想一劳永逸:签证一次以后也不需要再签名,而且证书“不会过期”,那是坠吼的!
前戏
确保cloudflare中的DNS记录为DNS only(仅解析DNS),先不急着上CDN。待调试成功再开启HTTP Proxy CDN。
自签名
自签名需要生成两个密钥,一个用于自造CA,另一个用作泛域名。
切换当前目录
cd /tmp/test-cert
自造CA证书
新建一个ca目录,存放自造ca
mkdir ca
创建一个私钥用于CA,这里使用ECC证书(如果使用RSA证书,可以使用genrsa参数)
openssl ecparam -genkey -name prime256v1 -out ca/ca.key
生成CA根证书,参数days后面的7305是指证书的有效期,这里设置成了20年
openssl req -new -x509 -days 7305 -key ca/ca.key -out ca/ca.crt \
-subj "/C=CN/ST=Sichuan/L=Chengdu/CN=example.com"
ca.crt就是自造的根域名CA证书。拷贝给其它设备安装它即可信任该自签CA
泛域名证书
创建一个私钥用于泛域名
openssl ecparam -genkey -name prime256v1 -out domain.key
生成签名请求CSR:
openssl req -new -sha256 -key domain.key -out domain.csr\
-subj "/C=CN/ST=Sichuan/L=Chengdu/CN=example.com"
domain.csr就是自造的域名CSR,用于下文的签证书。
CA自签证
新建一个extended.ext文件,内容如下,修改最后的subjectAltName字段为主域名+泛域名。
[ req ]
default_bits = 2048
distinguished_name = req_distinguished_name
req_extensions = san
extensions = san
[ req_distinguished_name ]
countryName = CN
stateOrProvinceName = Sichuan
localityName = Chengdu
[ SAN ]
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = DNS:example.com,DNS:*.example.com
开始签名,使用指定的extended.ext文件,签名有效期20年。。。
openssl x509 -req \
-days 7305 \
-sha256 \
-CA ca/ca.crt -CAkey ca/ca.key -CAcreateserial \
-in domain.csr -out cert.crt \
-extfile extended.ext -extensions SAN
将根证书和泛域名证书合成一个full-chain证书
cat cert.crt ca.crt > fullchain.crt
在下一步部署nginx,我们只需要以下三个文件
- domain.key
- cert.crt
- fullchain.crt
自造CA可以选择留存下来,下次可以再签新证书。再签的时候需要重新删除并做一个demoCA目录。否则提示TXT_DB error number 2
部署
nginx
在监听80端口的server标签中,强制http跳转到https。
location / {
rewrite ^(.*)$ https://$host$1 permanent;
}
在监听443端口server标签中修改
listen 443 ssl;
ssl_certificate /tmp/test-cert/cert.crt;
ssl_certificate_key /tmp/test-cert/domain.key;
ssl_trusted_certificate /tmp/test-cert/fullchain.crt;
测试配置是否正确(test),正确就reload
nginx -t && nginx -s reload
打开网站看看效果,肯定提示证书不被信任(自签证书),跟12306网站一样。忽略这个警告,进入网站,确认无误就可以开启cloudflare的CDN了。
cloudflare
大致就是如下步骤
- 在cloudflare中的DNS选项卡,右侧的Status选择”HTTP proxy,CDN”。
- 注意cloudflare在切换HTTP CDN模式和DNS Only模式有一定的延时,可能是DNS缓存。有时候修改记录后一分钟后就生效了,有时候却等几个小时才生效。耐心等候。
- 在cloudflare中的crypto选项卡,SSL模式选择Full。
其它
清除HPKP
之前有证书,且部署了HPKP,使用自签证书后,chrome提示如下错误
NET::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN
由于我的网站使用了pinned SHA256,在浏览器中清除以前的HPKP记录即可
# 打开并删除自己网站记录
chrome://net-internals/#hsts
可以使用ca.crt重新生成pinned key,放入到nginx配置中
openssl x509 -in ca.crt -noout -pubkey | openssl asn1parse -noout -inform pem -out ca.pubkey
HPKP_SHA256=`openssl dgst -sha256 -binary ca.pubkey | openssl enc -base64`
echo $HPKP_SHA256
当然,若要使用cloudflare,必须或cloudflare中间证书的SHA256值,而不是自签CA的。
我的方法是打开这个SSLlabs网站,填入自己域名,点测试,查看中间证书的SHA256值,然后手动加入到nginx里面的。
从上图可以看出,加入到nginx的代码如下
add_header Public-Key-Pins 'pin-sha256="x9SZw6TwIqfmvrLZ/kz1o0Ossjmn728BnBKpUFqGNVM="; max-age=2592000;';