网站通过 certbot 生成免费的 SSL 证书

一、安装依赖

安装 Certbot 和 Nginx 插件

# 对于Ubuntu/Debian系统
sudo apt update
sudo apt install certbot python3-certbot-nginx

# 对于CentOS/RHEL系统
sudo yum install epel-release
sudo yum install certbot python3-certbot-nginx

二、生成证书

# 1、切换到项目目录
cd /home/ubuntu/Code/nofx

# 2、生成证书
sudo certbot certonly --manual --preferred-challenges dns   -d tradingbit.ai   -d www.tradingbit.ai

示例:

## 生成SSL证书(2025/06/16 17:40)
ubuntu@AwesomeStrategy-Freqtrade:~/stamp-website$ sudo certbot certonly --manual --preferred-challenges dns   -d stamp-src20.com   -d www.stamp-src20.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for stamp-src20.com and www.stamp-src20.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name:

_acme-challenge.www.stamp-src20.com.

with the following value:

o13IitbvB9HO9qDO37kBln1epuIvQBfSJqU1r-6mzfY

Before continuing, verify the TXT record has been deployed. Depending on the DNS
provider, this may take some time, from a few seconds to multiple minutes. You can
check if it has finished deploying with aid of online tools, such as the Google
Admin Toolbox: https://toolbox.googleapps.com/apps/dig/#TXT/_acme-challenge.www.stamp-src20.com.
Look for one or more bolded line(s) below the line ';ANSWER'. It should show the
value(s) you've just added.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/stamp-src20.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/stamp-src20.com/privkey.pem
This certificate expires on 2025-09-14.
These files will be updated when the certificate renews.

NEXT STEPS:
- This certificate will not be renewed automatically. Autorenewal of --manual certificates requires the use of an authentication hook script (--manual-auth-hook) but one was not provided. To renew this certificate, repeat this same certbot command before the certificate's expiry date.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
 * Donating to EFF:                    https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

# 查看
sudo cd /etc/letsencrypt/live/stamp-src20.com

docker run -d \
  -p 80:80 \
  -p 443:443 \
  -v /etc/letsencrypt:/etc/letsencrypt \          # 挂载宿主机证书目录
  -v /var/www/certbot:/var/www/certbot \          # 挂载验证文件目录
  --restart unless-stopped \                      # 自动重启
  --name stamp-website \
  stamp-website

  # 在宿主机创建目录并设置权限
sudo mkdir -p /var/www/certbot/.well-known/acme-challenge
sudo chmod -R 755
 /var/www/certbot

# 验证目录结构
ls -la /var/www/certbot/.well-known/acme-challenge

## 证书自动续期
以下是针对 Docker 容器与宿主机共享 Certbot 证书的优化方案,确保自动续期和证书同步:

---

### **1. 修改后的 Dockerfile**
```dockerfile
# 使用Node.js作为构建环境
FROM node:18-alpine AS builder

WORKDIR /app

# 复制package文件
COPY package*.json ./
COPY pnpm-lock.yaml ./

# 安装pnpm并安装依赖
RUN npm install -g pnpm
RUN pnpm install

# 复制源代码
COPY . .

# 构建应用
RUN pnpm run build

# 使用Nginx作为生产环境
FROM nginx:alpine

# 创建必要的目录(无需复制证书,通过挂载实现)
RUN mkdir -p /var/www/certbot && \
    mkdir -p /etc/letsencrypt/live/stamp-src20.com

# 复制构建文件和Nginx配置
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf

# 暴露端口
EXPOSE 80 443

# 启动Nginx
CMD ["nginx", "-g", "daemon off;"]

关键修改

  1. 移除 COPY 证书的指令(改为运行时挂载)
  2. 保留目录创建命令(确保挂载点存在)

2. 容器运行命令优化

sudo docker run -d \
  -p 80:80 \
  -p 443:443 \
  -v /etc/letsencrypt:/etc/letsencrypt \          # 挂载宿主机证书目录
  -v /var/www/certbot:/var/www/certbot \          # 挂载验证文件目录
  --restart unless-stopped \                      # 自动重启
  --name stamp-website \
  stamp-website
挂载说明 宿主机路径 容器路径 用途
/etc/letsencrypt /etc/letsencrypt 证书自动同步
/var/www/certbot /var/www/certbot Certbot 验证文件

3. 证书自动续期方案

(1)在宿主机设置续期脚本

创建 /usr/local/bin/renew_cert.sh

#!/bin/bash
# 续期证书
certbot renew --quiet --force-renewal

# 重启容器使新证书生效
docker restart stamp-website

赋予执行权限:

sudo chmod +x /usr/local/bin/renew_cert.sh

(2)添加 cron 任务

(sudo crontab -l 2>/dev/null; echo "0 3 * * * /usr/local/bin/renew_cert.sh") | sudo crontab -

4. Nginx 配置验证

您的 nginx.conf 配置完全正确,但需确保:

  1. 证书路径与挂载路径一致
    ssl_certificate /etc/letsencrypt/live/stamp-src20.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/stamp-src20.com/privkey.pem;
  2. 验证文件目录存在
    location ^~ /.well-known/acme-challenge/ {
       root /var/www/certbot;
       default_type "text/plain";
    }

5. 验证流程

  1. 检查挂载是否生效

    docker exec stamp-website ls /etc/letsencrypt/live/stamp-src20.com
    # 应显示 fullchain.pem 和 privkey.pem
  2. 测试证书续期

    sudo /usr/local/bin/renew_cert.sh
    docker logs stamp-website | grep "SSL"
  3. 检查 HTTPS 访问

    curl -vk https://stamp-src20.com

6. 关键注意事项

  1. 权限问题

    • 确保容器用户(通常为 nginx)有证书文件的读取权限:
      sudo chmod -R 755 /etc/letsencrypt/{live,archive}
  2. 证书符号链接

    • Certbot 使用符号链接管理证书,挂载时需保持链接结构:
      ls -l /etc/letsencrypt/live/stamp-src20.com
      # 应显示:
      # lrwxrwxrwx 1 root root  42 Jan 1 00:00 fullchain.pem -> ../../archive/stamp-src20.com/fullchain1.pem
  3. 备份建议

    # 定期备份证书
    sudo cp -r /etc/letsencrypt /backup/letsencrypt_$(date +%Y%m%d)

架构示意图

graph TD
    A[宿主机] -->|挂载| B[Docker容器]
    A --> C[/etc/letsencrypt]
    A --> D[/var/www/certbot]
    B --> E[Nginx]
    E -->|读取| C
    E -->|验证文件| D
    F[Certbot] -->|续期| C
    F -->|验证| D

按此方案配置后,证书可自动续期并实时同步到容器,无需手动干预。

为者常成,行者常至