[NOTE] 构建HTTPS

@hou说了许久,刚好上次申请的证书快过期了,这次把泛域名开启HTTPS的一些流程及注意事项记录一下。

UPDATE 2020/06/15

certbot 太难用了,说是自动更新,每次都不 work,换用 acme.sh

相关信息

  • certbot 0.39.0
  • python 2.7
  • CentOS 7
  • urllib3
  • requests 2.6

1.使用certbot申请证书

Certbot 利用Let’s encrypt自动申请证书,并可以自动更新证书。

安装Certbot

签署通配符证书需要 Certbot 0.22 以上。如果以前安装过certbot,一般是直接yum update即可。如果是全新安装,则如下:
先升级:

1
yum update -y

查看系统版本:

1
cat  /etc/centos-release CentOS Linux release 7.4.1708 (Core)

安装epel源:

1
yum install epel-release -y

安装certbot:

1
yum install certbot -y

查看certbot版本:

1
certbot --version certbot 0.39.0

注意:使用certbot可能会遇到urllib库无法调用的问题,解决方法如下:

1
2
3
4
5
6
7
pip uninstall urllib3
pip uninstall requests
pip uninstall chardet
yum remove python-requests
yum remove python-urllib3
pip install --upgrade --force-reinstall 'requests==2.6.0' urllib3
yum install certbot

申请证书

nuzar.top*.nuzar.top换成自己的域名:

1
certbot -d nuzar.top -d *.nuzar.top --manual --preferred-challenges dns-01 --server https://acme-v02.api.letsencrypt.org/directory certonly --agree-tos

输入应急邮箱,证书到期前会有邮件提示:

1
2
Enter email address (used for urgent renewal and security notices) (Enter 'c' to
cancel):

如果想跳过输入邮箱的步骤,可在申请命令后面加上:

1
--register-unsafely-without-email

之后出现如下提示:要公开记录申请该证书的IP地址,是否同意?不同意就无法继续。

1
2
3
4
5
6
7
8
-------------------------------------------------------------------------------
NOTE: The IP of this machine will be publicly logged as having requested this
certificate. If you're running certbot in manual mode on a machine that is not
your server, please ensure you're okay with that.

Are you OK with your IP being logged?
-------------------------------------------------------------------------------
(Y)es/(N)o: y

同意之后,出现如下提示,第一个“Press Enter to Continue”处直接回车,第二个“Press Enter to Continue”不要按回车

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
-------------------------------------------------------------------------------
Please deploy a DNS TXT record under the name
_acme-challenge.co1dawn.com with the following value:

iLS0NjcdP3RR1KphB6xbbVnKS_NS2uMW-xdDRzz85OM

Before continuing, verify the record is deployed.
-------------------------------------------------------------------------------
Press Enter to Continue #此处直接回车

-------------------------------------------------------------------------------
Please deploy a DNS TXT record under the name
_acme-challenge.nuzar.top with the following value:

f3V7aw5GPm5yzNsJFanQQaUFMyVQcqriUe3UjIDUHn0

Before continuing, verify the record is deployed.
-------------------------------------------------------------------------------
Press Enter to Continue #此处不要按回车

验证服务器

接上步中,需要在域名解析中添加TXT解析,_acme-challenge.nuzar.top,记录值为其提示的value,将其添加成功后,还需要等待一定时间使解析成功。

验证方法包括:

1
host -t txt _acme-challenge.nuzar.top

或:

1
dig -t txt _acme-challenge.nuzar.top @8.8.8.8

验证成功后,便可以回车了,之后会在目录/etc/letsencrypt/live/nuzar.top/中生成证书。

检查域名是否为泛域名:

1
openssl x509 -in /etc/letsencrypt/live/nuzar.top/fullchain.pem -noout -text

2.Nginx使用证书

证书存放

如果在二级域名的配置中,你也是参照我的文章,那么此时只需要将证书加到对应文件夹root/nginx/conf.crt中。

由于certbot可以自动更新证书,不管是从任何角度,此时都应该保持证书所在位置不变,因此我们可以将/etc/letsencrypt/映射到{pwd}/nginx/conf.crt下,让nginx容器直接读取到证书文件。

这样一来,当90天期限到期时,证书可以直接更新,而不需要再进行一些额外的操作。

如我的文件结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|-- conf.crt
| |-- accounts
| |-- archive
| |-- keys
| |-- live
| | |-- nuzar.top
| | | |-- cert1.pem
| | | |-- chain1.pem
| | | |-- fullchain1.pem
| | | `-- privkey1.pem
|-- conf.d
| `-- default.conf
|-- html
| `-- index.html
|-- nginx
`-- nginx.conf

这里放在哪其实没有太大关系,接下来在conf.d/default.conf中加入对443端口的监听,并且指明证书的位置(注意我们的nginx是容器环境,在存放证书时要注意是否放在了挂载卷的目录下)

HTTPS开启

接下来,就要修改Nginx的配置文件:

sudo vim /root/nginx/conf.d/default.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
server {
listen 443;
listen [::]:443;
server_name gitlab.nuzar.top;

# enable ssl
ssl on;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH EDH+aRSA !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4";

# config ssl certificate
ssl_certificate conf.crt/live/nuzar.top/fullchain.pem;
ssl_certificate_key conf.crt/live/nuzar.top/privkey.pem;

location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
root /usr/share/nginx/html;
}
location = /.well-known/acme-challenge/ {
return 404;
}
location / {
proxy_pass http://127.0.0.1:6080;
}
}

此段配置的含义:

  • listen:使Nginx监听443端口,即https默认的端口;

  • server_name:接受gitlab.nuzar.top的请求;(此步骤需要添加域名解析gitlab到主机地址,前文中有提到)

  • ssl_certificate:指定证书地址,注意路径

  • proxy_pass:将请求转发到http://127.0.0.1:6080

