在阿里云服务器ECS上搭建SSL+Git+Docker环境(三)

服务器   2024-09-23 16:42   440   0  

安装完 nginx 后 ,要实现使用 https 访问系统,需要申请域名证书。这里介绍如何申请一种免费的通配符证书 —— Let’s Encrypt,它是一家免费、开放、自动化的公益性证书颁发机构(CA), 由互联网安全研究组(ISRG)运作。

一、什么是 Let’s Encrypt

部署 HTTPS 网站的时候需要证书,证书由 CA 机构签发,大部分传统 CA 机构签发证书是需要收费的,这不利于推动 HTTPS 协议的使用。

Let’s Encrypt 也是一个 CA 机构,但这个 CA 机构是免费的!!!也就是说签发证书不需要任何费用。

Let’s Encrypt 由于是非盈利性的组织,需要控制开支,他们搞了一个非常有创意的事情,设计了一个 ACME 协议。

那为什么要创建 ACME 协议呢,传统的 CA 机构是人工受理证书申请、证书更新、证书撤销,完全是手动处理的。而 ACME 协议规范化了证书申请、更新、撤销等流程,只要一个客户端实现了该协议的功能,通过客户端就可以向 Let’s Encrypt 申请证书,也就是说 Let’s Encrypt CA 完全是自动化操作的。

任何人都可以基于 ACME 协议实现一个客户端,官方推荐的客户端是Certbot 。

二、什么是通配符证书

Let’s Encrypt 支持两种证书。

1)单域名证书:证书仅仅包含一个主机。

2)SAN 证书:通配符证书,一张证书可以包括多个主机(Let’s Encrypt 限制是 20),也就是证书可以包含下列的主机:www.example.com、www.example.cn、blog.example.com 等等。

证书包含的主机可以不是同一个注册域,注册域就是向域名注册商购买的域名。

对于个人用户来说,由于主机并不是太多,所以使用 SAN 证书完全没有问题,但是对于大公司来说有一些问题:

子域名非常多,而且过一段时间可能就要使用一个新的主机,注册域也非常多。

对于大企业来说,SAN 证书可能并不能满足需求,类似于 sina 这样的网站,所有的主机全部包含在一张证书中,而使用 Let’s Encrypt 证书是无法满足的。

通配符证书就是证书中可以包含一个通配符,比如 .example.com、.example.cn。

为了实现通配符证书,Let’s Encrypt 对 ACME 协议的实现进行了升级,只有 v2 协议才能支持通配符证书。

客户在申请 Let’s Encrypt 证书的时候,需要校验域名的所有权,证明操作者有权利为该域名申请证书,目前支持三种验证方式:

dns-01:给域名添加一个 DNS TXT 记录。

http-01:在域名对应的 Web 服务器下放置一个 HTTP well-known URL 资源文件。

tls-sni-01:在域名对应的 Web 服务器下放置一个 HTTPS well-known URL 资源文件。

而申请通配符证书,只能使用 dns-01 的方式

三、申请 Let’s Encrypt 通配符证书

申请 Let’s Encrypt 通配符证书需要有对云服务器的命令行控制权限,要在服务器上安装 certbot,依据服务器环境申请安装的方法有很多,具体可参考官网的文档。这里以我的云服务器环境为例介绍。服务器采用 nginx 提供 web 服务,并且服务器安装有 Python。

这里需要注意一个坑,云服务器自带的 Python 有 Python2.7 和 Python3.6两个版本,都太低,安装 certbot 需要 Python3.6 以上版本,所以需要手动安装 Python 更高版本,比如 Python 3.9。切记不要删除云服务器上的 Python,会导致很多错误。

(一)、使用源码安装 Python 3.9

1、安装依赖包

yum install -y zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gcc make libffi-devel

这些依赖包是编译Python 3.9所必需的。

2、下载并解压 Python 3.9 源代码

直接使用 wget 命令在终端中从官网下载并解压:

wget https://www.python.org/ftp/python/3.9.20/Python-3.9.20.tgz 
tar -zxvf Python-3.9.20.tgz

解压后,你将得到一个名为Python-3.9.0的文件夹。

3、编译与安装

切换到解压后的目录中,开始编译和安装Python 3.9:

cd Python-3.9.0  
./configure --prefix=/usr/local/python3.9  
make -j $(nproc)  
make altinstall

这里使用了--prefix选项来指定Python的安装路径(这里是/usr/local/python3.9),以避免与系统默认的Python版本冲突。

make -j $(nproc)会使用所有可用的CPU核心来加速编译过程。

make altinstall 会安装Python 3.9,但不会替换系统默认的Python版本。

