Docker 部署 QD(Qiandao):复用 Redis,并通过 Nginx Proxy Manager 开启 HTTPS

QD(也常被称为 Qiandao)是一个可以根据 HAR 请求编排定时任务的签到框架。官方 Compose 示例包含了大量可选参数,第一次部署时容易让人无从下手。实际上,如果服务器上已经有 Redis 和 Nginx Proxy Manager,只需要保留少量核心配置即可。

本文完成的部署结构如下:

Internet
   |
   v
Cloudflare / DNS
   |
   v
Nginx Proxy Manager :80/:443
   |
   | app-network
   v
QD container :80 --------> Redis container :6379 (DB 1)

QD 不向宿主机映射端口。公网请求统一进入 Nginx Proxy Manager,再通过 Docker 内部网络访问 qd:80

一、准备条件

本文假设服务器已经具备:

  • Docker Engine 和 Docker Compose
  • 一个正在运行的 Redis 容器
  • 一个正在运行的 Nginx Proxy Manager 容器
  • 一个已解析到服务器的域名,例如 qd.example.com
  • Redis、Nginx Proxy Manager 和 QD 使用同一个 Docker 网络,例如 app-network

先确认网络是否存在:

docker network ls

如果还没有公共网络,可以创建:

docker network create app-network

已有 Redis 和 Nginx Proxy Manager 时,不要重复创建网络,只需确认它们已经加入该网络:

docker network inspect app-network

二、准备部署目录

创建 QD 的独立目录:

mkdir -p /opt/docker/qd/config
cd /opt/docker/qd

其中 config 用于保存 SQLite 数据库等持久化数据。删除或丢失该目录会导致账号和任务数据丢失。

三、创建脱敏环境变量

在部署目录创建 .env

REDIS_PASSWORD=请替换为你的Redis密码
COOKIE_SECRET=请替换为随机生成的长字符串
AES_KEY=请替换为另一个随机生成的长字符串

可以使用 OpenSSL 生成两个独立密钥:

openssl rand -hex 32
openssl rand -hex 32

不要继续使用示例中的 binux 等默认值。限制 .env 的读取权限:

chmod 600 .env

如果 Redis 密码含有 @:/# 等 URL 特殊字符,需要先进行 URL 编码,否则 Redis 连接地址可能解析失败。为了避免这个问题,也可以使用只包含字母、数字、连字符和下划线的强随机密码。

四、编写 Compose 配置

创建 compose.yaml

services:
  qd:
    image: qdtoday/qd:latest
    container_name: qd
    restart: unless-stopped
    volumes:
      - ./config:/usr/src/app/config
    environment:
      TZ: Asia/Shanghai
      DOMAIN: qd.example.com
      COOKIE_SECURE_MODE: "True"
      COOKIE_SECRET: ${COOKIE_SECRET}
      AES_KEY: ${AES_KEY}
      REDISCLOUD_URL: redis://:${REDIS_PASSWORD}@redis:6379/1
    networks:
      - app-network

networks:
  app-network:
    external: true
    name: app-network

这里有几个需要注意的地方:

  • redis 是现有 Redis 的容器名。如果你的容器名不同,需要同步修改连接地址。
  • /1 表示使用 Redis DB 1,避免和已经使用 DB 0 的应用混在一起。
  • 配置中没有 ports,因此不会把 QD 的端口暴露到宿主机。
  • COOKIE_SECURE_MODE 只应在网站已经通过 HTTPS 访问时启用。
  • DOMAIN 只填写域名,不要添加 https:// 和路径。
  • Compose 文件不需要再声明 version: "3",新版 Docker Compose 已经不再需要该字段。

如果 Redis 没有设置密码,连接地址可以改为:

REDISCLOUD_URL: redis://redis:6379/1

五、启动 QD

先检查最终配置是否有效:

docker compose config --quiet

拉取镜像并启动:

docker compose pull
docker compose up -d

查看状态与日志:

docker compose ps
docker compose logs -f --tail=100

正常情况下,日志中会出现类似内容:

Queue Worker start...
Http Server started on 0.0.0.0:80

docker compose ps 只显示 80/tcp 是正常的。这是容器内部端口,并不代表宿主机的 80 端口被 QD 占用。只有看到类似 0.0.0.0:8923->80/tcp 时,才表示端口被映射到了宿主机。

六、配置 Nginx Proxy Manager

打开 Nginx Proxy Manager 管理页面,进入 Hosts -> Proxy Hosts -> Add Proxy Host

在 Details 页面填写:

Domain Names: qd.example.com
Scheme: http
Forward Hostname / IP: qd
Forward Port: 80
Websockets Support: 开启
Block Common Exploits: 开启

在 SSL 页面填写:

SSL Certificate: 选择现有证书,或申请新的证书
Force SSL: 开启
HTTP/2 Support: 开启

保存后,Nginx Proxy Manager 会通过 app-network 访问 qd:80。这里不能填写 127.0.0.1,因为在 Nginx Proxy Manager 容器内部,127.0.0.1 指向的是它自己。

可以在服务器上测试:

curl -I https://qd.example.com

如果返回 HTTP/2 200HTTP/1.1 200,说明 HTTPS 和反向代理均已正常工作。

七、首次登录

QD 没有预设的默认账号和密码。首次打开 https://qd.example.com 后,需要自行注册账号。

全新数据库中的第一个注册用户默认会成为管理员,因此正式开放域名前最好先完成管理员账号注册,并使用独立的强密码。

八、更新与备份

更新镜像:

cd /opt/docker/qd
docker compose pull
docker compose up -d

日常备份至少应包含:

/opt/docker/qd/config/
/opt/docker/qd/compose.yaml
/opt/docker/qd/.env

其中 .env 包含敏感信息,备份文件也应加密或限制访问权限。迁移部署时必须保留原来的 COOKIE_SECRETAES_KEY,随意更换可能导致现有 Cookie 或加密数据无法继续使用。

九、常见问题

1. Redis 提示 NOAUTH Authentication required

说明 Redis 开启了密码认证,但 REDISCLOUD_URL 没有携带密码。检查连接地址是否为:

redis://:密码@redis:6379/1

2. Nginx Proxy Manager 返回 502

依次检查:

docker ps
docker network inspect app-network
docker logs --tail=100 qd

确认 QD 和 Nginx Proxy Manager 位于同一网络,并且代理目标是容器名 qd 和容器端口 80

3. 签到任务出现 HTTP 521

任务请求中的 521 通常是目标网站的 WAF 或源站返回,并不等于 QD 服务部署失败。如果 QD 页面本身可以正常打开,应检查目标网站是否限制了服务器 IP、自动化请求、Cookie 或 User-Agent。

不要为了让任务显示成功而把成功断言改成 521,这只会掩盖真实的签到失败。

总结

复用现有 Redis 时,QD 的部署并不复杂:让 QD、Redis 和 Nginx Proxy Manager 加入同一个 Docker 网络,QD 使用容器名连接 Redis,Nginx Proxy Manager 再通过 qd:80 提供 HTTPS 入口即可。

这种方式不需要暴露额外的宿主机端口,服务入口更统一,后续备份和升级也更容易管理。

上一篇 重读《我与地坛》:在荒芜中学会与命运和解
下一篇 如何在 Linux 端使用 mktorrent 制作种子文件