Files
2026-09-16 11:09:03 +08:00

5.6 KiB
Raw Permalink Blame History

部署指南(1Panel + Docker Compose)

面向 1Panel 用户的生产部署。产物为 docker compose 两个服务:web(Django + gunicorn)与 nginx(admin SPA / SDK 静态 + API 反代),数据库复用 1Panel 已装的 MySQL。

1. 前置构建(仓库内完成,产出 dist 与 xdb)

# 管理后台:产出 admin/dist/
cd admin && pnpm install && pnpm build && cd ..
# 采集 SDK:产出 sdk/dist/v1.js
cd sdk && pnpm install && pnpm build && cd ..

下载 ip2region 离线库到 deploy/data/ip2region.xdb(compose 以只读卷挂载进容器,重建容器不丢):

mkdir -p deploy/data
cp /path/to/ip2region_v4.xdb deploy/data/ip2region.xdb

2. MySQL 准备(1Panel 已有容器)

在 1Panel 的 MySQL 里建库建账号(utf8mb4):

CREATE DATABASE tracker CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'tracker'@'%' IDENTIFIED BY '<强密码>';
GRANT ALL PRIVILEGES ON tracker.* TO 'tracker'@'%';
FLUSH PRIVILEGES;

容器连宿主 MySQL 的三条路径(.env 的 DB_HOST 三选一):

路径 做法 DB_HOST 备注
a 走宿主机发布端口(compose 已配 extra_hosts: host.docker.internal:host-gateway) host.docker.internal MySQL 端口需以 0.0.0.0 发布(1Panel 默认如此),账号 host 为 %
b 推荐 compose 追加外部网络,与 MySQL 容器同网 <MySQL 容器名>(如 1Panel-mysql-xxxx) 不暴露额外端口,容器名在 1Panel 容器列表可见
c 走 docker0 网桥网关 172.17.0.1 网桥地址随环境可能变化,兜底用

路径 b 的 compose 改法(文件末尾已有注释模板,取消注释即生效):

networks:
  default:
    name: 1panel-network
    external: true

3. 配置 .env

cd deploy
cp .env.example .env

填必填项:DJANGO_SECRET_KEY(生成命令见文件内注释)、DJANGO_ALLOWED_HOSTS(实际域名)、DB_*。

fail-fast 设计:DJANGO_ENV=prod 时缺 SECRET_KEY / ALLOWED_HOSTS 启动即崩(RuntimeError),不带病上线——这是有意为之的护栏,不是 bug。漏配时看容器日志 docker compose logs web 即可定位。

4. 部署

docker compose up -d --build
# 建管理员账号(JWT 登录用)
docker compose exec web python manage.py createsuperuser

浏览器访问 http://<服务器IP>:8018/(配域名后走第 5 步的 HTTPS 网站访问)。

5. 域名与 HTTPS(1Panel 建一个网站即可,前后端共用)

只需要建 1 个站点:前端(管理后台)、后端 API、SDK 文件共用同一域名(compose 的 nginx 已合并三者)。

步骤:1Panel「网站」→ 创建网站 → 反向代理 → 代理地址填 127.0.0.1:8018(不带 http:// 前缀,compose 映射端口,见 docker-compose.yml)→ 在该网站设置里申请 Let's Encrypt 证书并开启 HTTPS。

  • 前端访问:https://track.你的域名.com/
  • API:https://track.你的域名.com/api/...(同域自动生效)
  • SDK:https://track.你的域名.com/sdk/v1.js

为什么 compose 不直接占 80/443:1Panel 的 OpenResty 已占用宿主 80/443,直接映射会端口冲突。TLS 由 1Panel 网站终结,转发到 compose 的 8018。

6. 建站点拿 site_id

登录后台 → 站点管理 → 新建站点(填域名) → 列表里复制 site_id(形如 site_xxxxxxxx),接入目标网站时用它。

7. 目标网站接入

目标站 <head> 里加两行(endpoint 与 SDK 地址换成正式域名):

<script>window.ctk = window.ctk || function(){(ctk.q=ctk.q||[]).push(arguments)};
ctk("init", { siteId: "<上一步的 site_id>", endpoint: "https://track.example.com/api/collect/batch" });</script>
<script async src="https://track.example.com/sdk/v1.js"></script>

8. 定时任务(不做则趋势图历史全零)

1Panel「计划任务」→ 每日 00:10 执行(Shell 脚本):

docker exec tracker-web python manage.py refresh_stats --days 2

refresh_stats 聚合昨日明细为每日统计快照(--days 2 幂等重算近两天,补齐漏跑)。

9. JWT 应急

token 泄露时唯一吊销手段是更换 DJANGO_SECRET_KEY(JWT 由它签名,换钥即全体登出):重新生成 → 改 .env → docker compose up -d。后台没有"注销某 token"的接口,这是无状态 JWT 的设计取舍。

10. CDN / WAF 注意

目标网站套 CDN/WAF 后,到达采集 API 的 X-Forwarded-For 层数会变化(CDN 一层 + 本站 nginx 一层 = 2 层起)。取真实客户端 IP 依赖 DRF NUM_PROXIES(当前为 1,对应"仅前置一层可信代理"取末段)。CDN 层数变化后需同步调整 server/config/settings.py 的 NUM_PROXIES 并重建镜像,否则取到的是 CDN 节点 IP,地域与去重统计失真。

11. 大陆网络备用源

资源 主源 备用源
admin 模板(Vite 等 npm 依赖) npm registry pnpm config set registry https://registry.npmmirror.com
ip2region xdb GitHub lionsoul2014/ip2region gitee.com/lionsoul/ip2region
pip 依赖 pypi.org 清华源(Dockerfile 已内置 -i https://pypi.tuna.tsinghua.edu.cn/simple)

附:常用运维命令

docker compose logs -f web                # 看后端日志
docker compose up -d --build              # 改代码后重建
docker compose exec web python manage.py createsuperuser   # 再建账号