Certbot安装和申请免费Let's Encrypt证书,附一键生成脚本

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 已经反代的服务而写的,毕竟一个一个复制然后改端口也挺麻烦的。

全文完。

网站总访客数:Loading
网站总访问量:Loading
使用 Hugo 构建
主题 StackJimmy 设计
-->