跳转到内容

证书路径设置

证书路径设置

本节介绍 TLS 证书文件在 Docker 容器和宿主机之间的路径配置。正确的路径配置是 Mosquitto TLS 正常工作的前提。学习完成后,您将能够:

  • 正确配置证书文件路径
  • 管理证书文件的权限
  • 处理证书更新后的路径问题
  • 理解 Docker volume 挂载与路径的关系

在开始本节之前,请确保:

  • 已获取 Let’s Encrypt 证书
  • Mosquitto 使用 Docker 部署
  • 了解 Docker volume 挂载概念
/opt/mosquitto/
├── config/
│ ├── mosquitto.conf # Mosquitto 配置文件
│ ├── passwd # 密码文件
│ └── acl # 访问控制列表
├── certs/
│ ├── fullchain.pem # 服务器证书 + 中间证书链
│ └── privkey.pem # 服务器私钥
├── data/
│ └── mosquitto.db # 持久化数据
└── log/
└── mosquitto.log # 日志文件
# docker-compose.yml volumes 配置
volumes:
- ./config/mosquitto.conf:/mosquitto/config/mosquitto.conf:ro
- ./config/passwd:/mosquitto/config/passwd:ro
- ./config/acl:/mosquitto/config/acl:ro
- ./certs:/mosquitto/certs:ro # 证书文件
- ./data:/mosquitto/data # 数据持久化
- ./log:/mosquitto/log # 日志输出
/usr/local/bin/sync-certs.sh
#!/bin/bash
# 将 Let's Encrypt 证书同步到 Mosquitto 证书目录
DOMAIN="mqtt.example.com"
LETSENCRYPT_DIR="/etc/letsencrypt/live/${DOMAIN}"
MOSQUITTO_CERTS_DIR="/opt/mosquitto/certs"
echo "同步证书文件到 Mosquitto..."
# 检查 Let's Encrypt 证书是否存在
if [ ! -f "${LETSENCRYPT_DIR}/fullchain.pem" ]; then
echo "错误: Let's Encrypt 证书未找到: ${LETSENCRYPT_DIR}"
exit 1
fi
# 创建目标目录
mkdir -p "${MOSQUITTO_CERTS_DIR}"
# 复制证书文件(使用 cat 而非 cp -L 确保内容最新)
cat "${LETSENCRYPT_DIR}/fullchain.pem" > "${MOSQUITTO_CERTS_DIR}/fullchain.pem"
cat "${LETSENCRYPT_DIR}/privkey.pem" > "${MOSQUITTO_CERTS_DIR}/privkey.pem"
# 设置权限
chmod 644 "${MOSQUITTO_CERTS_DIR}/fullchain.pem"
chmod 600 "${MOSQUITTO_CERTS_DIR}/privkey.pem"
# 设置所有者(Mosquitto Docker 容器使用 UID 1883)
chown 1883:1883 "${MOSQUITTO_CERTS_DIR}/fullchain.pem"
chown 1883:1883 "${MOSQUITTO_CERTS_DIR}/privkey.pem"
echo "证书同步完成"
echo "请重新加载 Mosquitto: docker exec mosquitto kill -HUP 1"

配置 Certbot 在续期后自动同步证书:

# 创建续期后钩子
sudo tee /etc/letsencrypt/renewal-hooks/post/mosquitto.sh << 'EOF'
#!/bin/bash
# Let's Encrypt 续期后自动同步证书到 Mosquitto
DOMAIN="mqtt.example.com"
LETSENCRYPT_DIR="/etc/letsencrypt/live/${DOMAIN}"
MOSQUITTO_CERTS_DIR="/opt/mosquitto/certs"
cat "${LETSENCRYPT_DIR}/fullchain.pem" > "${MOSQUITTO_CERTS_DIR}/fullchain.pem"
cat "${LETSENCRYPT_DIR}/privkey.pem" > "${MOSQUITTO_CERTS_DIR}/privkey.pem"
chmod 644 "${MOSQUITTO_CERTS_DIR}/fullchain.pem"
chmod 600 "${MOSQUITTO_CERTS_DIR}/privkey.pem"
chown 1883:1883 "${MOSQUITTO_CERTS_DIR}/fullchain.pem"
chown 1883:1883 "${MOSQUITTO_CERTS_DIR}/privkey.pem"
# 重新加载 Mosquitto(发送 SIGHUP 信号)
docker exec mosquitto kill -HUP 1 2>/dev/null || true
EOF
# 设置执行权限
chmod +x /etc/letsencrypt/renewal-hooks/post/mosquitto.sh
# 测试续期钩子
sudo certbot renew --dry-run
mosquitto.conf
# 注意:路径是 Docker 容器内部的路径
# 证书文件(指向 /mosquitto/certs/ 目录)
cafile /mosquitto/certs/fullchain.pem
certfile /mosquitto/certs/fullchain.pem
keyfile /mosquitto/certs/privkey.pem

