# alibb 生产部署文档(1Panel + OpenResty + MySQL 8.4) > 基于 2026-08-27 实际生产部署整理(服务器重装后完整恢复验证通过)。 > 与 2026-07-15 首次部署的差异见 §8。恢复/迁移专用 runbook 见 > [2026-08-25-server-restore-redeploy.md](superpowers/plans/2026-08-25-server-restore-redeploy.md)。 ## 1. 架构 ``` 浏览器扩展(抓 alibaba 询盘) │ POST /api/ingest(Bearer INGEST_TOKEN) ▼ http://219.157.255.213:23010 ── OpenResty 站点「alibaba」(1Panel 面板管理,host 网络) ├─ / → 前端 dist 静态(/opt/1panel/www/sites/alibaba/index) └─ /api/* → http://127.0.0.1:8090(反代,client_max_body_size 50m) │ ▼ alibb-backend 容器(Express + Prisma,127.0.0.1:8090→8080) │ ▼ 1Panel MySQL 8.4(容器 1Panel-mysql-YL0F,库 alibaba) ``` 管理后台:浏览器开 http://219.157.255.213:23010 → admin 登录(密码见服务器 `~/alibb-secrets.txt`)。 ## 2. 环境与信息总表 | 项 | 值 | |---|---| | 服务器 | 阿里云 ECS `219.157.255.213`,Ubuntu 26.04 LTS | | 登录用户 | `kt`(sudo 免密);SSH 密钥 `C:\Users\30997\.ssh\alibb_deploy` | | SSH(本机) | `/c/Windows/System32/OpenSSH/ssh.exe -i 'C:\Users\30997\.ssh\alibb_deploy' kt@219.157.255.213`(Git Bash 自带 ssh 因私钥权限 644 不可用) | | Docker 网络 | `1panel-network`(bridge,1Panel 安装时自动创建) | | MySQL | 容器 `1Panel-mysql-YL0F`,镜像 mysql:8.4.11,`127.0.0.1:3306`,root 密码见容器 env `MYSQL_ROOT_PASSWORD` | | 业务库/账号 | 库 `alibaba`(utf8mb4),用户 `alibaba@%`,密码 `wecbni5zRRnZrMMh`,授权 `ALL ON alibaba.*` | | 后端 | 容器 `alibb-backend`,代码 `~/alibb-server/backend`,`127.0.0.1:8090→8080`,restart unless-stopped | | OpenResty | 容器 `1Panel-openresty-Seym`,**host 网络模式**,管理 80/443/23010 | | 站点 | 1Panel 面板管理,代号 **alibaba**;目录 `/opt/1panel/www/sites/alibaba/`(index/ 前端、log/ 日志) | | 站点 conf | `/opt/1panel/www/conf.d/alibaba.conf`(面板生成的 server 块 + 手工并入的 SPA fallback 与 /api 反代) | | 对外端口 | 23010(云安全组已放行);8090/3306 仅本机 | | 生产密钥 | JWT_SECRET / INGEST_TOKEN / ADMIN_USERNAME / ADMIN_PASSWORD 内嵌于 `~/alibb-server/backend/docker-compose.yml`;明文副本 `~/alibb-secrets.txt`(600) | | 本机代码 | 扩展 `d:\alibb`(master);后端 `d:\alibb-server\backend`(master,compose 为 **dev 版**);前端 `d:\alibb-server\frontend`(main) | | 备份 | 本机 `D:\alibb-server\backups\`(权威);服务器副本 `~/alibb-backup-20260825/` | ## 3. 从零部署(完整步骤) > 以下命令全部在 2026-08-27 实际验证。分两段:本机(Windows/Git Bash)与服务器(SSH)。 ### 3.1 SSH 准备 ```bash # 首次:云控制台 VNC 或 1Panel 面板「主机→终端」,root 执行(公钥替换成自己的) useradd -m -s /bin/bash kt; echo "kt ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/kt; \ mkdir -p /home/kt/.ssh; echo "<本机公钥内容>" > /home/kt/.ssh/authorized_keys; \ chown -R kt:kt /home/kt/.ssh; chmod 700 /home/kt/.ssh; chmod 600 /home/kt/.ssh/authorized_keys # 本机清除旧 host key(重装后必做,否则报 HOST IDENTIFICATION HAS CHANGED) /c/Windows/System32/OpenSSH/ssh-keygen.exe -R 219.157.255.213 ``` ### 3.2 系统基础 ```bash # Docker curl -fsSL https://get.docker.com | sudo sh sudo tee /etc/docker/daemon.json <<'EOF' { "registry-mirrors": ["https://docker.1panel.live"] } EOF sudo systemctl restart docker # 1Panel(官方脚本,装时设面板密码) curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sudo bash quick_start.sh ``` ### 3.3 1Panel 应用 面板 → 应用商店安装: - **OpenResty**(1.31+,host 网络模式) - **MySQL 8.4**(装完记容器名,形如 `1Panel-mysql-XXXX`,下称 ``) ### 3.4 数据库 方式 A(面板):数据库 → 创建,库名 `alibaba`,用户 `alibaba`,权限 `alibaba.*`(密码设 `wecbni5zRRnZrMMh` 与 compose 一致,或建完后 ALTER)。 方式 B(命令,推荐): ```bash M= R=$(sudo docker inspect $M --format '{{range .Config.Env}}{{println .}}{{end}}' | grep MYSQL_ROOT_PASSWORD | cut -d= -f2) sudo docker exec -i -e MYSQL_PWD=$R $M mysql -uroot <<'SQL' CREATE DATABASE alibaba CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE USER 'alibaba'@'%' IDENTIFIED BY 'wecbni5zRRnZrMMh'; GRANT ALL PRIVILEGES ON `alibaba`.* TO 'alibaba'@'%' WITH GRANT OPTION; FLUSH PRIVILEGES; SQL # 验证 sudo docker exec -e MYSQL_PWD=wecbni5zRRnZrMMh $M mysql -ualibaba -e "SELECT 1;" ``` 导入存量数据(有备份时): ```bash sudo docker exec -i -e MYSQL_PWD=$R $M mysql -uroot < alibaba-db.sql ``` ### 3.5 后端 ```bash # 本机推代码(排除 node_modules/dist/.git) cd /d && tar czf /tmp/alibb-server.tgz --exclude='alibb-server/*/node_modules' --exclude='*/dist' --exclude='*/.git' alibb-server /c/Windows/System32/OpenSSH/scp.exe -i 'C:\Users\30997\.ssh\alibb_deploy' /tmp/alibb-server.tgz kt@219.157.255.213:/tmp/ # 服务器解包 ssh ... 'tar xzf /tmp/alibb-server.tgz -C ~' ``` **compose 关键项**(服务器生产版,本地 dev compose 上线前必须对齐): ```yaml services: backend: container_name: alibb-backend build: . ports: ["127.0.0.1:8090:8080"] environment: DATABASE_URL: "mysql://alibaba:wecbni5zRRnZrMMh@:3306/alibaba?charset=utf8mb4&timezone=Z" INGEST_TOKEN / JWT_SECRET / ADMIN_USERNAME / ADMIN_PASSWORD: 生产值(强随机,首次生成见下) NODE_ENV: production restart: unless-stopped networks: 1panel-network: external: true ``` 首次生成密钥(已有备份则沿用旧值,扩展/老 JWT 不失效): ```bash openssl rand -hex 24 # INGEST_TOKEN openssl rand -hex 32 # JWT_SECRET openssl rand -hex 16 # ADMIN_PASSWORD ``` 构建启动(注意 MySQL 容器名替换): ```bash cd ~/alibb-server/backend sed -i "s/<旧MYSQL容器名>/<新MYSQL容器名>/g" docker-compose.yml sudo docker compose build backend && sudo docker compose up -d sudo docker compose logs backend | tail # 期望:No pending migrations + listening on 8080 ``` ### 3.6 站点 + 前端 **先在 1Panel 面板建站**(网站 → 创建网站):类型**静态网站**,主域名 `219.157.255.213`,端口 `23010`,代号 `alibaba`。 > 注意:面板检查端口占用——若 conf.d 里有手工 conf 占着 23010 会报"端口已被占用",先移除再建。 面板会生成 `/opt/1panel/www/sites/alibaba/` 和 `/opt/1panel/www/conf.d/alibaba.conf`。然后合并前端与反代: ```bash S=/opt/1panel/www/sites/alibaba # 前端 dist(备包直解最快;index 子目录在面板建站时已建) sudo tar xzf alibb-frontend-dist.tgz -C $S/ && sudo chmod -R a+rX $S/index # 或源码构建: # cd ~/alibb-server/frontend && sudo docker run --rm -v "$PWD":/app -w /app node:22-alpine sh -c 'npm ci && npm run build' # sudo rm -rf $S/index/* && sudo cp -r dist/. $S/index/ && sudo chmod -R a+rX $S/index # 在 conf 的 root 行后并入 SPA fallback + /api 反代(host 网络 → 必须宿主端口,不能用容器名) sudo sed -i "/root \/www\/sites\/alibaba\/index;/a\\ location / { try_files \$uri \$uri/ /index.html; }\\ location ^~ /api/ {\\ proxy_pass http://127.0.0.1:8090;\\ client_max_body_size 50m;\\ proxy_set_header Host \$host;\\ proxy_set_header X-Real-IP \$remote_addr;\\ proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;\\ }" /opt/1panel/www/conf.d/alibaba.conf ``` 重载 OpenResty: ```bash sudo docker exec 1Panel-openresty-Seym openresty -t && sudo docker exec 1Panel-openresty-Seym openresty -s reload ``` ### 3.7 安全组 云控制台放行 **TCP 23010** 入方向(源 0.0.0.0/0 或收窄)。8090/3306 不放行。 ### 3.8 验证 ```bash curl http://219.157.255.213:23010/ # 200 index.html curl http://219.157.255.213:23010/inquiries # 200(SPA fallback) curl http://219.157.255.213:23010/api/health # {"ok":true} ``` 浏览器登录 admin / ADMIN_PASSWORD,核对询盘/客户/消息数据。 ### 3.9 扩展配置 popup:serverUrl `http://219.157.255.213:23010` + INGEST_TOKEN(~/alibb-secrets.txt)→ 授权 → 启用推送 → 抓取。 ## 4. 增量更新(改代码后) | 改动 | 操作 | |---|---| | 后端 | 传变更文件 → `cd ~/alibb-server/backend && sudo docker compose build backend && sudo docker compose up -d`(migrate 自动跑) | | 前端 | 传变更 → 服务器 build(§3.6 方式 B)→ 复制 dist → 无需 reload(静态文件即时生效) | | 扩展 | 本机改 → `chrome://extensions` 刷新扩展(用户操作) | ## 5. 常用运维 ```bash # 后端日志 / 重启 sudo docker compose -f ~/alibb-server/backend/docker-compose.yml logs -f backend sudo docker compose -f ~/alibb-server/backend/docker-compose.yml restart backend # 查库 sudo docker exec -e MYSQL_PWD=wecbni5zRRnZrMMh 1Panel-mysql-YL0F mysql -ualibaba alibaba # 行数快照 sudo docker exec -e MYSQL_PWD=wecbni5zRRnZrMMh 1Panel-mysql-YL0F mysql -ualibaba alibaba -e \ "SELECT (SELECT COUNT(*) FROM inquiries) i,(SELECT COUNT(*) FROM customers) c,(SELECT COUNT(*) FROM chat_messages) m;" # 清询盘重抓(customers 保留,重抓 upsert 更新) ... mysql ... -e "SET FOREIGN_KEY_CHECKS=0; TRUNCATE chat_messages; TRUNCATE inquiries; SET FOREIGN_KEY_CHECKS=1;" # 重载 OpenResty(改 conf 后) sudo docker exec 1Panel-openresty-Seym openresty -t && sudo docker exec 1Panel-openresty-Seym openresty -s reload ``` ## 6. 备份与恢复 - **备份**(本机执行,产物存 `D:\alibb-server\backups\`): ```bash /c/Windows/System32/OpenSSH/ssh.exe -i 'C:\Users\30997\.ssh\alibb_deploy' kt@219.157.255.213 \ 'sudo docker exec 1Panel-mysql-YL0F mysqldump -ualibaba -pwecbni5zRRnZrMMh --single-transaction --no-tablespaces --routines --triggers --databases alibaba' > D:\alibb-server\backups\alibaba-db-$(date +%Y%m%d).sql ``` - 完整备份方案:[2026-08-25-server-reinstall-backup.md](superpowers/plans/2026-08-25-server-reinstall-backup.md) - 服务器重装恢复 runbook:[2026-08-25-server-restore-redeploy.md](superpowers/plans/2026-08-25-server-restore-redeploy.md)(含 2026-08-27 实操记录) ## 7. 故障排查 | 症状 | 原因 → 处理 | |---|---| | `/api` 502 | ① backend 挂了:`docker ps` / `logs backend`;② 反代写成了 `http://backend:8080`——host 网络模式解析不了容器名,必须 `http://127.0.0.1:8090` | | openresty -t 报 host not found in upstream | 同上,proxy_pass 用容器名导致 | | 后端起不来,连接拒绝 | DATABASE_URL 里 MySQL 容器名不对(重装/重建后容器名后缀会变) | | 管理后台登录 401 | ADMIN_USERNAME/PASSWORD 与 compose 不符;扩展推送 401 → INGEST_TOKEN 不符 | | migrate 报表不存在 | 库导错/导到别的库,重做 §3.4 | | MySQL 8.x 用户连不上(老客户端) | `ALTER USER 'alibaba'@'%' IDENTIFIED WITH caching_sha2_password BY '...'`(Prisma 支持 caching_sha2,一般无需处理) | | 换服务器/IP | 改 3 处:扩展 serverUrl、站点 conf `server_name`、云安全组 | ## 8. 与 2026-07-15 旧环境差异(重要) | 项 | 旧(7 月) | 新(2026-08-27) | |---|---|---| | MySQL | 5.7.44(容器 1Panel-mysql-sLiG,0.0.0.0:3306) | 8.4.11(容器 1Panel-mysql-YL0F,**127.0.0.1:3306 已收紧**) | | OpenResty | bridge 网络,反代可用容器名 `http://backend:8080` | **host 网络,反代必须 `http://127.0.0.1:8090`** | | 1Panel 路径 | /opt/1panel/apps/openresty/openresty/www/sites/... | **/opt/1panel/www/sites/...**(容器内仍挂 /www,旧 conf 兼容) | | 系统 | Ubuntu 24.04(kt-W580G20) | Ubuntu 26.04(xyh-W580G20) | | 站点管理 | 1Panel 面板建站(站点 alibb) | 1Panel 面板建站(代号 **alibaba**,2026-08-27 起面板可见可管理) | ## 9. 已知限制(业务) - **折叠面板字段抓不到**:客户资料折叠面板里的手机/座机/商业类型等,alibaba 校验 `event.isTrusted`(只认真实鼠标点击),扩展无法展开;这些字段多数买家本就是"-"。 - **风控**:抓取间隔已随机化(randSleep);大量抓取分批 + 中途暂停。 - 公网明文 HTTP(23010):内网/测试用途可接受;若需公网长期使用,建议套域名 + HTTPS(1Panel 可申请 Let's Encrypt)。