Compare commits

..

2 Commits

Author SHA1 Message Date
浅念 0a5eb49359 docs(deploy): DEPLOY.md 对齐 2026-09-03 实测落地(NAT 端口模式)
- 拓扑现实:服务器在路由器 NAT 后,公网 80 被其他设备占用
- 对外访问实测:1Panel 域名管理加 公网IP:32002 + 路由器转发,零配置直访
- 修媒体解压路径 bug:包内根是 media/,须 -C yunke-server
- HTTPS 改为将来项:域名 + 1Panel DNS 验证(绕开被占的 80)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-03 14:35:00 +08:00
浅念 284cecfcd9 fix(deploy): server 编排接入 1panel-network 直连 1Panel MySQL
MySQL 容器只绑 127.0.0.1:3306,宿主机网段不可达;backend/scheduler
挂 external 网络 1panel-network 用容器名直连,不改 1Panel 任何配置。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-03 12:02:12 +08:00
2 changed files with 37 additions and 15 deletions
+16 -2
View File
@@ -5,8 +5,10 @@
# 「所有区域(%)」,容器经宿主机内网 IP 访问,3306 不对公网);redis 应用 # 「所有区域(%)」,容器经宿主机内网 IP 访问,3306 不对公网);redis 应用
# 尚未接线(config 里只有一个默认 URL),省一份常驻内存——app 将来接 # 尚未接线(config 里只有一个默认 URL),省一份常驻内存——app 将来接
# redis 时记得同步回这里。 # redis 时记得同步回这里。
# - DB_URL 主机/端口走 MYSQL_HOST / MYSQL_PORT 环境变量(.env 里填宿主机 # - backend/scheduler 挂到 external 网络 1panel-network(1Panel 的 MySQL
# 内网 IP,如 172.19.x.x;容器→宿主机内网 IP 是 docker bridge 默认可达)。 # 容器 1Panel-mysql-YL0F 只绑 127.0.0.1:3306,宿主机网络够不着;加入它
# 所在网络后用容器名直连,不改 MySQL 任何配置)。MYSQL_HOST 填该容器名。
# frontend 不需要——它只跟 backend 说话。
# - 端口只绑 127.0.0.1:frontend 供 1Panel OpenResty(host 网络)反代; # - 端口只绑 127.0.0.1:frontend 供 1Panel OpenResty(host 网络)反代;
# backend 不映射宿主机(/api 由 frontend 容器内 nginx 反代,见 # backend 不映射宿主机(/api 由 frontend 容器内 nginx 反代,见
# yunkes/nginx.conf)。 # yunkes/nginx.conf)。
@@ -41,6 +43,9 @@ services:
API_TOKEN: ${API_TOKEN:-} API_TOKEN: ${API_TOKEN:-}
ENCRYPTION_KEY: ${ENCRYPTION_KEY:-} ENCRYPTION_KEY: ${ENCRYPTION_KEY:-}
TZ: Asia/Shanghai TZ: Asia/Shanghai
networks:
- default
- 1panel
volumes: volumes:
# 媒体 bind mount:服务器上 ./yunke-server/media 数据直观可见、好备份 # 媒体 bind mount:服务器上 ./yunke-server/media 数据直观可见、好备份
- ./yunke-server/media:/data/media - ./yunke-server/media:/data/media
@@ -69,6 +74,9 @@ services:
FULL_SYNC_HOUR: ${FULL_SYNC_HOUR:-2} FULL_SYNC_HOUR: ${FULL_SYNC_HOUR:-2}
MESSAGE_INTERVAL_HOURS: ${MESSAGE_INTERVAL_HOURS:-4} MESSAGE_INTERVAL_HOURS: ${MESSAGE_INTERVAL_HOURS:-4}
TZ: Asia/Shanghai TZ: Asia/Shanghai
networks:
- default
- 1panel
volumes: volumes:
- ./yunke-server/media:/data/media - ./yunke-server/media:/data/media
@@ -83,3 +91,9 @@ services:
# 只绑 127.0.0.1:公网流量一律走 1Panel OpenResty 反代(80/443), # 只绑 127.0.0.1:公网流量一律走 1Panel OpenResty 反代(80/443),
# 5173 不暴露到安全组 # 5173 不暴露到安全组
- "127.0.0.1:5173:80" - "127.0.0.1:5173:80"
networks:
# 1Panel 的 MySQL 容器所在网络(external:只挂靠,不创建不修改)
1panel:
name: 1panel-network
external: true
+21 -13
View File
@@ -1,7 +1,9 @@
# 云客数据镜像 — 服务器部署 runbook(阿里云 ECS + 1Panel) # 云客数据镜像 — 服务器部署 runbook(1Panel 服务器,2026-09-03 实测落地版)
> 2026-09-01 v2|形态:1Panel 管理,OpenResty 单站点反代,复用 1Panel MySQL, > 形态:1Panel 管理,OpenResty 站点 + 公网高位端口,复用 1Panel MySQL,
> 数据从本地整体搬迁。本地开发栈(五服务 docker-compose.yml)不在本文范围。 > 数据从本地整体搬迁。本地开发栈(五服务 docker-compose.yml)不在本文范围。
> **实测拓扑**:服务器在路由器 NAT 后(网卡 192.168.100.x,公网 IP 为路由器,
> 公网 80 端口被同网其他设备占用)。
## 架构 ## 架构
@@ -30,9 +32,9 @@
- [ ] 1Panel 应用商店已装 **OpenResty**(建站依赖) - [ ] 1Panel 应用商店已装 **OpenResty**(建站依赖)
- [ ] 1Panel MySQL 版本 **8.x**;已建库 `yunke` + 专用用户,库权限设 - [ ] 1Panel MySQL 版本 **8.x**;已建库 `yunke` + 专用用户,库权限设
「**所有区域(%)**」(容器从 docker 网段连入;3306 不对公网开,无风险) 「**所有区域(%)**」(容器从 docker 网段连入;3306 不对公网开,无风险)
- [ ] 域名已解析到 ECS 公网 IP,大陆区域已**备案**(80/443 必须) - [ ] 对外访问走「1Panel 域名管理加 `公网IP:高位端口`(实测 32002)+
- [ ] 阿里云安全组:公网只开 **80/443**;SSH 与 1Panel 面板端口限源 IP; 路由器端口转发到本机同端口」;**3306 / 5173 / 8000 不对公网开**
**3306 / 5173 / 8000 不对公网开** (公网 80 已被其他设备占用,域名+HTTPS 为将来可选项)
- [ ] Docker Hub 镜像加速:1Panel「容器→设置」里配加速器(拉 python/node/nginx - [ ] Docker Hub 镜像加速:1Panel「容器→设置」里配加速器(拉 python/node/nginx
基础镜像用);apt/pip/npm/playwright 源已在 Dockerfile 内置国内镜像 基础镜像用);apt/pip/npm/playwright 源已在 Dockerfile 内置国内镜像
- [ ] 服务器可访问 `crm2.yunkecn.com` 和 `*.oss.yunkecn.com`(抓取+媒体下载) - [ ] 服务器可访问 `crm2.yunkecn.com` 和 `*.oss.yunkecn.com`(抓取+媒体下载)
@@ -130,8 +132,9 @@ docker exec -i <1Panel-mysql容器名> mysql -uyunke -p<密码> \
# ⚠️ 86 万行 message 的 ngram 全文索引导入时重建,约 12 分钟——慢是正常, # ⚠️ 86 万行 message 的 ngram 全文索引导入时重建,约 12 分钟——慢是正常,
# 不要中断;期间导入脚本看似卡在索引阶段属预期。 # 不要中断;期间导入脚本看似卡在索引阶段属预期。
# 媒体:解到 bind mount 目录(compose 已挂 ./yunke-server/media) # 媒体:解到 bind mount 目录(compose 已挂 ./yunke-server/media)。
tar xzf media.tar.gz # 解出 yunke-server/media/ # 包内根目录是 media/(打包时 -C yunke-server),必须 -C 解到 yunke-server 下
tar xzf media.tar.gz -C yunke-server
# 数据自带 alembic_version=head,不需要跑 alembic upgrade。 # 数据自带 alembic_version=head,不需要跑 alembic upgrade。
``` ```
@@ -148,13 +151,18 @@ docker compose -f docker-compose.server.yml exec scheduler \
python scripts/scrape_via_page.py --entity messages --max-conversations 200 python scripts/scrape_via_page.py --entity messages --max-conversations 200
``` ```
## 5. 站点 + HTTPS(1Panel) ## 5. 站点与对外访问(实测:1Panel 端口模式)
1. 「网站→创建网站→反向代理」:主域名填**真实域名**,代理地址 1. 1Panel「网站→创建网站→反向代理」:代理地址 `127.0.0.1:5173`(已建则跳过)
`127.0.0.1:5173`(已建好站点的话跳过) 2. 1Panel「网站→设置→域名管理」添加一条 `公网IP:高位端口`(实测
2. 「网站→证书」:Let's Encrypt 申请该域名证书 → 网站设置里开启 HTTPS `219.157.255.213:32002`)→ 站点多监听该端口
3. 打不开/502 时排查:栈是否 Up(`docker compose -f docker-compose.server.yml ps`)、 3. 路由器端口转发:`外部 32002 → 192.168.100.132:32002`
`curl 127.0.0.1:5173` 是否通、OpenResty 是否 host 网络(1Panel 默认是) 4. 访问 `http://219.157.255.213:32002`,别人零配置直接用
5. 502 排查:栈是否 Up、`curl 127.0.0.1:5173` 是否通(OpenResty 是 host 网络,
1Panel 默认)
将来要 HTTPS:买真实域名 → 1Panel 证书走 **DNS 验证**(HTTP 验证需要 80,
已被占)→ 路由器加 443 转发。
前端登录鉴权即 `.env` 的 `API_TOKEN`(`Authorization: Bearer <token>` 或 前端登录鉴权即 `.env` 的 `API_TOKEN`(`Authorization: Bearer <token>` 或
`?token=`;**公网部署绝不能留空**)。 `?token=`;**公网部署绝不能留空**)。