CamelzNav配置docker compose,nginx,certbot
nav.xiagao.site配置docker compose,nginx,certbot
我会按照 背景 → 镜像构建 → Docker Compose → 证书申请 → 自动续签与监控 的顺序整理,并标明关键点和注意事项。
📝 Camelznav Docker + Certbot-DNS-Aliyun 整体梳理
1️⃣ 背景与目标
- 使用 Docker 部署前后端 + nginx 的导航站 (
camelznav)。 - 使用 Certbot + DNS-01(阿里云 DNS 插件) 申请泛域名证书。
- 实现 自动续签 + nginx 无中断 reload + 续签失败邮件通知。
- 镜像存放在 Docker Hub (
camel52zhang/certbot-dns-aliyun) 供自己使用。
2️⃣ 构建 Certbot-DNS-Aliyun 镜像
Dockerfile 示例
FROM certbot/certbot:v2.11.0
# 安装构建依赖
RUN apk add --no-cache \
python3 \
py3-pip \
gcc \
musl-dev \
libffi-dev \
openssl-dev
# 安装 certbot-dns-aliyun
RUN pip install --no-cache-dir certbot-dns-aliyun
# 验证插件是否安装成功(构建时检查)
RUN certbot plugins构建与推送
docker build -t camel52zhang/certbot-dns-aliyun:latest .
docker tag camel52zhang/certbot-dns-aliyun:latest camel52zhang/certbot-dns-aliyun:v2.11.0
docker push camel52zhang/certbot-dns-aliyun:latest
docker push camel52zhang/certbot-dns-aliyun:v2.11.0✅ 注意点:
- 固定 certbot 版本更稳定。
使用
docker run --rm camel52zhang/certbot-dns-aliyun:latest plugins检查插件加载。# 看到类似: dns-aliyun如果能看到,说明插件 OK ✅,以后即可随时拉取使用了
3️⃣ Docker Compose 配置
compose 文件结构
services:
certbot:
image: camel52zhang/certbot-dns-aliyun:latest
container_name: camelznav-certbot
volumes:
- ./certbot/letsencrypt:/etc/letsencrypt
- ./certbot/credentials.ini:/etc/letsencrypt/aliyun.ini:ro
command: >
certonly
--authenticator dns-aliyun
--dns-aliyun-credentials /etc/letsencrypt/aliyun.ini
--dns-aliyun-propagation-seconds 30
-d nav.xiagao.site
--email eric.zhng@gmail.com
--agree-tos
--non-interactive
nginx:
image: nginx:alpine
container_name: camelznav-nginx
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d:ro
- ./certbot/letsencrypt:/etc/letsencrypt:ro
depends_on:
- camelznav-backend
- camelznav-frontend
camelznav-backend:
build: ./camelznav-backend
container_name: camelznav-backend
restart: always
environment:
- PORT=8080
- GIN_MODE=release
volumes:
- ./data/nav.db:/app/nav.db
- ./data/uploads:/app/uploads
- /etc/localtime:/etc/localtime:ro
expose:
- "8080"
camelznav-frontend:
build:
context: ./camelznav-frontend
args:
- NEXT_PUBLIC_API_URL=http://camelznav-backend:8080
container_name: camelznav-frontend
restart: always
environment:
- NEXT_PUBLIC_API_URL=http://camelznav-backend:8080
expose:
- "3000"
depends_on:
- camelznav-backend关键修改点:
--dns-aliyun→--authenticator dns-aliyun避免参数歧义。credentials.ini放在/etc/letsencrypt/aliyun.ini,统一管理。- nginx 只读挂载证书,保证安全。
- certbot 容器不加
restart: always,避免重复申请证书。 docker-compose.yml放在/vol1/1000/Docker/camelznav-project/目录下
同时要配置nginx:
创建关联文件夹和文件
mkdir -p /vol1/1000/Docker/camelznav-project/nginx cd /vol1/1000/Docker/camelznav-project/nginx/ mkdir -p nginx.conf mkdir -p conf.d cd /conf.d nano default.conf粘贴下边内容:
server { listen 80; server_name nav.xiagao.site; return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name nav.xiagao.site; ssl_certificate /etc/letsencrypt/live/nav.xiagao.site/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/nav.xiagao.site/privkey.pem; # 处理 API 请求,代理到后端 location /api/ { rewrite ^/api/(.*) /$1 break; proxy_pass http://camelznav-backend:8080; 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; } # 其他请求代理到前端 location / { proxy_pass http://camelznav-frontend:3000; 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; } }- Ctrl+X然后yes保存
配置certbot:
创建关联文件夹和文件
cd /vol1/1000/Docker/camelznav-project/ # 项目地址根目录 mkdir -p certbot cd certbot mkdir -p letsencrypt nano credentials.ini粘贴下边内容:
dns_aliyun_access_key = 你的AccessKeyID dns_aliyun_access_key_secret = 你的AccessKeySecret权限必须是:
chmod 600 credentials.ini 或 chmod 600 ~/certbot/credentials.ini 或 chmod 600 ./certbot/credentials.ini证书申请的docker-compose模版
services: certbot: image: camel52zhang/certbot-dns-aliyun:latest container_name: camelznav-certbot volumes: - ./certbot/letsencrypt:/etc/letsencrypt - ./certbot/credentials.ini:/etc/letsencrypt/aliyun.ini:ro command: > certonly --authenticator dns-aliyun --dns-aliyun-credentials /etc/letsencrypt/aliyun.ini --dns-aliyun-propagation-seconds 30 -d aaaaaaa.aaaaaa.com # 修改为您的🌽地址地址 --email aaaaaa@aaaa.com # 修改为您的邮箱地址 --agree-tos --non-interactive- Ctrl+X然后yes保存
4️⃣ 证书申请流程
- 手动测试插件:
docker run --rm camel52zhang/certbot-dns-aliyun:latest plugins- 手动运行 certbot:
docker compose run --rm certbot输出下边内容说明成功
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Account registered.
Requesting a certificate for nav.xiagao.site
Waiting 30 seconds for DNS changes to propagate
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/nav.xiagao.site/fullchain.pem
Key is saved at: /etc/letsencrypt/live/nav.xiagao.site/privkey.pem
This certificate expires on 2026-03-27.
These files will be updated when the certificate renews.
NEXT STEPS:
- The certificate will need to be renewed before it expires. Certbot can automatically renew the certificate in the background, but you may need to take steps to enable that functionality. See https://certbot.org/renewal-setup for instructions.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- 查看证书是否生成:
ls certbot/letsencrypt/live/nav.xiagao.site/- 必须有
fullchain.pem、privkey.pem、cert.pem、chain.pem。
- 启动所有服务:
docker compose up --build -d5️⃣ 自动续签 + nginx reload + 邮件通知
renew-cert.sh(最终版本)
- 只有证书实际更新时 reload nginx
- 续签失败发送邮件
保留 hash 文件避免重复 reload
在你的项目目录
/vol1/1000/Docker/camelznav-project创建文件:nano renew-cert.sh粘贴renew-cert.sh内容:
#!/usr/bin/env bash
set -e
PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)"
COMPOSE="docker compose"
NGINX_CONTAINER="camelznav-nginx"
MAIL_TO="eric.zhng@gmail.com"
DOMAIN="nav.xiagao.site"
CERT_FILE="$PROJECT_DIR/certbot/letsencrypt/live/$DOMAIN/fullchain.pem"
HASH_FILE="$PROJECT_DIR/certbot/letsencrypt/live/$DOMAIN/.last_cert_hash"
send_mail() {
local subject="$1"
local body="$2"
echo -e "$body" | mail -s "$subject" "$MAIL_TO"
}
echo "========== Certbot Renew Start =========="
date
cd "$PROJECT_DIR"
LAST_HASH=""
if [[ -f "$HASH_FILE" ]]; then
LAST_HASH=$(cat "$HASH_FILE")
fi
if ! $COMPOSE run --rm certbot; then
send_mail "❌ Certbot 续签失败 [$(hostname)]" \
"时间: $(date)\n主机: $(hostname)\nCertbot 自动续签失败,请尽快检查。\n路径: $PROJECT_DIR"
exit 1
fi
if [[ -f "$CERT_FILE" ]]; then
NEW_HASH=$(sha256sum "$CERT_FILE" | awk '{print $1}')
else
send_mail "⚠️ Certbot 续签完成,但找不到证书 [$(hostname)]" \
"时间: $(date)\n主机: $(hostname)\n证书文件不存在: $CERT_FILE"
exit 1
fi
if [[ "$NEW_HASH" != "$LAST_HASH" ]]; then
if ! docker exec "$NGINX_CONTAINER" nginx -s reload; then
send_mail "⚠️ Nginx reload 失败 [$(hostname)]" \
"时间: $(date)\n主机: $(hostname)\n证书已更新,但 nginx reload 失败,请检查容器状态: $NGINX_CONTAINER"
exit 1
fi
echo "$NEW_HASH" > "$HASH_FILE"
echo "[INFO] Certificate updated, nginx reloaded."
else
echo "[INFO] Certificate not changed, nginx reload skipped."
fi
echo "========== Certbot Renew Finished =========="Ctrl+x保存指令,按yes保存退出
- 给脚本执行权限:
chmod +x renew-cert.sh- 手动测试一次(在项目目录
/vol1/1000/Docker/camelznav-project内运行):
./renew-cert.sh- 如果证书未过期 → nginx reload 跳过
- 如果证书续签成功 → nginx reload 执行
续签失败 → 邮件通知
你应该看到类似:
Cert not yet due for renewal ... Reloading nginx...这说明:
- certbot 正常判断
- nginx reload 成功
- 一切 OK
- cron 定时任务:
1️⃣ 编辑 cron
crontab -e2️⃣ 每天凌晨 3 点自动跑
0 3 * * * /vol1/1000/Docker/camelznav-project/renew-cert.sh >> /var/log/certbot-renew.log 2>&1✅ 优势:
- nginx reload 只在证书更新时执行
- 续签失败会发邮件
- 脚本安全、可长期运行
- 完全适配你的 Docker + 飞牛 NAS 环境
- 每天凌晨 3 点执行
- Certbot 自动判断是否续签(到期前 30 天才会更新)
- 成功不发邮件,失败发邮件
6️⃣ 优点与生产环境特点
- 镜像可控:固定 certbot 版本 + DNS 插件
- 泛域名支持:通过 DNS-01 完成
- 自动化:renew 脚本 + nginx reload + 邮件通知
- 安全:证书目录只读挂载 nginx
- 可扩展:多域名、NAS cron、飞牛 DSM 都可用
7️⃣ 建议的下一步扩展(可选)
- 多域名 / 多证书自动续签
- Telegram / 企业微信通知
- 脚本拆分 init / renew 两阶段
- 自动备份证书到远程存储
💡 总结一句话:
你已经拥有一个生产级 Docker + Certbot + nginx 证书管理体系,带自动续签、失败报警和安全 reload,非常稳健,适合长期运行。