WP 03 – 给你的网站开启 HTTPS (使用免费的 SSL 证书)
目录
1 为何要开启 HTTPS
HTTPS, 全称Hyper Text Transfer Protocol over Secure Socket Layer
, 是以安全为目标的 HTTP 通道 —— 通过为 HTTP 添加 SSL 证书, 实现安全加密访问.
与 HTTP 默认的访问端口80不同, HTTPS 默认的访问端口是443.
一般的浏览器都在 URL 地址栏中对 HTTPS 的请求作了特殊显示, 以 Chrome 为例, HTTPS 的请求会加上一把象征安全的所?
出于安全与好看的考虑(你不想自己的网站总提示 不安全
吧:-D), 这里对网站添加 SSL 证书, 实现HTTPS安全访问.
2 如何开启 HTTPS
开启 HTTPS 的方法主要有3种:
① 通过第三方服务商购买 SSL 证书服务 —— 收费普遍高昂, 不可行;
② 向自己的主机服务商申请 SSL 证书服务, 有收费的也有免费的. 我用的是阿里云香港区的 ECS 服务器, 可以免费配置, 不过他们要求ECS实例的IP是大陆的, 且需要备案 —— 很明显我并不符合, 不可行;
③ 通过 Let’s Encrypt 等授权中心, 自己配置SSL证书 —— 可行.
关于Let’s Encrypt:
Let’s Encrypt 是2016年成立的一家证书授权中心;
他们提供免费的传输层安全 (TLS)X.509 证书, 通过自动化的过程消除目前安全网站证书需要手工创建、加密、签名、安装以及更新的复杂性.
这里通过Github上的一个开源脚本 acme-tiny 对网站进行加密设置.
2.1 克隆脚本
[root@onepiece ssl]# sudo git clone https://github.com/diafygi/acme-tiny.git
2.2 创建 Let’s Encrypt 私钥
先创建一个目录, 用来存放 SSL 所需的文件, 我创建的是 /data/ssl/
. 然后创建一个 RSA 账号, 让 Let’s Encrypt 能够识别你的身份:
cd /data/ssl/
openssl genrsa 4096 > account.key
2.3 创建 CSR 文件
CSR, 即 Certificate Signing Request, 证书签名请求.
Let’s Encrypt 证书的签发过程使用了 ACME 协议, 而 ACME 协议要求用户提交一个 CSR 文件, 用来进行证书签名和证书更新.
1) 创建域名RSA私钥和上面创建账号的RSA私钥用到的命令一样, 如下:
[root@onepiece ssl]# openssl genrsa 4096 > domain.key
注意: 不要使用account.key
来当作 domain.key
.
2) 创建 CSR 文件: 一般域名有带 www 和不带 www 的, 我们全部写进去:
[root@onepiece ssl]# openssl req -new -sha256 -key domain.key -subj "/" -reqexts SAN -config <(cat /etc/pki/tls/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:healchow.com,DNS:www.healchow.com")) > domain.csr
把上面的www.healchow.com
和healchow.com
替换成你的域名即可.
如果提示找不到/etc/ssl/openssl.cnf
文件, 那么使用命令find / -name "openssl.cnf"
找到这个文件的地址, 更换命令中的地址即可.
2.4 获取网站证书
acme-tiny脚本会生成验证文件并写入你指定的目录, 然后通过.well-known/acme-challenge/
这个URL来访问验证文件.
注意: Let’s Encrypt 会对服务器做一次 HTTP 请求来进行验证, 因此你需要保证80端口能够访问.
1) 创建challenges
目录, 用来存放验证文件(路径可以自行修改):
[root@onepiece ssl]# mkdir -p /data/ssl/www/challenges
2) 配置 Nignx 的80端口:
[root@onepiece ssl]# vim /etc/nginx/nginx.conf
# 修改后的相关内容如下:
server {
listen 80;
server_name healchow.com www.healchow.com;
# 注意: 这里先不要配置301重定向到https, 否则会导致下一步失败
# return 301 https://healchow.comrequest_uri;
location /.well-known/acme-challenge/ {
alias /data/ssl/www/challenges/;
try_filesuri = 404;
}
# 其他配置...
}
3) 重启 Nginx:
[root@onepiece ssl]# service nginx reload
Redirecting to /bin/systemctl reload nginx.service
[root@onepiece ssl]# service nginx restart
Redirecting to /bin/systemctl restart nginx.service
4) 获取签名证书:
# 注意: 下述"--acme-dir"后面是2个"/"
[root@onepiece ssl]# python acme_tiny.py --account-key ./account.key --csr ./domain.csr --acme-dir //data/ssl/www/challenges/ > ./signed.crt
# 如果一切正常, 应该会出现下述内容, 并且当前目录下就会生成一个signed.crt, 这就是申请好的证书文件
Parsing account key...
Parsing CSR...
Found domains: healchow.com, www.healchow.com
Getting directory...
Directory found!
Registering account...
Registered!
Creating new order...
Order created!
Verifying healchow.com...
healchow.com verified!
Verifying www.healchow.com...
www.healchow.com verified!
Signing certificate...
Certificate signed!
2.5 测试配置是否正确
1) 在/data/ssl/www/challenge/
目录下创建文件ssl_test.txt
, 添加内容为ssl text!
.
2) 通过浏览器访问该文件healchow.com/.well-known/acme-challenge/ssl_test.txt , 若能出现下述内容, 说明此时的配置仍然正确.
2.6 安装证书
1) 服务中, 还需要将 Let’s Encrypt 的中间件证书intermediate.pem
的内容附加在签名证书signed.crt
之后:
# 获取中间证书:
[root@onepiece ssl]# wget -O - https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem > intermediate.pem
# 附加到signed.crt之后, 生成新文件chained.pem:
[root@onepiece ssl]# cat signed.crt intermediate.pem > chained.pem
2) Nginx的配置文件中添加如下配置:
此时应该开启301重定向, 详细的配置文件, 请参见本文 [3.1节 第(2)部分].
server {
listen 80;
server_name healchow.com www.healchow.com;
# 配置301重定向到https, 否则通过http仍能访问资源
return 301 https://healchow.comrequest_uri;
# 下述配置要注释掉, 并移动到443端口的server中:
# location /.well-known/acme-challenge/ {
# alias /data/ssl/www/challenges/;
# try_filesuri = 404;
# }
}
server {
listen 443 ssl http2;;
server_name healchow.com www.healchow.com;
ssl on;
ssl_certificate /data/ssl/chained.pem;
ssl_certificate_key /data/ssl/domain.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 60m;
ssl_session_tickets on;
ssl_prefer_server_ciphers on;
location /.well-known/acme-challenge/ {
alias /data/ssl/www/challenges/;
try_files $uri = 404;
}
# 其他配置...
}
3) 重启 Nginx 服务:
[root@onepiece ssl]# service nginx restart
然后访问你的网站, 是不是也有把锁了? 恭喜, 你的网站已经开启了HTTPS ^_^
3 定时任务更新SSL证书
由于 Let’s Encrypt 证书的有效期只有90天, 所以需要定期更新.
这里我们编写更新脚本, 并开启定时任务, 让服务器定时更新它即可.
3.1 准备 Nginx 配置文件
(1) 配置 SSL 证书前的配置文件, 命名为nginx.conf.before
, 内容如下:
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main 'remote_addr -remote_user [time_local] "request" '
'statusbody_bytes_sent "http_referer" '
'"http_user_agent" "http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
server {
listen 80;
server_name healchow.com www.healchow.com;
root /data/blog;
index index.php index.html;
location / {
try_filesuri uri/ /index.php?args;
}
location /.well-known/acme-challenge/ {
alias /data/ssl/www/challenges/;
try_files uri = 404;
}
# 这里是反斜线\
location ~ \.php {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME document_rootfastcgi_script_name;
include fastcgi_params;
}
# 修改404页面为php页面
error_page 404 /404.html;
location = /40x.php {}
# 修改50x页面为php页面
error_page 500 502 503 504 /50x.html;
location = /50x.php {}
}
}
(2) 配置 SSL 证书后的配置文件, 就是此时正在使用的文件, 名称为nginx.conf
, 内容如下:
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main 'remote_addr -remote_user [time_local] "request" '
'statusbody_bytes_sent "http_referer" '
'"http_user_agent" "http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
server {
listen 80;
server_name healchow.com www.healchow.com;
# 配置301重定向到https, 否则通过http仍能访问资源
return 301 https://healchow.comrequest_uri;
}
server {
listen 443 ssl http2;
server_name healchow.com www.healchow.com;
ssl on;
ssl_certificate /data/ssl/chained.pem;
ssl_certificate_key /data/ssl/domain.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 60m;
ssl_session_tickets on;
ssl_prefer_server_ciphers on;
root /data/blog;
index index.php index.html;
location / {
try_files uriuri/ /index.php?args;
}
location /.well-known/acme-challenge/ {
alias /data/ssl/www/challenges/;
try_filesuri = 404;
}
# 这里是反斜线\
location ~ \.php{
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAMEdocument_root$fastcgi_script_name;
include fastcgi_params;
}
# 修改404页面为php页面
error_page 404 /404.html;
location = /40x.php {}
# 修改50x页面为php页面
error_page 500 502 503 504 /50x.html;
location = /50x.php {}
}
}
3.2 编写更新脚本
[root@onepiece ssl]# vim renew_cert.sh
脚本内容为:
#!/usr/bin/sh
# 先恢复 Nginx 的配置:
cd /etc/nginx
mv nginx.conf nginx.conf.after
mv nginx.conf.before nginx.conf
systemctl reload nginx.service
# 然后获取签名证书:
cd /data/ssl
python acme_tiny.py --account-key ./account.key --csr ./domain.csr --acme-dir //data/ssl/www/challenges/ > ./signed.crt
wget -O - https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem > intermediate.pem
cat signed.crt intermediate.pem > chained.pem
# 最后更新 Nginx 的配置:
cd /etc/nginx
mv nginx.conf nginx.conf.before
mv nginx.conf.after nginx.conf
systemctl reload nginx.service
3.3 添加定时任务
[root@onepiece ssl]# crontab -e
在打开的文本框中输入如下任务, 这里我设置为每个月执行一次:
注意: 这里的
2>>
是指将标准输出流输入到后面的文件日志中, 不能加空格.
# 每月的1日凌晨00:10就重新生成一次SSL证书
10 0 1 * * /data/ssl/renew_cert.sh 2>> /data/ssl/log/acme_tiny.log
然后依次按 [ESC] + : + q + !
, 保存文件内容并退出, 定时任务开启完成.
查看定时任务的命令:
[root@onepiece ssl]# crontab -l # 每月的1日凌晨00:10就重新生成一次SSL证书 10 0 1 * * /data/ssl/renew_cert.sh 2>> /data/ssl/log/acme_tiny.log
4 常见问题
4.1 无法下载文件
报错内容为:
ValueError: Wrote file to /data/ssl/www/challenges/xxxxxxxxxx, but couldn't download https://healchow.com/.well-known/acme-challenge/xxxxxxxxxx
这个错误的出现, 很有可能是Nginx配置文件中, 对80端口的访问开启了301重定向.
请参考 [2.4节 第2)步], 再试一次.
4.2 acme_tiny.py文件错误
报错内容为:
Parsing account key...
Parsing CSR...
Registering account...
Already registered!
Verifying www.healchow.com...
Traceback (most recent call last):
File "acme_tiny.py", line 198, in <module>
main(sys.argv[1:])
File "acme_tiny.py", line 194, in main
signed_crt = get_crt(args.account_key, args.csr, args.acme_dir, log=LOGGER, CA=args.ca)
File "acme_tiny.py", line 123, in get_crt
wellknown_path, wellknown_url))
ValueError: Wrote file to /date/ssl/www/challenges/xxxxxxxxxx, but couldn't download https://www.healchow.com/.well-known/acme-challenge/xxxxxxxxxx
1) 解决方法一:
检查Nginx配置文件中对域名的解析是否正确, 请参考 [2.4节 第2)步];
如果有错误, 请修改之, 然后重启Nginx服务 service nginx restart
.
2) 解决方法二:
Nginx配置正确, 那就可能是 acme_tiny.py
脚本的问题导致的, 注释掉 acme_tiny.py
脚本中的下述内容:
try:
resp = urlopen(wellknown_url)
resp_data = resp.read().decode('utf8').strip()
assert resp_data == keyauthorization
except (IOError, AssertionError):
os.remove(wellknown_path)
raise ValueError("Wrote file to {0}, but couldn't download {1}".format(
wellknown_path, wellknown_url))
4.3 配置HTTPS后要做的工作
可参考博客:
WordPress 博客/网站配置了 https 后需要做的工作
解决WordPress设置错误的url网站不能访问的问题
参考资料
(全文完)
(感谢阅读, 转载请注明作者和出处 瘦风的南墙 , 请勿用于任何商业用途)