路径映射关系

宿主机路径Docker 容器内路径
/opt/mosquitto/certs//mosquitto/certs/
/opt/mosquitto/config/mosquitto.conf/mosquitto/config/mosquitto.conf
Terminal window
# 证书目录权限
drwxr-xr-x 2 root root 4096 May 18 10:00 /opt/mosquitto/certs/
# 证书文件权限
-rw-r--r-- 1 1883 1883 3500 May 18 10:00 fullchain.pem # 644
-rw------- 1 1883 1883 1700 May 18 10:00 privkey.pem # 600
# 配置文件权限
-rw-r--r-- 1 root root 1200 May 18 10:00 mosquitto.conf # 644

权限说明

文件权限理由
fullchain.pem644证书是公开信息,Mosquitto 读取
privkey.pem600私钥机密,仅 Mosquitto 进程读取
mosquitto.conf644配置文件,包含证书路径
Terminal window
# 错误: 私钥权限太大
sudo chmod 600 /opt/mosquitto/certs/privkey.pem
# 错误: Mosquitto 容器无法读取
# 检查 Mosquitto 内用户 ID
docker exec mosquitto id mosquitto
# uid=1883(mosquitto) gid=1883(mosquitto)
sudo chown -R 1883:1883 /opt/mosquitto/certs/
Terminal window
# 1. 检查证书文件是否存在
ls -la /opt/mosquitto/certs/
# 2. 验证证书文件格式
openssl x509 -in /opt/mosquitto/certs/fullchain.pem -text -noout | head -20
# 3. 验证证书未过期
openssl x509 -in /opt/mosquitto/certs/fullchain.pem -noout -dates
# notBefore=May 18 00:00:00 2026 GMT
# notAfter=Aug 16 00:00:00 2026 GMT
# 4. 验证证书域名
openssl x509 -in /opt/mosquitto/certs/fullchain.pem -noout -subject
# subject=CN = mqtt.example.com
# 5. 验证证书链完整性
openssl verify -CAfile /opt/mosquitto/certs/fullchain.pem \
/opt/mosquitto/certs/fullchain.pem
# fullchain.pem: OK
证书更新周期(Let's Encrypt 90 天自动续期):
Day 1: 第一次获取证书
Day 60: Certbot 自动检查并续期(30 天前开始尝试)
Day 90: 证书过期(如果未成功续期)
自动化流程:
1. Certbot 续期成功
2. Renewal hook 触发: sync-certs.sh
3. 证书同步到 Mosquitto certs 目录
4. Mosquitto 重新加载证书(SIGHUP)
5. 新客户端连接使用新证书
6. 已连接的客户端继续使用旧证书(不受影响)
Terminal window
# 手动续期并触发同步
sudo certbot renew --force-renewal
# 续期钩子自动执行
# 手动重新加载 Mosquitto
docker exec mosquitto kill -HUP 1
# 检查 Mosquitto 日志确认证书加载
docker logs mosquitto --tail 20
# 输出示例:
# 1726425607: OpenSSL reload: certfile /mosquitto/certs/fullchain.pem
要点说明常见错误
路径唯一性配置文件使用容器内路径误用宿主机路径
文件权限私钥 600,证书 644权限太高导致读取失败
自动同步续期钩子自动复制证书忘记配置导致证书过期
重新加载证书更新后需重新加载证书更新后未通知 Mosquitto

本节介绍了证书路径配置:

  1. 目录结构:certs/ 目录存放 fullchain.pem 和 privkey.pem
  2. 路径映射:宿主机 /opt/mosquitto/certs/ → 容器 /mosquitto/certs/
  3. 自动同步:创建同步脚本 + Certbot 续期钩子
  4. 权限管理:私钥 600,证书 644,所有者 1883:1883
  5. 验证流程:定期检查证书文件是否存在、是否过期、域名是否正确
  6. 证书更新:续期后自动同步并重新加载 Mosquitto