校验文件上传页面与服务部署
使用方式
网站首页提供“上传业务域名校验文件”入口,独立地址为 /admin/verification。输入管理员上传密钥,将微信小程序业务域名配置时下载的原始 .txt 文件拖入页面(也可以点击选择),再点击上传。
文件按原名和原始字节写入服务器 deployRoot/shared/,同名普通文件直接覆盖。若同名路径是目录或符号链接,接口返回错误并保留原路径。仅接受文件名为 1–128 位字母、数字、下划线或短横线加 .txt 后缀的 UTF-8 文本,单文件最大 16 KB,不能为空。不要修改微信提供的文件名或内容。
上传是管理操作,密钥由管理员保管;页面不将密钥存入 localStorage 或前端构建配置。支持通过 /admin/verification?secret=你的密钥 自动填入输入框,未提供或为空时手动填写;填入后会移除地址栏中的 secret,保留其他参数。URL 编码请使用 encodeURIComponent。该链接的初始请求仍可能被服务器或代理访问日志记录,应按敏感链接保管。不要使用 VITE_ 环境变量保存上传密钥。
架构与首次部署
授权回调依然是静态页面;新增上传功能使用 server/verification-upload.mjs,需要额外的 Node.js 22.12+ 服务。服务无需 npm 依赖,仅监听 127.0.0.1:8787,由网站的 HTTPS Nginx 反向代理访问。
pnpm deploy / pnpm deploy:dist 只发布前端,不安装、启动或更新上传服务。 首次启用需完成以下步骤;后续改动服务端文件时需重新上传并重启该服务。前端回滚也不会自动回滚独立上传服务或 shared 中的文件。
方式一:宝塔面板 Node 项目(推荐)
本节对应宝塔“添加 Node 项目”中的「传统项目」界面。通过面板管理启动、停止、重启及环境变量,无需创建 systemd 服务。与下一节 systemd 方式二选一,不要让两个管理器同时启动同一服务,否则会争用 8787 端口。如果此前已通过 systemd 启动,应先停用旧服务并确认端口释放,再创建面板项目;切换期间上传接口会短暂不可用。
1. 准备 Node 和上传文件
- 在宝塔“网站 → Node 项目”的 Node 版本管理入口安装或选择 Node.js 22.12.0 或符合项目要求的更高版本。不同面板版本菜单名称可能略有差异。
- 打开宝塔“文件”,创建
/opt/weixin-web-auth-upload,将本地server/verification-upload.mjs上传到该目录。 - 确认最终文件路径为
/opt/weixin-web-auth-upload/verification-upload.mjs,不是多套一层server/的路径。服务没有第三方依赖,无需上传前端源码、dist、node_modules 或安装 pnpm。 - 通过文件管理检查
/www/wwwroot/webauth.wx.zhang520.cn/shared已存在。该磁盘目录名与访问域名不同是正常的,必须使用服务器实际的持久化 shared 目录,不要指向 current 或某个版本目录。
2. 设置目录权限
在宝塔文件管理中,对 shared 目录打开“权限”设置:
- 所有者和用户组设为
www,目录权限为755。 - 仅调整 shared 目录本身,不勾选递归应用到子目录和文件,保留
.well-known及现有文件的权限。 - 上传服务文件通常设为
644,服务目录通常设为755,其上级目录必须允许www遍历。
程序会在 shared 内创建临时文件,再重命名覆盖同名文件,因此 www 必须能写入 shared 目录。仅将已有 .txt 文件改成可写并不够。不要使用 777 或将运行用户改成 root 来替代正确的目录权限。
3. 填写「传统项目」表单
进入“网站 → Node 项目 → 添加 Node 项目”,选择「传统项目」,按下表填写:
| 表单字段 | 填写内容 |
|---|---|
| 项目名称 | weixin-txt-upload(若该项目已存在,直接进入项目设置修改,不要重复创建) |
| Node版本 | v22.12.0 或符合要求的已安装版本 |
| 启动文件 | /opt/weixin-web-auth-upload/verification-upload.mjs |
| 运行目录 | /opt/weixin-web-auth-upload |
| 参数 | 留空;不要填写完整 node 命令或 --env-file |
在「环境变量」文本框中填写,一行一个 key=value,不要加 export 或引号:
UPLOAD_SHARED_DIR=/www/wwwroot/webauth.wx.zhang520.cn/shared
UPLOAD_ORIGINS=https://webauth.wx.ax3672.cn,https://webauth.wx.zhang520.cn
UPLOAD_PORT=8787
UPLOAD_TOKEN=替换为生成的64位随机密钥密钥可在安装了 Node.js 的本机终端生成:
node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))"将输出的完整字符串填入 UPLOAD_TOKEN,不要使用中文占位内容。密钥只用于本服务管理上传,不是微信 AppSecret,也不是 SSH 私钥。妥善保管,不要提交到 Git 或发到聊天中。
UPLOAD_ORIGINS 多个地址使用英文逗号分隔,每项包含协议,不带末尾 /、路径或查询参数;协议和端口精确匹配。兼容 UPLOAD_ORIGIN,两者同时配置时优先使用 UPLOAD_ORIGINS。这是允许打开管理页面的来源列表,不是后端监听地址。
本方式由面板注入环境变量,不需要 /etc/weixin-web-auth-upload.env,程序也不会自动读取该文件。若服务报环境变量错误,应检查面板中已保存的变量及运行日志。
展开“点击查看,更多配置”,若有对应字段:
| 配置项 | 设置 |
|---|---|
| 项目端口 | 8787,与 UPLOAD_PORT 一致 |
| 运行用户 | www |
| 开机启动 | 开启 |
| 域名绑定/外网映射 | 不配置,继续使用现有静态网站的路径代理 |
| 防火墙端口放行 | 无需对公网开放 8787 |
4. 创建并检查启动
点击“确定”,在 Node 项目列表检查运行状态,再打开项目日志。默认端口下应看到:
Verification upload listening on 127.0.0.1:8787该日志只说明服务已经监听,仍需完成接口代理和实际上传验证。开机启动不等于已经验证崩溃后自动重启,应以当前面板的进程管理能力为准。
| 报错或现象 | 检查方式 |
|---|---|
UPLOAD_TOKEN must contain ... | 变量是否已保存;值是否为 32–256 位字母、数字、下划线或短横线,不带引号或中文 |
UPLOAD_ORIGINS / UPLOAD_ORIGIN must contain ... | 来源列表是否为空,是否包含路径、末尾斜杠、中文逗号或多余空项 |
ENOENT / 共享目录错误 | 启动文件、运行目录和 shared 是否真实存在;shared 路径是否包含软链接 |
EADDRINUSE | 8787 是否被旧 systemd 服务或重复创建的 Node 项目占用 |
| 上传返回“保存失败,请检查共享目录和服务权限” | 优先核对运行用户和 shared 目录写权限;仍失败时检查日志、磁盘容量及文件系统状态,不能仅凭这条通用提示认定原因 |
5. 接入现有网站并测试
完成下文“通用步骤:宝塔 Nginx 配置”和“通用步骤:发布页面并验收”。它们同时适用于面板与 systemd 两种方式。
不要将现有授权域名整站绑定到这个 Node 项目:后端仅提供上传 API,首页与回调页仍由已有静态网站提供。每个允许的域名都应有正确的 HTTPS 配置、上传 API 代理及 shared 校验文件读取规则。
6. 后续更新与重启
修改服务代码后,在宝塔文件管理中先备份原 verification-upload.mjs,上传新文件覆盖,然后在 Node 项目列表中重启 weixin-txt-upload,核对日志并测试上传。修改面板环境变量后同样需要保存并重启。失败时恢复备份文件及原配置,再重启验证。
仅更新服务端无需构建前端;修改上传页面时需重新发布 dist。pnpm deploy 不会更新 /opt/weixin-web-auth-upload 中的文件,也不会自动重启面板 Node 项目。
方式二:systemd 常驻服务(可选)
本节仅供不使用宝塔 Node 项目管理服务的场景。已经完成方式一时,跳过本节,直接进入后面的通用 Nginx 配置。
1. 上传服务程序
在宝塔安装 Node.js 22.12+,在 Linux 终端执行 node -v、command -v node 确认版本及实际可执行路径。下面 systemd 配置中的 /usr/bin/node 必须替换为该实际路径。
在 Linux 服务器执行(示例沿用现有站点目录):
mkdir -p /opt/weixin-web-auth-upload
mkdir -p /www/wwwroot/webauth.wx.zhang520.cn/shared
# 宝塔默认 www 用户;若使用其他服务用户,所有位置保持一致。
chown www:www /www/wwwroot/webauth.wx.zhang520.cn/shared
chmod 755 /www/wwwroot/webauth.wx.zhang520.cn/shared不需要递归修改 shared 既有文件和 .well-known 的所有权。上传服务通过在 shared 内创建临时文件并重命名替换目标文件,避免读到写入一半的内容;服务用户需要 shared 目录的写入权限。
在 Windows 项目根目录执行,修改服务器地址、端口及私钥路径:
scp -P 22 -i "$env:USERPROFILE/.ssh/weixin_web_auth_ed25519" ./server/verification-upload.mjs root@你的服务器IP:/opt/weixin-web-auth-upload/verification-upload.mjs程序放在网站根目录之外,避免源码被静态服务公开访问。
2. 配置服务端密钥和环境
在 Linux 终端生成随机密钥:
node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))"用生成结果替换下方 UPLOAD_TOKEN。通过宝塔文件编辑器或终端创建 /etc/weixin-web-auth-upload.env,内容如下:
UPLOAD_SHARED_DIR=/www/wwwroot/webauth.wx.zhang520.cn/shared
UPLOAD_ORIGINS=https://webauth.wx.ax3672.cn,https://webauth.wx.zhang520.cn
UPLOAD_PORT=8787
UPLOAD_TOKEN=替换为上一步生成的64位随机十六进制字符串UPLOAD_ORIGINS 支持多个允许来源,以英文逗号分隔,逗号两侧空格会自动去除。每项必须为完整 HTTP(S) origin,包含协议和非标准端口(如有),不带路径、查询参数或末尾 /,不支持通配符或空项。协议、域名和端口精确匹配,列表外请求返回 403。兼容旧配置 UPLOAD_ORIGIN(也支持逗号分隔);两者同时设置时以 UPLOAD_ORIGINS 为准,显式设为空会报错,不会回退。每个使用的域名都需配置对应 HTTPS 站点和上传接口代理;此配置用于同源页面的来源校验,不开启跨域 CORS。共享目录必须已存在且路径不能包含软链接。密钥必须为 32–256 位字母、数字、下划线或短横线,示例占位符不能直接使用。
chown root:root /etc/weixin-web-auth-upload.env
chmod 600 /etc/weixin-web-auth-upload.env
chmod 644 /opt/weixin-web-auth-upload/verification-upload.mjs3. 启动常驻服务
创建 /etc/systemd/system/weixin-web-auth-upload.service:
[Unit]
Description=WeChat domain verification upload
After=network.target
[Service]
Type=simple
User=www
Group=www
EnvironmentFile=/etc/weixin-web-auth-upload.env
ExecStart=/usr/bin/node /opt/weixin-web-auth-upload/verification-upload.mjs
Restart=on-failure
RestartSec=3
UMask=0022
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/www/wwwroot/webauth.wx.zhang520.cn/shared
PrivateTmp=true
[Install]
WantedBy=multi-user.targetExecStart 使用实际 Node 路径,确保 www 用户可执行它,且不位于被 ProtectHome=true 屏蔽的家目录中。然后执行:
systemctl daemon-reload
systemctl enable --now weixin-web-auth-upload
systemctl status weixin-web-auth-upload --no-pager排查日志:journalctl -u weixin-web-auth-upload -n 50 --no-pager。修改密钥或程序后运行 systemctl restart weixin-web-auth-upload。不要将 8787 端口开放到公网。
通用步骤:宝塔 Nginx 配置
在该网站 HTTPS server 块中加入以下内容。已有相同 location 时编辑原配置;将以前仅匹配 MP_verify_*.txt 的规则替换为下面通用校验文件规则,使小程序提供的其他文件名也能读取。保留既有 SPA 回退和 .well-known 配置。
location = /api/verification-files {
client_max_body_size 16k;
client_body_timeout 30s;
proxy_pass http://127.0.0.1:8787;
proxy_set_header Host $host;
proxy_set_header Authorization $http_authorization;
proxy_set_header Origin $http_origin;
proxy_read_timeout 35s;
proxy_cache off;
}
# 放在可能匹配 .txt 的其他正则 location 之前。
location ~ "^/[A-Za-z0-9_-]{1,128}\.txt$" {
root /www/wwwroot/webauth.wx.zhang520.cn/shared;
types { }
default_type text/plain;
try_files $uri =404;
add_header Cache-Control "no-store" always;
add_header X-Content-Type-Options "nosniff" always;
}在宝塔检查配置后重载 Nginx。页面需通过 HTTPS 使用,HTTP 应按现有规则跳转 HTTPS;保留证书签发需要的 HTTP .well-known 例外。不要将整个 shared 目录映射为可浏览目录,它包含证书验证等其他持久化文件。
按此规则,访问 https://webauth.wx.ax3672.cn/微信原文件名.txt 会直接读取 shared,上传后立即生效,不依赖重新发布。CDN 若缓存该路径,需同时禁用对应 .txt 缓存或清除旧缓存。
通用步骤:发布页面并验收
执行 pnpm deploy 更新前端,然后访问 /admin/verification:
- 使用错误密钥上传,确认拒绝且服务器没有新文件。
- 使用正确密钥上传测试
.txt,打开返回链接,确认下载内容与本地文件完全相同。 - 修改测试文件内容后再次上传同名文件,确认公网链接返回新内容。
- 重新部署前端,再次读取该链接,确认文件仍存在。
- 上传微信原始校验文件并核对后,回到微信后台保存业务域名;测试文件用完后由管理员删除。
上传成功只代表已保存文件,不代表微信验证已通过。若链接返回首页 HTML,通常是 Nginx .txt 规则未生效;502 表示上传服务没有运行或代理端口错误;401 表示密钥错误;403 表示请求来源不在允许列表中;500 应检查目录写入权限和服务日志。
Windows 本地联调
在项目根目录打开 PowerShell,创建 Git 忽略的本地目录并启动服务:
New-Item -ItemType Directory -Path .upload-local -Force | Out-Null
$env:UPLOAD_SHARED_DIR = (Resolve-Path .upload-local).Path
$env:UPLOAD_ORIGINS = 'http://localhost:5173'
$env:UPLOAD_TOKEN = node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))"
# 复制输出的密钥到页面,仅用于当前本地测试。
$env:UPLOAD_TOKEN
pnpm upload:serve另开终端运行 pnpm dev,访问 http://localhost:5173/admin/verification。Vite 已将上传 API 代理至本机 8787;如果 Vite 使用其他端口或主机名,请同步修改 UPLOAD_ORIGINS 并重启上传服务。本地上传写入 .upload-local,不会访问生产服务器;本地 Vite 不提供 shared 文件读取,成功后的公网校验链接需在配置 Nginx 的部署环境验收。
参考:Node.js 文件系统、Nginx 反向代理、Nginx 路由及文件读取。
宝塔「传统项目」可直接在环境变量输入框填写 UPLOAD_ORIGINS=https://webauth.wx.ax3672.cn,https://webauth.wx.zhang520.cn(整项一行,不加引号)。将更新后的 server/verification-upload.mjs 上传覆盖服务入口,保存配置并重启 Node 项目后生效;无需重新构建前端。
ESA 接入注意
上传 API、管理页面(尤其含 secret 参数的地址)、根目录校验 .txt 和 ACME 路径必须配置绕过缓存。保留本页校验文件及后端 API 的 no-store,不要为了静态资源加速而全站删除。上线绕过规则时清理这些路径的历史缓存,随后验证同名文件覆盖可立即读取新内容。详见ESA 缓存配置。