安装完成后,你可以通过以下命令来验证Python 3.9是否安装成功

/usr/local/python3.9/bin/python3.9 --version

4、设置环境变量

为了方便使用新安装的Python 3.9,你可以将其路径添加到环境变量中。编辑你的bash配置文件(如~/.bashrc或~/.bash_profile),在文件末尾添加以下行:

export PATH=$PATH:/usr/local/python3.9/bin

然后,执行source ~/.bashrc(或相应的配置文件)来使更改生效。之后,你就可以在终端中直接使用python3.9命令来启动Python 3.9了。


(二)、安装 certbot

这里以申请通配符证书为例介绍,单域名证书的申请方法参考官网的文档

1、删除 certbot-auto 和所有 certbot 系统包

如果之前安装过任何Certbot包,应该在安装之前将它们移除,以确保运行certbot命令时,使用的是最新的包而不是来自操作系统包管理器的安装版本。

yum remove certbot

2、设置 Python 虚拟环境

python3.9 -m venv /opt/certbot/
/opt/certbot/bin/pip install --upgrade pip

3、安装 certbot 

/opt/certbot/bin/pip install certbot

4、准备 Certbot 命令

ln -s /opt/certbot/bin/certbot /usr/bin/certbot

到此 certbot 安装完成,并可以在系统任意位置使用 certbot 命令。

(三)、申请证书并自动续期

想要申请通配符证书,并自动续期,按官方文档的介绍需要使用 dns 插件,但是官方文档的 dns 插件不适用于国内,这里介绍一个开源的 hook,通过它来实现。

1、下载 hook,并放入 certbot  的安装目录中 

cd /opt/certbot
git clone https://github.com/ywdblog/certbot-letencrypt-wildcardcertificates-alydns-au
mv certbot-letencrypt-wildcardcertificates-alydns-au auto_run
cd auto_run
chmod 0777 au.sh

2、修改配置

(1)domain.ini

如果domain.ini文件没有你的根域名,请自行添加。

(2)DNS API 密钥:

这个 API 密钥什么意思呢?由于需要通过 API 操作阿里云 DNS 或腾讯云 DNS 的记录,所以需要去域名服务商哪儿获取 API 密钥,然后配置在 au.sh 文件中:

