Files
alibaba/docs/DEPLOY-ALIBB.md
T
2026-08-27 16:12:37 +08:00

12 KiB

alibb 生产部署文档(1Panel + OpenResty + MySQL 8.4)

基于 2026-08-27 实际生产部署整理(服务器重装后完整恢复验证通过)。 与 2026-07-15 首次部署的差异见 §8。恢复/迁移专用 runbook 见 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 准备

# 首次:云控制台 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 系统基础

# 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,下称 <MYSQL容器名>)

3.4 数据库

方式 A(面板):数据库 → 创建,库名 alibaba,用户 alibaba,权限 alibaba.*(密码设 wecbni5zRRnZrMMh 与 compose 一致,或建完后 ALTER)。

方式 B(命令,推荐):

M=<MYSQL容器名>
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;"

导入存量数据(有备份时):

sudo docker exec -i -e MYSQL_PWD=$R $M mysql -uroot < alibaba-db.sql

3.5 后端

# 本机推代码(排除 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 上线前必须对齐):

services:
  backend:
    container_name: alibb-backend
    build: .
    ports: ["127.0.0.1:8090:8080"]
    environment:
      DATABASE_URL: "mysql://alibaba:wecbni5zRRnZrMMh@<MYSQL容器名>: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 不失效):

openssl rand -hex 24  # INGEST_TOKEN
openssl rand -hex 32  # JWT_SECRET
openssl rand -hex 16  # ADMIN_PASSWORD

构建启动(注意 MySQL 容器名替换):

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。然后合并前端与反代:

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:

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 验证

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. 常用运维

# 后端日志 / 重启
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\):
/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

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)。