WP 03 – 给你的网站开启 HTTPS (使用免费的 SSL 证书)

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 的请求会加上一把象征安全的所🔐

009-支持HTTPS的安全链接.jpg

出于安全与好看的考虑(你不想自己的网站总提示 不安全 吧:-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.comhealchow.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.com$request_uri;

        location /.well-known/acme-challenge/ {
            alias            /data/ssl/www/challenges/;
            try_files $uri = 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 , 若能出现下述内容, 说明此时的配置仍然正确.

010-测试ssl配置.jpg

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.com$request_uri;

        # 下述配置要注释掉, 并移动到443端口的server中:
        # location /.well-known/acme-challenge/ {
        #    alias            /data/ssl/www/challenges/;
        #    try_files $uri = 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" '
                      '$status $body_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_files $uri $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_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 {}
    }
}

(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" '
                      '$status $body_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.com$request_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 $uri $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_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网站不能访问的问题

参考资料

让你的网站免费加上https
如何申请免费好用的HTTPS证书Let’s Encrypt

(全文完)

瘦风的南
微信关注《瘦风的南墙》 在移动端阅读文章

(感谢阅读, 转载请注明作者和出处 瘦风的南墙 , 请勿用于任何商业用途)

——=== 访问 本站404页面 寻找遗失儿童 ===——

发表评论

你的个人信息不会被公开, 注意:标记为 * 的项必填。