- ALY_KEY 和 ALY_TOKEN:阿里云 [API key 和 Secrec 官方申请文档](https://help.aliyun.com/knowledge_detail/38738.html)。

- TXY_KEY 和 TXY_TOKEN:腾讯云 [API 密钥官方申请文档](https://console.cloud.tencent.com/cam/capi)。

- GODADDY_KEY 和 GODADDY_TOKEN:GoDaddy [API 密钥官方申请文档](https://developer.godaddy.com/getstarted)。

(3)选择运行环境

目前该工具支持五种运行环境和场景,通过 hook 文件和参数来调用:

- PHP(>4以上版本均可)

- au.sh php aly add/clean:PHP操作阿里云DNS,增加/清空DNS。

- au.sh php txy add/clean:PHP操作腾讯云DNS,增加/清空DNS。

- au.sh php godaddy add/clean:PHP操作GoDaddy DNS,增加/清空DNS。

- Python(支持2.7和3.7,无需任何第三方库)

- au.sh python aly add/clean:Python操作阿里云DNS,增加/清空DNS。

- au.sh python txy add/clean:Python操作腾讯云DNS,增加/清空DNS。

 - au.sh python godaddy add/clean:Python操作GoDaddy DNS,增加/清空DNS。

根据自己服务器环境和域名服务商选择任意一个 hook shell(包含相应参数),具体使用见下面。

3、申请证书

测试是否有错误,操作 DNS API 可能会遇到一系列问题,比如 API token 权限不足,遇到相关问题,可以查看 /var/log/certbot/certd.log。

certbot certonly -d {your_domain} --manual --preferred-challenges dns --dry-run --manual-auth-hook "/opt/certbot/auto_run/au.sh python aly add" --manual-auth-hook "/opt/certbot/auto_run/au.sh python aly clean"

参数说明:


#certonly:表示采用验证模式,只会获取证书,不会为web服务器配置证书

#--manual:表示手动安装插件

#-d:表示需要为那个域名申请证书,可以有多个,比如 -d my_web.com -d *.my_web.com,注意  *.my_web.com 并不包含 my_web.com,需要单独指明。

#--preferred-challenges dns:表示采用DNS验证申请者合法性(是不是域名的管理者)

#--dry-run: 表示在实际申请/更新证书前进行测试,强烈推荐,真实申请时,去掉该参数

#--manual-auth-hook:在执行命令的时候调用一个 hook 文件

#--manual-cleanup-hook:清除 DNS 添加的记录

--manual-auth-hook 和 --manual-cleanup-hook 有三个参数:

第一个代表你要选择那种语言(php/python)

第二个参数代表你的DNS厂商(aly/txy)

第三个参数是固定的(--manual-auth-hook中用add,--manual-clean-hook中用clean)

比如你要选择PHP环境,可以将 --manual-auth-hook 输入修改为 "/脚本目录/au.sh php aly add",--manual-cleanup-hook 输入修改为 "/脚本目录/au.sh php aly clean"

 如果你想为多个域名申请通配符证书(合并在一张证书中,也叫做 SAN 通配符证书),直接输入多个 -d 参数即可,比如:

-d *.example.com -d *.example.org -d www.example.cn

最后生成的证书和私钥将会放在/etc/letsencrypt/live/{your_domain}/下,{your_domain}是申请的域名,多个域名取第一个


确认无误后,实际运行(去除 --dry-run 参数):


certbot certonly -d {your_domain} --manual --preferred-challenges dns --manual-auth-hook "/opt/certbot/auto_run/au.sh python aly add" --manual-auth-hook "/opt/certbot/auto_run/au.sh python aly clean"

自动申请通配符证书(会自动添加DNS的TXT记录,生成证书后自动删除)

certbot 执行的日志存放在 /var/log/letsencrypt/letsencrypt.log


4、自动续期证书

申请的免费 ssl 证书有效期只有 90 天,到期前30天内需要续期。

(1)对服务器上所有证书 renew

certbot renew --manual --preferred-challenges dns --manual-auth-hook "/opt/certbot/auto_run/au.sh python aly add" --manual-auth-hook "/opt/certbot/auto_run/au.sh python aly clean"

(2)对某一张证书进行续期

先看看机器上有多少证书:

certbot certificates

可以看到所有证书列表,记住证书名,比如 simplehttps.com,然后运行下列命令 renew:

certbot renew --cert-name simplehttps.com --manual --preferred-challenges dns --manual-auth-hook "/opt/certbot/auto_run/au.sh python aly add" --manual-auth-hook "/opt/certbot/auto_run/au.sh python aly clean"

(3)加入 crontab 自动续期

自动申请和续期证书命令过长,可以将这两个命令分别写入shell脚本文件,方便执行,比如在 /opt/certbot/auto_run 目录中新建两个脚本 auto_create.sh 和 auto_renew.sh,并对文件增加可执行权限:

chmod +x /opt/certbot/auto_run/auto_create.sh
chmod +x /opt/certbot/auto_run/auto_renew.sh

auto_create.sh 内容如下,{your_domain} 替换成你自己的域名,执行该脚本直接申请证书:

#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

if [[ $EUID -ne 0 ]]; then
	echo "This script must be run as root"
	exit 1
fi

# 临时禁用,不需要重启(推荐)
setenforce 0
certbot certonly -d {your_domain} --manual --preferred-challenges dns --manual-auth-hook "/opt/certbot/auto_run/au.sh python aly add" --manual-auth-hook "/opt/certbot/auto_run/au.sh python aly clean"

auto_renew.sh 内容如下,{your_domain} 是证书的名字,替换成你自己的证书名称,执行该脚本自动续期:

#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

if [[ $EUID -ne 0 ]]; then
	echo "This script must be run as root"
	exit 1
fi

# 临时禁用,不需要重启(推荐)
setenforce 0

certbot renew --cert-name {your_domain} --manual --preferred-challenges dns --deploy-hook  "/bin/systemctl reload nginx" --manual-auth-hook "/opt/certbot/auto_run/au.sh python aly add" --manual-cleanup-hook "/opt/certbot/auto_run/au.sh python aly clean" >> /var/log/certbot/renewal.log

其中 --deploy-hook  "/bin/systemctl reload nginx"  的作用是证书续期成功后,自动重启 nginx。

注意:只有单机建议这样运行,如果要将证书同步到多台web服务器,需要有别的方案。


将自动续期脚本加入定时任务,每周一凌晨一点执行一次,检查证书是否过期,快过期自动更新

crontab -e
0 1 * * 1 /opt/certbot/auto_run/auto_renew.sh
systemctl reload crond


至此申请 ssl 证书及自动续期就已经完成。要实现正确解析ssl,还需要添加一个 dhparam.pem 文件,用来存放DH密钥交换协议所需的参数文件

openssl dhparam -out /etc/nginx/certs/dhparam.pem 2048

该文件路径已经在 在阿里云服务器ECS上搭建SSL+Git+Docker环境(二)中设置过。