Files
doodle-store/docs/v3.5/服务端首次部署操作手册.md
T
2026-10-23 15:11:31 +08:00

442 lines
27 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 服务端首次部署操作手册
更新时间:2026-10-22。适用腾讯云 Ubuntu 24.04 / x86_64、1Panel 2.3.2、已有 PostgreSQL 与 `doodle_prod` 的环境。
用户已确认数据库准备完成;本文不重复建库、初始化表或导入数据,也不表示已现场核验云端数据。本文是操作说明与配套配置,不代表已经部署到云端。
## 1. 本次采用的部署方式
在 Mac 上构建 Linux 镜像,导出压缩包,通过 1Panel 上传到服务器并导入。服务器只运行构建好的 API,不需要额外安装 Node.js、pnpm、PM2 或源码。暂时无需镜像仓库,后续可改为仓库推送/拉取。
```text
小程序 → https://doodle-api.joeyone.cn
→ 1Panel 已有 OpenResty:443 / 证书
→ doodle-api-prod:8800
→ 1panel-network → 既有 PostgreSQL:5432 / doodle_prod
资源 → https://cdn.joeyone.cn
```
本阶段只运行一套云端业务环境。小程序 develop 可选择 production 调试;trial/release 固定 production。旧正式版继续访问旧 CloudBase,保留全部旧云函数、预拉取和定时任务;新服务部署成功后先用开发版和体验版验收。
现有数据库由 1Panel 管理;API 由本文 Compose 文件管理,在 1Panel 中可查看其状态和日志。不要再用 1Panel 新建一个同名 API 编排,也不要运行旧 `compose.database.yaml`。
配套文件都在 `doodle-store` 仓库:
| 文件 | 作用 |
| ---------------------------- | ------------------------------------------ |
| `deploy/Dockerfile.server` | 构建 Linux 服务端镜像,启动 `dist/main.js` |
| `.dockerignore` | 排除本机依赖、真实环境配置和备份 |
| `deploy/compose.api.yaml` | 只启动 API,复用 1Panel 数据库网络 |
| `deploy/compose.env.example` | 镜像版本和网络名模板 |
| `deploy/server.env.example` | 服务运行配置模板,真实值仅在服务器填写 |
首版镜像保留 Prisma CLI 和构建依赖,便于同一个版本镜像执行独立数据库迁移;因此体积尚未优化。迁移不随 API 每次重启自动执行。
## 2. 服务器部署前检查
以下命令均在 **1Panel → 终端 → 本地服务器**执行,建议使用当前已有管理终端。不要在 Mac 终端执行服务器命令。
```bash
docker version
docker compose version
docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Ports}}'
docker network inspect 1panel-network --format '{{range .Containers}}{{println .Name .IPv4Address}}{{end}}'
ss -lntp | rg ':80 |:443 |:8800 '
```
若服务器没有 `rg`,最后一条改用 `ss -lntp` 直接查看。
确认以下条件后继续:
- Docker 正常,Compose 至少 **2.30.0**;配置使用 `env_file.format: raw`,低版本会报不支持。版本不足时通过 1Panel 支持的升级方式更新 Compose,再继续。
- `1Panel-postgresql-RqP6` 正常运行,属于 `1panel-network`。这是此前核查的名称,若已重装,应以本次实际名称为准,并同步替换 `server.env`。
- `8800` 未被其他程序占用;`80/443` 继续交给已有 OpenResty。
- 在 1Panel → 容器中查出 OpenResty 容器名和网络模式。也可把实际名称代入:
```bash
docker inspect <OpenResty容器名> --format '{{.HostConfig.NetworkMode}} {{json .NetworkSettings.Networks}}'
```
若是 `host` 模式,反向代理上游使用 `http://127.0.0.1:8800`;若是 bridge 且与 API 同处 `1panel-network`,使用 `http://doodle-api-prod:8800`。若 bridge 未接入该网络,先通过 1Panel 核对并持久配置共享网络,再创建代理;不要把 OpenResty 容器内的 `127.0.0.1` 当成宿主机。
若不存在 `1panel-network`,先找到数据库实际所在网络,将该名字写入后面的 `.env`,而不是盲目新建一个与数据库隔离的同名网络。
### 检查并备份已有数据库
先在 1Panel 的 PostgreSQL 管理中为 `doodle_prod` 做一次完整备份,确认任务成功并下载一份到本机。也可通过 DBX 执行以下只读查询核对当前目标和迁移历史:
```sql
SELECT current_database(), current_user;
SELECT migration_name, finished_at, rolled_back_at
FROM public._prisma_migrations
ORDER BY migration_name;
SELECT 'categories' AS table_name, count(*) FROM public.categories
UNION ALL SELECT 'worksheets', count(*) FROM public.worksheets
UNION ALL SELECT 'assets', count(*) FROM public.assets;
```
当前代码包含三份迁移:
```text
0_v35_baseline
20261016000000_category_publication
20261019000000_member_assets
```
初始化 SQL 已写入这些迁移记录。不要重新运行初始化 SQL、导入本地 `_prisma_migrations`,也不要删除现有表来绕过迁移错误。
## 3. 在 Mac 构建和导出镜像
先启动 Docker Desktop。在 **Mac 终端**执行:
```bash
cd /Users/joey-xd/sites/doodle/doodle-store
git status --short
docker version
docker buildx build \
--platform linux/amd64 \
-f deploy/Dockerfile.server \
-t doodle-server:20261022-01 \
--load .
```
`20261022-01` 是本文示例版本号。实际每次发布使用新编号,不覆盖上一次可运行的标签;构建包含当前工作区未提交的改动,应先确认这些改动属于本次发布。
必须在 `doodle-store` 根目录构建,最后的 `.` 不能省略。即使 Mac 是 Apple Silicon,也显式构建 `linux/amd64`,与云服务器一致。
Docker 内部安装项目锁定的 Node.js 24.20.0 / pnpm 11.24.0,构建 contracts、生成 Linux Prisma 客户端,再编译 NestJS。不会使用 Mac 的 `node_modules`,也不需要提供真实数据库密码、微信或七牛密钥来构建。
如果 `pnpm install` 从 npm 官方源下载依赖时持续超时,可通过构建参数切换到 [npmmirror 国内镜像源](https://npmmirror.com/):
```bash
docker buildx build \
--platform linux/amd64 \
--progress=plain \
--build-arg NPM_REGISTRY=https://registry.npmmirror.com \
-f deploy/Dockerfile.server \
-t doodle-server:20261022-01 \
--load .
```
该参数同时用于安装 pnpm 和安装项目依赖;默认仍使用 npm 官方源,不修改 Mac 的全局 npm 配置或锁文件。保留 `--frozen-lockfile` 及依赖完整性校验。仅在 Mac 上执行 `npm config set registry` 不会自动修改 Docker 构建环境中的源。
此参数只控制 npm 包下载,不控制 Docker Hub 基础镜像、Debian apt 软件源和 Prisma 独立引擎下载。如果镜像源尚未同步指定版本,或错误发生在其他下载域名,需要按完整日志另行处理。
确认镜像架构并导出:
```bash
docker image inspect doodle-server:20261022-01 --format '{{.Os}}/{{.Architecture}}'
mkdir -p /tmp/doodle-release-20261022-01
docker image save doodle-server:20261022-01 | gzip > /tmp/doodle-release-20261022-01/doodle-server-20261022-01.tar.gz
cd /tmp/doodle-release-20261022-01
shasum -a 256 doodle-server-20261022-01.tar.gz > doodle-server-20261022-01.tar.gz.sha256
```
架构输出应为 `linux/amd64`。若构建失败,先处理镜像源、依赖下载或编译报错,不上传不完整的压缩包。初次拉取基础镜像和跨架构编译可能较慢。
## 4. 用 1Panel 上传并导入镜像
服务器建立本次发布目录和长期配置目录。在 **1Panel 终端**执行:
```bash
mkdir -p /opt/doodle/releases/20261022-01
mkdir -p /opt/doodle/prod
chmod 700 /opt/doodle/prod
```
在 **1Panel → 文件**中:
1. 将 Mac `/tmp/doodle-release-20261022-01/` 中的压缩包和 `.sha256` 文件上传到服务器 `/opt/doodle/releases/20261022-01/`。
2. 将仓库 `deploy/` 下的 `compose.api.yaml`、`compose.env.example`、`server.env.example` 上传到 `/opt/doodle/prod/`。
3. 首次在服务器复制模板:`compose.env.example` → `.env`;`server.env.example` → `server.env`。后续发布不要再次复制模板覆盖真实配置。
如果文件页隐藏点文件,打开显示隐藏文件后编辑 `.env`。若通过网页上传大镜像超时,可改用 1Panel 支持的分片上传,或用已有 SSH/SFTP 上传;无需改用浏览器将镜像作为 SQL 文件导入。
建议在导入前通过 **1Panel 终端**校验上传文件:
```bash
cd /opt/doodle/releases/20261022-01
sha256sum -c doodle-server-20261022-01.tar.gz.sha256
```
校验输出应为 `OK`;否则重新上传。SHA-256 校验不是部署必需步骤,但建议保留,以便提前发现上传不完整的问题。
### 4.1 通过图形界面导入(推荐)
1. 进入 **1Panel → 容器 → 镜像 → 导入镜像**。
2. 选择已上传到服务器的 `/opt/doodle/releases/20261022-01/doodle-server-20261022-01.tar.gz`,确认导入。
3. 如果导入界面不接受 `.tar.gz`,先通过 **1Panel → 文件**将其解压成 `.tar`,再选择该 `.tar` 文件导入。
4. 导入完成后,在镜像列表确认存在标签 **`doodle-server:20261022-01`**。
使用图形界面导入后,不需要再执行 `docker load`。镜像已经保存在服务器本机 Docker 中,后续 Compose 可直接使用,无需再从镜像仓库下载。
**导入镜像不等于启动服务。** 接下来仍需按第 5 节填写 `server.env`,再按第 6 节通过 Compose 创建、启动 API 容器。
### 4.2 命令行导入(备选)
如果不使用图形界面,也可在 **1Panel 终端**执行以下命令,二选一即可:
```bash
cd /opt/doodle/releases/20261022-01
docker image load -i doodle-server-20261022-01.tar.gz
```
无论采用哪种导入方式,都可以用以下命令补充检查镜像架构和 ID:
```bash
docker image inspect doodle-server:20261022-01 --format '{{.Os}}/{{.Architecture}} {{.Id}}'
```
## 5. 填写服务器配置
### 5.1 `.env`:编排配置
编辑服务器 `/opt/doodle/prod/.env`:
```dotenv
DOODLE_API_IMAGE=doodle-server:20261022-01
PANEL_DOCKER_NETWORK=1panel-network
```
镜像标签必须与刚导入的一致;网络名必须是数据库实际所在网络。
### 5.2 `server.env`:应用配置
编辑 `/opt/doodle/prod/server.env`。文件采用 raw 格式:每行 `KEY=value`,不加包裹引号,不写行尾注释,密钥中的 `$` 不需要改成 `$$`。
| 配置项 | 填写要求 |
| ----------------------------------- | -------------------------------------------------------------------------------------------------------- |
| `NODE_ENV` / `HOST` / `PORT` | 保留 `production` / `0.0.0.0` / `8800`。容器内不能只监听 `127.0.0.1` |
| `JWT_SECRET` | 单独生成至少 32 字节的随机密钥;可在自己的终端执行 `openssl rand -hex 32`,只把结果保存到此文件 |
| `WECHAT_MINI_APP_ID` | 当前小程序 AppID |
| `WECHAT_MINI_APP_SECRET` | 与 AppID 对应的服务端 AppSecret,不能填 JWT 密钥 |
| `DATABASE_URL` | 使用下文格式,指向 `doodle_prod` |
| `QINIU_PUBLIC_DOMAIN` | `https://cdn.joeyone.cn` |
| `QINIU_BUCKET` / `QINIU_KEY_PREFIX` | `doodle-cn` / `doodle-assets/` |
| `QINIU_AK` / `QINIU_SK` | 上传验收前填写真实服务端密钥;只读连通阶段可同时留空 |
| `QINIU_REGION` | 按七牛空间真实区域填写;未知时留空由 SDK 发现,不猜区域 |
| `SWAGGER_ENABLED` | 保留 `false`,生产默认不开放接口文档 |
| `CORS_ORIGINS` | 仅小程序联调可留空;未来 Web 上线时增加准确 origin,例如 `https://doodle.joeyone.cn`,不带路径和末尾 `/` |
| `TRUSTED_PROXY_CIDRS` | 初次留空;确认实际代理来源后再填明确 IP/CIDR,不填 `true` 或任意来源网段 |
| `SITE_REFRESH_HOUR_UTC` | `22`,对应北京时间每日 06:00;新后端任务不会关闭旧云任务 |
数据库连接格式:
```text
postgresql://joey_postgresql:URL编码后的密码@1Panel-postgresql-RqP6:5432/doodle_prod?schema=public
```
这里的 `5432` 是 PostgreSQL **容器内部端口**;数据库主机不是公网 IP,也不是 API 容器的 `127.0.0.1`。不需要开放 PostgreSQL 公网端口。
密码中含 `@`、`#`、`/`、`%` 等字符时必须 URL 编码。可在自己的 **Mac 终端**交互转换,输入不会回显,结果只用于配置,不发送到聊天或截图:
```bash
python3 - <<'PY'
from getpass import getpass
from urllib.parse import quote
print(quote(getpass('数据库原始密码:'), safe=''))
PY
```
完成后在 **服务器终端**限制权限并检查编排语法:
```bash
cd /opt/doodle/prod
chmod 600 .env server.env
docker compose -f compose.api.yaml config --quiet
```
检查成功无输出。不要把不带 `--quiet` 的完整配置输出发到聊天,其中可能包含已展开的密钥。此语法检查不能验证密钥、数据库密码或域名是否正确。
## 6. 核对迁移状态,再启动 API
以下在 **服务器 `/opt/doodle/prod`** 执行:
```bash
cd /opt/doodle/prod
docker compose -f compose.api.yaml run --rm --no-deps api pnpm --filter @doodle/server db:status
```
这个一次性容器使用同样的镜像、环境变量和内部网络,不发布 API 端口,也不会启动 HTTP 服务或业务定时任务。
首次部署且数据库已用当前初始化 SQL 建好时,预期为 **Database schema is up to date**。若报错,按下表处理:
| 输出 | 处理 |
| ------------------------------ | ---------------------------------------------------------------------------- |
| 无法连接 / P1001 | 检查网络、数据库容器名和内部端口 |
| 认证失败 / P1000 | 检查账号、密码 URL 编码及库名 |
| 表已存在但没有迁移历史 / P3005 | 停止,不删除表;核对是否执行了完整初始化 SQL,单独制定基线修复方案 |
| 失败迁移 / 校验和不一致 | 停止,核对初始化脚本与本次镜像版本,不手工把失败记录标为成功 |
| 出现待执行迁移 | 首次预期不应出现;确认这些是计划发布的新增迁移并已备份后,再执行下方迁移命令 |
需要应用已审查的新迁移时执行:
```bash
docker compose -f compose.api.yaml run --rm --no-deps api pnpm --filter @doodle/server db:deploy
```
`db:deploy` 会修改数据库;没有待执行迁移时不会重复初始化。云端不使用 `migrate dev`、`db push` 或 `migrate reset`。
状态确认后启动:
```bash
docker compose -f compose.api.yaml up -d --pull never --wait --wait-timeout 120
docker compose -f compose.api.yaml ps
docker compose -f compose.api.yaml logs --tail=100 api
```
容器名是 `doodle-api-prod`。API 容器自动重启,启动失败时先看日志,不需要叠加 PM2。健康检查通过只说明 HTTP 和数据库能连接,还需要下一节的业务检查。
## 7. 先验证服务器内部访问
在服务器终端执行:
```bash
curl --fail-with-body http://127.0.0.1:8800/api/v1/health
curl --fail-with-body http://127.0.0.1:8800/api/v1/health/ready
curl --fail-with-body http://127.0.0.1:8800/api/v1/categories
curl --fail-with-body 'http://127.0.0.1:8800/api/v1/worksheets?page=1&pageSize=1'
curl --fail-with-body http://127.0.0.1:8800/api/v1/page-config
```
前两个预期 HTTP 200 且 `code: 0`;分类和题型应能查询到已导入并发布的数据。没有数据时检查发布状态、分类可见性、资产 ready 状态和迁移内容,不能仅凭健康检查认定导入成功。
如果 `page_configs.current` 仍为空或快照引用不正确,需要在管理员功能中执行新后端页面重建,再验收首页;不要重新导入默认占位记录。管理员权限以数据库当前角色为准,不会自动把第一个登录用户设为管理员。
服务启动后会运行新后端的任务逻辑:每日首页刷新受 `settings.homeAutoRefresh` 控制;配置七牛密钥后还会处理待清理头像。因此启动前应确认导入的任务、资产状态符合 [生产数据整合与导入方案](./生产数据整合与导入方案.md),不要把开发库的清理队列直接复制到生产。
## 8. 配置 API 域名和 HTTPS
### 8.1 DNS
在 `joeyone.cn` 的 DNS 管理后台添加:
| 类型 | 主机记录 | 记录值 |
| ---- | ------------ | ---------------------------------------------- |
| A | `doodle-api` | `175.24.138.234`(以云控制台当前公网 IP 为准) |
DNS 记录只填 `doodle-api`;1Panel 网站的域名要填完整的 `doodle-api.joeyone.cn`。证书不代替域名解析。
### 8.2 1Panel 创建反向代理网站
进入 **网站 → 创建网站 → 反向代理**:
| 项目 | 值 |
| --------- | ----------------------------------------------------------------------- |
| 域名 | `doodle-api.joeyone.cn` |
| HTTP 端口 | `80` |
| 代号 | `doodle-api` |
| HTTPS | 启用,选择包含 `joeyone.cn` + `*.joeyone.cn` 的已有证书(此前 ID 11) |
| 代理协议 | `http`,TLS 在 OpenResty 终止 |
| 代理地址 | host 网络用 `127.0.0.1:8800`;共享 bridge 网络用 `doodle-api-prod:8800` |
| 应用选择 | 自定义 Compose 服务可能不在商店应用列表,手工填写代理地址即可 |
代理路径为 `/`,保留原始路径和查询参数,**不要把上游填写成 `/api/v1`**,避免重复前缀。创建后检查 HTTPS 监听 443、HTTP 跳转 HTTPS,代理缓存关闭。
网站上传大小建议设为 `4 MB` 或更高,使 2 MiB 图片及 multipart 包装能通过;API 自身仍执行 2 MiB 图片限制。若编辑 OpenResty 配置,在网站对应 `server` 中设置 `client_max_body_size 4m;`,不要重复添加同名指令。使用 1Panel 的配置检测和重载功能,不替换其他网站配置。
腾讯云安全组应允许业务访问 `80/443`。API 的 `8800` 仅发布到宿主机回环地址,无需放行公网 `8800`,数据库也不依赖公网 `5432`。
### 8.3 公网验收
在 **Mac 终端**执行,不加 `-k` 忽略证书验证:
```bash
curl --fail-with-body https://doodle-api.joeyone.cn/api/v1/health
curl --fail-with-body https://doodle-api.joeyone.cn/api/v1/health/ready
curl --fail-with-body https://doodle-api.joeyone.cn/api/v1/categories
```
出现 502 时先回到第 7 节检查 API,再核对 OpenResty 网络和上游。域名根路径 `/` 返回 404 可以是正常现象,应使用实际健康检查路径。
网站绑定已有证书,并确认其自动续签处于开启状态;未来需要核验续签任务与 OpenResty 实际生效证书,不能只看最初签发成功。
## 9. 微信与小程序联调
1. 微信后台配置新后端调用微信接口所需的**实际公网出口 IP 白名单**。`10.0.16.14` 是内网地址,不能填它;若出现微信 `40164`,核对实际出口与白名单。
2. 服务器应能出站访问微信接口及七牛服务。检查 AppID/AppSecret 配对,不能用浏览器随便编造一个 code 判断登录是否成功。
3. 配置 request、uploadFile 合法域名为 `https://doodle-api.joeyone.cn`;资源下载使用的 downloadFile 合法域名包含 `https://cdn.joeyone.cn`。依据实际接口用途添加,不在合法域名中填写 `/api/v1` 路径。
4. API 公网验收成功后,再修改 `doodle-mini/miniprogram/config/api.ts` 中的 `productionBaseUrl` 为 `https://doodle-api.joeyone.cn/api/v1`。`localBaseUrl` 保留本地;未部署 staging 时不将其描述为独立可用的测试环境。本手册不会自动修改小程序地址。
5. 先在 develop 的 Debug 页切到 production,再用体验版验证真实登录、分类、题型、首页、收藏、下载记录、资料保存、头像上传与管理员发布。trial/release 固定 production,不能通过 Debug 切到本地。
6. 使用七牛真实密钥做上传验收前,确认 CloudBase 用户头像绑定、七牛对象 key 和 `assets` 权限映射符合预期,避免把本地测试用户当成线上用户。
只有 HTTP、数据库、真实微信登录和必要业务都验收后,才安排新的正式版发布。旧线上 CloudBase 在并行期仍产生新数据;部署本身不会实现双向同步,正式切换前还需按迁移方案安排最新补导和对账。
## 10. 日常维护、更新和回退
### 查看状态与重新加载配置
在服务器 `/opt/doodle/prod`:
```bash
docker compose -f compose.api.yaml ps
docker compose -f compose.api.yaml logs --tail=100 api
docker stats --no-stream doodle-api-prod
```
修改 `server.env` 后必须重建容器来注入新配置,仅 `restart` 不会读取新环境变量:
```bash
docker compose -f compose.api.yaml up -d --pull never --force-recreate --wait --wait-timeout 120
```
Compose 的内存限制为 768 MiB,Node 堆上限为 384 MiB。上线后根据实际占用调整;不要为小项目预先启动第二套 API/数据库占满服务器。unhealthy 不会自动触发 Docker 重启,需查看告警/日志和实际进程;`restart: unless-stopped` 处理的是进程退出。
### 发布新版本
1. 在本机使用新标签重新构建,保存 Git 提交/工作区说明、构建输出和镜像 ID。
2. 导出、校验、上传、`docker load`;保留旧镜像与旧配置副本。配置副本含密钥,仅存权限受限目录,不能打入发布包。
3. 完整备份数据库并确认可下载恢复;查看本次迁移 SQL,判断旧程序能否兼容新结构。
4. 编辑 `.env` 的 `DOODLE_API_IMAGE` 为新标签,先运行 `db:status`;需要时执行 `db:deploy`,再 `up -d --pull never --wait --wait-timeout 120`。
5. 重做内部和公网健康、业务检查,以及涉及本次改动的小程序验收。
当前是单 API 容器更新,重建期间会有短暂中断;若以后需要零中断,再设计双实例切换。本手册不宣称零停机。
### 应用回退
若数据库结构仍兼容旧镜像,把 `.env` 标签改回上一版本,恢复匹配的运行配置,再执行:
```bash
docker compose -f compose.api.yaml up -d --pull never --wait --wait-timeout 120
```
应用回退不会自动撤销数据库迁移。若新增迁移不兼容旧程序,先停止业务写入并制定恢复方案,不能直接执行 `migrate reset`;恢复旧备份还会丢失备份之后的新写入,必须先保留当前数据。
### 定期备份
通过 1Panel 给 `doodle_prod` 配置每日完整备份、保留周期和服务器外副本,并在独立恢复库演练恢复。网站备份不能自动等同于 PostgreSQL 备份;仅删除/更新 API 容器不会删除数据库,但服务器损坏仍会同时影响本机文件和容器卷。
## 11. 常见故障
| 现象 | 排查方式 |
| ------------------------------- | --------------------------------------------------------------------------------- |
| `env_file ... format` 不支持 | Compose 升级到 2.30.0 及以上 |
| 镜像不存在 / pull access denied | 检查是否执行 `docker load`,以及 `.env` 标签是否一致;离线发布使用 `--pull never` |
| `exec format error` | 镜像架构错误,重建 `linux/amd64` |
| 启动即退出 | 检查 JWT 长度、必填微信凭据、连接串格式及日志;不要贴出真实环境文件 |
| health 成功、ready 失败 | 检查 PostgreSQL 网络、密码、数据库名;health 不检查数据库 |
| ready 成功、业务查询失败 | 检查表结构、迁移历史、导入数据与资产状态 |
| 502 Bad Gateway | 检查 API 是否 healthy、OpenResty 网络与上游地址 |
| 413 Request Entity Too Large | 检查 OpenResty 上传上限及后端图片 2 MiB 限制 |
| 微信 `40164` | 服务端实际出口 IP 不在微信白名单 |
| 登录正常、上传失败 | 检查七牛 AK/SK、空间区域、上传域名及资产权限 |
| 首页为空 | 检查内容发布状态和页面快照;通过有权限的管理员重建 |
| 修改配置后仍用旧值 | `up --force-recreate`,而不是仅 `restart` |
## 12. 本轮验证范围
2026-10-22 已在本机验证 Compose 解析、单 API 服务、回环端口绑定、已有外部网络引用及 raw 环境变量特殊字符处理;文档和 YAML 格式检查通过。
实际尝试构建 `linux/amd64` 镜像时,Docker Hub 的 `node:24.20.0-bookworm-slim` 元数据下载超时,尚未进入依赖安装和编译。因此镜像完整构建、容器启动和迁移 CLI 仍需在网络恢复后验证,不能把本手册当作已部署成功的记录。云端没有执行迁移、启动 API 或修改小程序接口地址。
## 13. 官方参考
- [Docker 跨平台镜像构建参数](https://docs.docker.com/reference/cli/docker/buildx/build/)
- [Docker 镜像导出与压缩](https://docs.docker.com/reference/cli/docker/image/save/)
- [Docker Compose 服务配置:env_file、healthcheck、ports 等](https://docs.docker.com/reference/compose-file/services/)
- [1Panel 创建反向代理网站](https://docs.fit2cloud.com/1panel/user_manual/websites/website-create/)
- [1Panel 网站 HTTPS 与反向代理配置](https://docs.fit2cloud.com/1panel/user_manual/websites/website-config-basic/)