完成此步后,由于前文提到,容器的映射与之前有所不同,所以此时需要将容器删除

docker rm -f CONTAINER_ID,并重新运行一个新的容器

1
2
3
4
5
6
7
8
docker run -d -p 80:80 -p 443:443 \
-v $(pwd)/nginx/conf.d:/etc/nginx/conf.d:ro \
-v $(pwd)/nginx/conf.crt:/etc/nginx/conf.crt:ro \
-v $(pwd)/nginx/nginx.conf:/etc/nginx/nginx.conf:ro \
-v $(pwd)/logs/nginx:/var/log/nginx \
-v $(pwd)/nginx/html:/usr/share/nginx/html \
--restart=always --name=gateway --network=host \
nginx

3.证书自动更新

Let’s Encrypt 的 HTTPS 证书有效期只有90天,需要在即将到期时手动更新,这里借助 Systemd.timer 以及 Certbot 自动创建的 Systemd 服务进行自动更新(renew or renewal)

  1. 查看 certbot 自动更新是否启用

    1
    $ systemctl is-enabled certbot-renew.timer

    enabled

  2. 启用 certbot 自动更新

    1
    $ systemctl enable certbot-renew.timer
  3. 查看 certbot 自动更新是否运行

    1
    $ systemctl list-timers
  4. 启动 certbot 自动更新

    1
    $ systemctl start certbot-renew
  5. 利用脚本自动同步证书到Nginx的 /nginx/conf.crt路径下

    待完成,可以手动哦

4. 更新

  • 2020/03/31 update:

上述无法生效的情况下,可以选择使用手动更新:certbot renew,会在/etc/letsencrypt/archieve下生成新的证书(原证书依然在),同时/etc/letsencrypt/live下有活跃证书,软链接指向前者。

如果在更新中遇到报错的问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
certbot --nginx certonly
Traceback (most recent call last):
File "/usr/bin/certbot", line 9, in <module>
load_entry_point('certbot==0.24.0', 'console_scripts', 'certbot')()
File "/usr/lib/python2.7/site-packages/pkg_resources.py", line 378, in load_entry_point
return get_distribution(dist).load_entry_point(group, name)
File "/usr/lib/python2.7/site-packages/pkg_resources.py", line 2566, in load_entry_point
return ep.load()
File "/usr/lib/python2.7/site-packages/pkg_resources.py", line 2260, in load
entry = __import__(self.module_name, globals(),globals(), ['__name__'])
File "/usr/lib/python2.7/site-packages/certbot/main.py", line 17, in <module>
from certbot import account
File "/usr/lib/python2.7/site-packages/certbot/account.py", line 17, in <module>
from acme import messages
File "/usr/lib/python2.7/site-packages/acme/messages.py", line 7, in <module>
from acme import challenges
File "/usr/lib/python2.7/site-packages/acme/challenges.py", line 11, in <module>
import requests
File "/usr/lib/python2.7/site-packages/requests/__init__.py", line 58, in <module>
from . import utils
File "/usr/lib/python2.7/site-packages/requests/utils.py", line 32, in <module>
from .exceptions import InvalidURL
File "/usr/lib/python2.7/site-packages/requests/exceptions.py", line 10, in <module>
from .packages.urllib3.exceptions import HTTPError as BaseHTTPError
File "/usr/lib/python2.7/site-packages/requests/packages/__init__.py", line 95, in load_module
raise ImportError("No module named '%s'" % (name,))
ImportError: No module named 'requests.packages.urllib3'

这是由于系统更新时,会将request urllib等库更新,导致certbot脚本不可用,重新回退可解:

1
pip2.7 install --upgrade --force-reinstall 'requests==2.6.0' urllib3

acme.sh

参见文档,已经写得很详细了,主要是在验证域名所有权这一步,需要衡量一下操作便利性和安全性,我这里直接使用阿里云提供的 AccessKey 进行访问,https://usercenter.console.aliyun.com/#/manage/ak

安装并申请证书

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 安装 acme.sh
$ curl https://get.acme.sh | sh

# AK 导入 env
$ export Ali_Key="YmFkYXNzbW90aGVyZnVja2VyCg"
$ export Ali_Secret="dHJ5aWZ5b3VjYW4K"
# It's fake access keys.

$ acme.sh --issue --dns dns_ali -d nuzar.top -d *.nuzar.top
-----END CERTIFICATE-----
[Tue Jun 16 16:00:48 CST 2020] Your cert is in /root/.acme.sh/nuzar.top/nuzar.top.cer
[Tue Jun 16 16:00:48 CST 2020] Your cert key is in /root/.acme.sh/nuzar.top/nuzar.top.key
[Tue Jun 16 16:00:48 CST 2020] The intermediate CA cert is in /root/.acme.sh/nuzar.top/ca.cer
[Tue Jun 16 16:00:48 CST 2020] And the full chain certs is there: /root/.acme.sh/nuzar.top/fullchain.cer

使用证书

1
2
3
4
$ acme.sh --installcert -d nuzar.top \
--key-file /root/nginx/conf.crt/live/nuzar.top/key.pem \
--fullchain-file /root/nginx/conf.crt/live/nuzar.top/full.pem \
--reloadcmd "docker exec gateway nginx -s reload"

更新 acme.sh

1
2
3
4
5
6
7
8
# 手动更新
$ acme.sh --upgrade

# 自动升级
$ acme.sh --upgrade --auto-upgrade

# 关闭自动更新
$ acme.sh --upgrade --auto-upgrade 0

听说你想请我喝杯奶茶😊?

WechatQRCode.png