Certbot 申请 SSL 证书
Certbot 是一个由 Electronic Frontier Foundation (EFF) 开发的免费、开源的工具,用于自动化在 Web 服务器上部署 SSL/TLS 证书。SSL/TLS 证书是用于加密网站与用户之间传输的数据,确保数据传输的安全性和隐私性。
Certbot 支持大多数常见的 Web 服务器,包括 Apache、Nginx、IIS 等。
安装 certbot
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
# debian
sudo apt update
# 添加软件源
sudo apt install software-properties-common
sudo add-apt-repository ppa:certbot/certbot
# 安装certbot
sudo apt install certbot
# centos 没用,不太清楚,应该类似于debian
sudo yum update
此处省略添加软件源,请自己记得添加。。。
sudo yum install certbot
|
这里注意:一定要添加软件源,安装最新版本的 certbot,否则后面提示安装 dns 插件有问题
安装完成,查看版本 certbot --version
,目前是 2.9.0
官方使用 snap 安装的教程:
https://certbot.eff.org/instructions?ws=nginx&os=debianbuster
申请域名证书
使用 certbot 来申请 Let’s Encrypt 免费 CA 的 SSL 证书
官网教程
https://eff-certbot.readthedocs.io/en/latest/using.html#getting-certificates-and-choosing-plugins
1
2
|
# 比如,实际我没用,我使用的是下面的dns插件来获取
certbot certonly --webroot -w /path/to/your/website -d yourdomain.com
|
使用 Web 根目录/path/to/your/website
中的文件验证您拥有yourdomain.com
的控制权,并为该域名获取 SSL 证书。
DNS 获取 SSL 泛域名证书(推荐)
DNS 获取证书的好处在于可以申请泛域名证书,也就是像 *.seektao.cc
也就是一次申请,到处使用,方便至极。
certbot-dns-dnspod
certbot-dns-dnspod 是 dnspod 的插件,默认的 certbot 是没有的,需要手动安装
Github 地址
https://github.com/tengattack/certbot-dns-dnspod
1
2
3
4
5
6
7
8
9
|
# pip
sudo pip install git+https://github.com/tengattack/certbot-dns-dnspod.git
# snap 本次没有采用
sudo snap install certbot-dns-dnspod
sudo snap set certbot trust-plugin-with-root=ok
sudo snap connect certbot:plugin certbot-dns-dnspod
|
安装完成之后新建一个 .ini 文件,比如 /etc/certbot/dnspod.ini
1
2
|
sudo mkdir /etc/certbot
sudo touch /etc/certbot/dnspod.ini
|
编辑 dnspod.ini,填入下面的内容,点此跳转到 dnspod api 申请页面,注意申请的是 dnspod token
1
2
|
dns_dnspod_api_id = 12345
dns_dnspod_api_token = 1234567890abcdef1234567890abcdef
|
1
|
sudo chmod 600 /etc/certbot/dnspod.ini
|
申请,替换为自己的域名
1
2
3
4
5
6
7
8
9
10
11
12
|
sudo certbot certonly -a dns-dnspod \
--dns-dnspod-credentials /etc/certbot/dnspod.ini \
-d seektao.cc \
-d "*.seektao.cc"
接着就是:
输入邮箱,
是否同意注册acme(选Y),
是否同意发送邮件。。。看自己吧
接着等待,等待。。就完成了
|
通过日志可以看到证书文件保存在 /etc/letsencrypt/live
1
2
3
4
5
|
# 其中
[cert name]/privkey.pem:证书的私钥。
[cert name]/fullchain.pem:在大多数服务器软件中使用的证书文件。
[cert name]/chain.pem:在Nginx >=1.3.7 中用于 OCSP stapling。
[cert name]/cert.pem:会破坏许多服务器配置,不应在未进一步阅读文档的情况下使用。
|
我们用到 privkey.pem,fullchain.pem 即可。
此节关于 dnspod 申请 ssl 证书就是如此。
自动续期
自动续期添加一个定时任务即可
1
2
3
4
5
|
# 设置定时任务
sudo crontab -e
# 每月1号的午夜执行 certbot renew 命令来续订证书
0 0 1 * * /usr/local/bin/certbot renew
|
需要注意自己的 certbot 执行路径是否正确
which certbot
可以看到 certbot 执行路径
关于续期的更多文档可以观看
https://eff-certbot.readthedocs.io/en/latest/using.html#setting-up-automated-renewal
Nginx 一键生成模板
需求 1
这个需求在于我使用 Nginx 作为反代服务器,每新增一个服务,就要手动去新增一个 nginx 文件,而且我主要使用的是二级域名加端口的模式,配合使用 泛域名证书来编写这个脚本就很方便了。
现在想要实现输入 脚本文件 域名 端口
就会在 /etc/nginx/conf.d/
下新增一个以域名开头的配置文件,例如:
1
2
3
4
5
6
|
$ sudo ./generate_nginx_simple_template.sh test1.seektao.cc 5980
Do you want to reload Nginx configuration? (y/n) y
Reloading Nginx configuration...
$ ll /etc/nginx/conf.d/test1.conf
-rw-r--r-- 1 root root 965 Mar 25 13:01 /etc/nginx/conf.d/test1.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
27
28
29
30
31
32
33
|
$ cat /etc/nginx/conf.d/test1.conf
server {
listen 80;
server_name test1.seektao.cc;
return 301 $scheme://test1.seektao.cc$request_uri;
}
server {
listen 443 ssl http2;
server_name test1.seektao.cc;
# SSL 证书配置
ssl_certificate /etc/letsencrypt/live/seektao.cc/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/seektao.cc/privkey.pem;
# 安全设置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# 反向代理
location / {
proxy_pass http://127.0.0.1:5980/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# 日志配置
access_log /var/log/nginx/test1.seektao.cc.access.log;
error_log /var/log/nginx/test1.seektao.cc.error.log;
}
|
需求 1 脚本的配置
使用这个脚本请先申请泛域名证书,或者你自己再修改配置文件的证书位置。
vim generate_nginx_simple_template.sh
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
#!/bin/bash
# 检查参数数量
if [ "$#" -ne 2 ]; then
echo "Usage: $0 <domain> <application_port>"
exit 1
fi
DOMAIN=$1
APPLICATION_PORT=$2
PORT_HTTP=80
PORT_HTTPS=443
CERT_DOMAIN=$(echo "$DOMAIN" | awk -F. '{print $(NF-1)"."$NF}')
CONF_FILE_PREFIX=$(echo "$DOMAIN" | awk -F. '{print $1}')
CONF_FILE="/etc/nginx/conf.d/${CONF_FILE_PREFIX}.conf"
# 生成 Nginx 配置内容
cat <<EOF > $CONF_FILE
server {
listen $PORT_HTTP;
server_name $DOMAIN;
return 301 \$scheme://$DOMAIN\$request_uri;
}
server {
listen $PORT_HTTPS ssl http2;
server_name $DOMAIN;
# SSL 证书配置
ssl_certificate /etc/letsencrypt/live/$CERT_DOMAIN/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/$CERT_DOMAIN/privkey.pem;
# 安全设置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# 反向代理
location / {
proxy_pass http://127.0.0.1:$APPLICATION_PORT/;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
}
# 日志配置
access_log /var/log/nginx/$DOMAIN.access.log;
error_log /var/log/nginx/$DOMAIN.error.log;
}
EOF
# 检查临时文件是否成功创建
if [ ! -f "${CONF_FILE}" ]; then
echo "Error: Failed to create temporary configuration file."
exit 1
fi
# 提示用户是否需要修改配置文件
# read -p "Do you want to modify the configuration file before saving? (y/n) " choice
# 根据用户选择执行相应操作
# case "$choice" in
# y|Y )
# # 使用文本编辑器让用户修改配置文件
# echo "Editing configuration file..."
# vim "${CONF_FILE}" # 或者使用你喜欢的其他文本编辑器,如 nano
# ;;
# n|N )
# # 直接将临时文件移动到目标位置
# echo "Saving configuration file without modification..."
# mv "${CONF_FILE}" "${CONF_FILE}"
# ;;
# * )
# echo "Invalid choice. Exiting..."
# exit 1
# ;;
# esac
# 检查 SSL 证书路径是否存在,如果不存在,提示用户手动申请
if [ ! -e "/etc/letsencrypt/live/$CERT_DOMAIN/fullchain.pem" ]; then
echo "Warning: SSL certificate for $CERT_DOMAIN does not exist."
echo "Please use certbot or another tool to manually obtain a certificate for $CERT_DOMAIN."
fi
# 提示用户是否需要重新加载 Nginx 配置
read -p "Do you want to reload Nginx configuration? (y/n) " reload_choice
case "$reload_choice" in
y|Y )
# 重新加载 Nginx 配置
echo "Reloading Nginx configuration..."
sudo nginx -s reload
;;
n|N )
echo "Nginx configuration will not be reloaded."
;;
* )
echo "Invalid choice. Exiting..."
exit 1
;;
esac
|
需求 2
此内容为更新内容:
和需求 1 不同的是:生成的 nginx 配置文件为域名.conf
而非 域名前缀.conf
这么做的目的是我在使用多个不同域名方便区分配置文件,特此更改。
以下内容为正文:从需求 1 复制更改
这个需求在于我使用 Nginx 作为反代服务器,每新增一个服务,就要手动去新增一个 nginx 文件,而且我主要使用的是二级域名加端口的模式,配合使用 泛域名证书来编写这个脚本就很方便了。
现在想要实现输入 脚本文件 域名 端口
就会在 /etc/nginx/conf.d/
下新增一个以全域名开头的配置文件,例如:
1
2
3
4
5
6
|
$ sudo ./generate_nginx_simple_template.sh test1.seektao.cc 5980
Do you want to reload Nginx configuration? (y/n) y
Reloading Nginx configuration...
$ ll /etc/nginx/conf.d/test1.seektao.cc.conf
-rw-r--r-- 1 root root 965 Mar 25 13:01 /etc/nginx/conf.d/test1.seektao.cc.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
27
28
29
30
31
32
33
|
$ cat /etc/nginx/conf.d/test1.seektao.cc.conf
server {
listen 80;
server_name test1.seektao.cc;
return 301 $scheme://test1.seektao.cc$request_uri;
}
server {
listen 443 ssl http2;
server_name test1.seektao.cc;
# SSL 证书配置
ssl_certificate /etc/letsencrypt/live/seektao.cc/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/seektao.cc/privkey.pem;
# 安全设置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# 反向代理
location / {
proxy_pass http://127.0.0.1:5980/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# 日志配置
access_log /var/log/nginx/test1.seektao.cc.access.log;
error_log /var/log/nginx/test1.seektao.cc.error.log;
}
|
需求 2 脚本的配置
使用这个脚本请先申请泛域名证书,或者你自己再修改配置文件的证书位置。
vim generate_nginx_simple_template1.sh
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
#!/bin/bash
# 检查参数数量
if [ "$#" -ne 2 ]; then
echo "Usage: $0 <domain> <application_port>"
exit 1
fi
DOMAIN=$1
APPLICATION_PORT=$2
PORT_HTTP=80
PORT_HTTPS=443
CERT_DOMAIN=$(echo "$DOMAIN" | awk -F. '{print $(NF-1)"."$NF}')
CONF_FILE_PREFIX=$(echo "$DOMAIN")
CONF_FILE="/etc/nginx/conf.d/${CONF_FILE_PREFIX}.conf"
# 生成 Nginx 配置内容
cat <<EOF > $CONF_FILE
server {
listen $PORT_HTTP;
server_name $DOMAIN;
return 301 \$scheme://$DOMAIN\$request_uri;
}
server {
listen $PORT_HTTPS ssl http2;
server_name $DOMAIN;
# SSL 证书配置
ssl_certificate /etc/letsencrypt/live/$CERT_DOMAIN/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/$CERT_DOMAIN/privkey.pem;
# 安全设置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# 反向代理
location / {
proxy_pass http://127.0.0.1:$APPLICATION_PORT/;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
}
# 日志配置
access_log /var/log/nginx/$DOMAIN.access.log;
error_log /var/log/nginx/$DOMAIN.error.log;
}
EOF
# 检查临时文件是否成功创建
if [ ! -f "${CONF_FILE}" ]; then
echo "Error: Failed to create temporary configuration file."
exit 1
fi
# 提示用户是否需要修改配置文件
# read -p "Do you want to modify the configuration file before saving? (y/n) " choice
# 根据用户选择执行相应操作
# case "$choice" in
# y|Y )
# # 使用文本编辑器让用户修改配置文件
# echo "Editing configuration file..."
# vim "${CONF_FILE}" # 或者使用你喜欢的其他文本编辑器,如 nano
# ;;
# n|N )
# # 直接将临时文件移动到目标位置
# echo "Saving configuration file without modification..."
# mv "${CONF_FILE}" "${CONF_FILE}"
# ;;
# * )
# echo "Invalid choice. Exiting..."
# exit 1
# ;;
# esac
# 检查 SSL 证书路径是否存在,如果不存在,提示用户手动申请
if [ ! -e "/etc/letsencrypt/live/$CERT_DOMAIN/fullchain.pem" ]; then
echo "Warning: SSL certificate for $CERT_DOMAIN does not exist."
echo "Please use certbot or another tool to manually obtain a certificate for $CERT_DOMAIN."
fi
# 提示用户是否需要重新加载 Nginx 配置
read -p "Do you want to reload Nginx configuration? (y/n) " reload_choice
case "$reload_choice" in
y|Y )
# 重新加载 Nginx 配置
echo "Reloading Nginx configuration..."
sudo nginx -s reload
;;
n|N )
echo "Nginx configuration will not be reloaded."
;;
* )
echo "Invalid choice. Exiting..."
exit 1
;;
esac
|
后话
在编写这篇教程之前,我一直都是用的是 Nginx Proxy Manager (简称 NPM)图形化管理界面,觉得 Nginx 配置看不懂,太复杂,对 Nginx 也不太懂。
教程的前一天,我想使用 Nginx Proxy Manager 为反代的服务添加 location 片段,却会导致添加了 location 的服务挂掉,不论是图形化添加还是修改配置文件,我还以为是我的配置姿势不对,添加的 location 内容有错,后面找了很久的资料,却没能找到解决办法,最后还是在 NPM 的 Github issues 很多人出现了这个问题,而且没有一个合适的解决方案,NPM 的 bug。唉,一不做,二不休,不如直接用 Nginx,还少去了 NPM 占据了一部分内存。
安装 Nginx 的过程还是很愉快的。但是对于 ssl 证书我又了解甚少了,对此又花费了很多精力去了解 certbot,结果 apt 安装的 certbot 没有 dnspod 插件??我一个大问号,又卸载了 apt 方式安装的 certbot,去安装 snap,通过 snap 安装 certbot,我发现 snap 也有问题??但是找到了 snap 上 GitHub 上的 dnspod 插件,也支持 snap,然后又卸载 certbot,snap,重新通过 apt 安装 certbot,然后下载 dnspod,结果又在申请证书的时候出错了。原来我为了简便,dnspod.ini 用的是 NPM 之前的配置。后来改了就好了。
现在只差反代了,上面的脚本也是为了我在 NPM 已经反代的服务而写的,毕竟一个一个复制然后改端口也挺麻烦的。
全文完。