发布到宝塔 Linux 服务器
项目通过本机 OpenSSH(ssh/scp)上传静态 dist,仅运行授权回调时服务器无需安装 Node.js;新增的校验文件上传功能需独立 Node.js 服务,不使用宝塔面板 API 或面板密码。发布会创建版本目录并原子切换 current 符号链接;旧版本和原站点文件保留。
1. 准备服务器与 SSH
本机需要 Node.js、pnpm、ssh、scp、tar。Windows 可在 PowerShell 中运行 Get-Command ssh,scp,tar 检查。Linux 服务器需要 bash、GNU tar/coreutils 和 flock(通常由 util-linux 提供),以及可用的 SSH/SFTP 服务。
在宝塔创建或使用现有静态网站,绑定实际回调域名(例如 webauth.wx.ax3672.cn),配置解析与 HTTPS。以下示例保留现有站点磁盘路径 webauth.wx.zhang520.cn;域名与磁盘目录名不必相同。部署用户需要对站点目录拥有读写权限,Nginx 用户需要目录遍历和文件读取权限;脚本不使用 sudo,不修改宝塔、SSH 或 Nginx 配置。
1.1 Windows 安装并检查 OpenSSH 客户端
以下本机命令均在 Windows PowerShell 中执行。只需要 OpenSSH 客户端,不需要在 Windows 上安装 SSH 服务端。
Get-Command ssh, scp, ssh-keygen, ssh-add, tar
ssh -V如果找不到 SSH 命令,在 Windows 的“设置 → 可选功能”中安装“OpenSSH 客户端”,或以管理员身份打开 PowerShell 执行:
Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0安装后重新打开终端并再次检查。后续生成密钥、加载密钥和运行部署命令应使用同一个 Windows 用户。
1.2 生成项目专用公钥和私钥
在普通 PowerShell 中执行下列命令。使用项目专用文件名,避免覆盖其他项目正在使用的密钥:
$sshDirectory = Join-Path $env:USERPROFILE '.ssh'
$deployKey = Join-Path $sshDirectory 'weixin_web_auth_ed25519'
New-Item -ItemType Directory -Path $sshDirectory -Force | Out-Null
if ((Test-Path -LiteralPath $deployKey) -or (Test-Path -LiteralPath "$deployKey.pub")) {
throw '该密钥文件已存在,请复用现有密钥,或更换文件名后重试;不要覆盖。'
}
ssh-keygen -t ed25519 -C 'weixin-web-auth-deploy' -f "$deployKey"命令会依次提示输入 Enter passphrase 和 Enter same passphrase again,建议设置口令保护私钥,再按第 1.4 节交给 ssh-agent 使用。输入口令时终端不会显示字符,这是正常现象。直接按两次回车可生成无口令私钥,但任何拿到该文件的人都可能使用它登录服务器,因此应妥善限制文件访问权限。
生成后会得到两个文件(你的用户名 对应当前 Windows 账户):
| 文件 | 用途 | 保存位置 |
|---|---|---|
C:/Users/你的用户名/.ssh/weixin_web_auth_ed25519 | 私钥,配置到 identityFile | 仅保存在本机,不上传服务器、不提交 Git |
C:/Users/你的用户名/.ssh/weixin_web_auth_ed25519.pub | 公钥,允许服务器识别本机 | 将内容追加到服务器目标用户的 ~/.ssh/authorized_keys |
identityFile 不是自行创建的空文件,也不是 .pub 文件,而是 ssh-keygen 生成的私钥。密钥不要放进项目、public、dist 或网站目录。
查看公钥和其指纹:
Get-Content -LiteralPath "$env:USERPROFILE/.ssh/weixin_web_auth_ed25519.pub"
ssh-keygen -lf "$env:USERPROFILE/.ssh/weixin_web_auth_ed25519.pub"1.3 将公钥安装到 Linux 服务器
首先用已有的 Linux SSH 登录方式连接服务器(示例使用 root;实际部署用户与端口须保持一致):
ssh -p 22 root@你的服务器IP首次连接前,通过云服务器控制台或可信的宝塔终端核对 SSH 主机指纹,例如在服务器执行 ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub,与客户端提示的对应算法指纹比较。确认一致后输入 yes,将其记录到 Windows 用户的 known_hosts。不要在指纹变化时直接删除记录并忽略警告,应先确认服务器是否重装或更换密钥。
登录密码是 Linux 用户密码,不是宝塔面板密码。如果服务器不允许密码登录,可通过云服务器控制台或宝塔终端进入服务器,切换到实际部署用户,再完成下列步骤。
在 Linux 服务器终端 中执行,替换示例公钥为上一步 .pub 文件的完整单行内容(从 ssh-ed25519 开始,不能使用私钥内容):
mkdir -p ~/.ssh
chmod 700 ~/.ssh
touch ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
# 先补一个换行,避免原文件末尾没有换行时粘连已有公钥
printf '\n' >> ~/.ssh/authorized_keys
cat >> ~/.ssh/authorized_keys <<'PUBLIC_KEY'
ssh-ed25519 替换为你的公钥数据 weixin-web-auth-deploy
PUBLIC_KEY这里使用 >> 追加,不覆盖已有公钥。公钥必须保持一行,不能手工插入换行。root 的目标文件通常是 /root/.ssh/authorized_keys,其他用户则位于各自家目录;文件及 .ssh 目录应归该目标用户所有。默认 OpenSSH 配置使用这个路径,若服务器自定义了 AuthorizedKeysFile,请使用实际配置路径。配置完成后输入 exit 回到 Windows,或保留当前服务器会话并另开本机终端进行测试。
1.4 加密私钥加入 Windows ssh-agent
部署脚本启用 BatchMode,不会交互询问密码或私钥口令。若私钥设置了口令,需要先加载到本机 ssh-agent。
先以管理员身份打开 PowerShell,启用 Windows 自带的代理服务(一般只需配置一次):
Set-Service -Name ssh-agent -StartupType Automatic
Start-Service ssh-agent
Get-Service ssh-agent然后回到运行部署的 普通 PowerShell / VS Code 终端,使用生成密钥的同一个 Windows 用户执行:
ssh-add "$env:USERPROFILE/.ssh/weixin_web_auth_ed25519"
ssh-add -lssh-add 会提示输入私钥口令;ssh-add -l 应列出该密钥指纹。如果重启、更换账户或清理代理后密钥未加载,再执行一次 ssh-add。无口令私钥可以直接通过 -i 使用,无需代理。
1.5 验证非交互登录并填写 identityFile
在普通 PowerShell 中,使用与部署脚本相同的严格指纹检查和非交互方式测试:
ssh -i "$env:USERPROFILE/.ssh/weixin_web_auth_ed25519" -p 22 -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes -o BatchMode=yes root@你的服务器IP "echo SSH_OK"输出 SSH_OK 且退出码为 0,才说明本机能够完成非交互认证;这并不代表站点目录写入权限已经就绪。随后在第 2 节的 deploy.local.json 中填写生成的私钥路径。可运行以下命令获得适用于 JSON 的路径:
(Join-Path $env:USERPROFILE '.ssh/weixin_web_auth_ed25519').Replace('\', '/')常见问题:
Permission denied (publickey):检查登录用户、公钥是否安装到该用户目录、私钥路径和公钥是否配对,以及 Linux 文件所有者和权限;加密私钥还需确认ssh-add -l中存在对应指纹。若服务器禁止 root 登录,应改用允许登录且有站点写权限的用户,不要直接放宽 SSH 安全配置。Host key verification failed:先完成第 1.3 节的指纹核对与首次连接;自定义端口也须使用相同端口连接。Could not open a connection to your authentication agent:检查 Windowsssh-agent服务是否运行,以及Get-Command ssh, ssh-add是否来自同一套 OpenSSH。Git Bash、WSL 与 Windows 自带的代理环境可能不同,本说明统一使用 Windows PowerShell。UNPROTECTED PRIVATE KEY FILE/bad permissions:检查本机私钥的 Windows 文件权限,移除无关用户的读取权限,不要将私钥放在共享目录。- 连接超时或拒绝连接:检查 SSH 服务、SSH 端口、云安全组和服务器防火墙;宝塔面板端口不能代替 SSH 端口。
Windows 密钥生成和代理操作参考:Microsoft OpenSSH 密钥管理文档。本节公钥安装目标是 Linux,不使用 Windows 服务端的 administrators_authorized_keys 路径。
2. 创建本地部署配置
仓库当前不提供 deploy.example.json。在项目根目录新建 deploy.local.json,填写以下内容(不要覆盖已有配置):
{
"host": "你的服务器IP或SSH别名",
"port": 22,
"user": "root",
"identityFile": "C:/Users/你的用户名/.ssh/weixin_web_auth_ed25519",
"deployRoot": "/www/wwwroot/webauth.wx.zhang520.cn"
}port是 SSH 端口,不是宝塔面板端口。identityFile可以留空,使用 SSH 默认密钥或 agent;路径也支持~/.ssh/weixin_web_auth_ed25519。JSON 中 Windows 路径使用/。deployRoot是站点的发布管理目录,只允许/www/wwwroot/站点目录名。该目录本身及其父路径不能是符号链接。deploy.local.json已被 Git 和 Prettier 忽略,不要放在 public 或 dist 中。其他自定义配置文件需自行加入 .gitignore。- Vite 的生产环境变量仍在构建前配置;deploy.local.json 只控制上传目的地,不影响页面业务配置。
3. 检查并发布
# 构建 + 查看目标,不连接服务器
pnpm build
pnpm deploy:plan
# 上传已生成的 dist
pnpm deploy:dist
# 后续也可以一条命令重新构建并发布
pnpm deploydeploy:dist 不重新构建,发布的就是当前 dist;修改环境变量或代码后需先构建。支持 pnpm deploy:dist --config 其他配置.json,或 pnpm deploy:dist --dry-run。
脚本流程:检查产物与配置 → 打包临时 tar.gz → SSH 远程路径检查 → SCP 上传 → SHA-256 校验 → 解压新版本并验证 index.html → 检查、迁移共享 .well-known 并建立版本链接 → 切换 current → 删除本次上传包。失败会停止后续操作,切换前失败保持原 current。上传/解压失败可能留下包或未完成版本供排查;脚本不自动清空历史目录。并发激活/回滚通过 flock 防止相互覆盖。
远程目录:
/www/wwwroot/webauth.wx.zhang520.cn/
current -> releases/20260913003000-abcdef123456
releases/
20260913003000-abcdef123456/
index.html
assets/
.well-known -> ../../shared/.well-known
shared/ # 微信校验 .txt 与持久化 .well-known 目录
.well-known-backups/ # 首次迁移保留的原目录
.uploads/ # 上传暂存(仅部署用户可访问)版本号以 UTC 时间加随机后缀生成。记录发布输出的当前版本和 Previous target,便于回滚。
4. 宝塔首次配置网站根目录
首次发布成功后,将该网站的实际 Nginx root(网站目录/运行目录对应配置)设置为:
/www/wwwroot/webauth.wx.zhang520.cn/current必须指向 current,不能把 deployRoot 当作网站根目录,否则无法显示新版本,并可能暴露历史版本目录。脚本不会覆盖已有 current 实体目录;若存在此情况,先人工检查并迁移。
授权站点的 SPA 路由与响应头请按阿里云 ESA 加速与缓存配置:先在 Nginx http 块加入 map,再合并站点 location。普通首页使用正数 TTL,哈希资源长期缓存,回调、管理页面、上传 API 和校验文件绕过缓存。仓库提供 config/nginx/auth-cache-http.conf 与 config/nginx/auth-cache-server.conf;不要继续对所有 index.html 响应统一设置 no-store。
在宝塔检查配置并重载 Nginx。确保 Nginx 未通过自定义 disable_symlinks 禁止该 current 链接;无需全局关闭任何安全设置。后续发布只切换链接,通常不需要重载 Nginx;若自定义了 open_file_cache/CDN,需按缓存策略处理刷新。
保留宝塔已有的 HTTPS 和 ACME 验证配置。脚本现在自动将每个发布版本的 .well-known 链接到 deployRoot/shared/.well-known,发布和回滚均执行此检查。宝塔仍向 current/.well-known/acme-challenge/ 写入,Linux 会将写入转到共享目录;Nginx 通过相同路径读取,不需要修改网站根目录或证书保存位置。
首次更新注意:
- 首次迁移应避开正在进行的证书签发或续签。部署锁只能协调本项目部署,不能锁住宝塔证书任务;实体目录替换成链接存在极短的路径切换窗口。
- 当前版本或回滚目标中已有的实体
.well-known会先检查文件冲突,合并到共享目录后,原目录整体移至deployRoot/.well-known-backups/migration.*/original保留。 - 同路径内容不同、文件/目录类型冲突、未知软链接或特殊文件会停止处理。不会直接覆盖冲突文件;新版本不会切换上线。此前已完成的无损共享迁移可能保留。
- 若替换链接失败,脚本尝试恢复原实体目录,并输出失败信息。备份路径会写入终端;如果恢复也失败,会输出
RESTORE REQUIRED,需根据路径恢复。 - 共享目录权限设为目录 755、文件 644;root 部署且存在 www 用户时,共享根和 acme-challenge 目录归 www 所有。非 root 部署需事先保证宝塔写入用户与部署用户的权限兼容;脚本遇到写入或权限调整失败会停止。
- dist 不能携带
.well-known,请勿将验证目录加入 public;也不要随历史版本清理删除 shared 或跟随版本内的软链接递归清理。
Linux 上可运行隔离测试(仅操作 mktemp 临时目录):
bash tests/deploy-acme.sh scripts/deploy-well-known.sh首次发布后,建议在 current/.well-known/acme-challenge/ 写入随机测试文件,从公网 HTTP 读取并核对内容;再次部署后重复读取,验证共享目录持续可用,完成后删除测试文件。不要使用真实验证文件作为测试文件。脚本本身不自动向公网发起探测,也不自动申请或续签证书。
微信校验文件:将服务号和小程序的校验 .txt 文件放入 deployRoot/shared/,脚本每次发布会复制到版本根目录。也会兼容复制原 deployRoot 下的 MP_verify_*.txt。未配置独立读取规则时,更新后需重新发布。此前已为线上站点配置 MP_verify_*.txt 直接从 shared 读取的规则,这种配置下上传后即可生效,且不受回滚影响。新服务器需手动加入下方规则,部署脚本不会修改 Nginx。
location ~ ^/MP_verify_[A-Za-z0-9]+\.txt$ {
root /www/wwwroot/webauth.wx.zhang520.cn/shared;
default_type text/plain;
try_files $uri =404;
add_header Cache-Control "no-store" always;
}5. 回滚
# 填写此前发布输出的真实版本号
pnpm deploy:rollback 20260913003000-abcdef123456 --dry-run
pnpm deploy:rollback 20260913003000-abcdef123456回滚只切换到已完成发布且存在 index.html 的版本,不重新构建或上传。脚本保留全部历史版本;可定期人工清理确认不再使用的版本,不能删除 current 指向的目录或仍需要的回滚版本。
6. 发布后验证
访问首页确认默认说明正常。场景预览页面已删除;直接访问缺少 code/state 的回调地址应显示无标题错误弹窗。用真实微信授权链路验证回调期间仅展示 loading,随后返回业务站点或小程序;网页标题为空。刷新 /callback/web 和 /callback/mini 确认 SPA 回退正常,并核对微信校验文件 URL 和 ACME 测试文件可访问。部署脚本校验的是文件完整性和链接切换,不代表域名、TLS、宝塔配置或微信授权已经通过验收。
本仓库测试覆盖部署配置与路径校验、打包范围检查;提供 dry-run。没有服务器配置时不会实际连接或部署。
SSH 行为参考:OpenSSH ssh、OpenSSH scp。
7. 启用网页上传校验文件
按校验文件上传服务部署指南优先通过宝塔“Node 项目 → 传统项目”配置独立上传服务。指南包含逐字段填写、管理员密钥、多来源环境变量、shared 目录权限、Nginx 代理和更新验证;也保留 systemd 作为可选方式,两种方式不要同时启动。该指南中的通用 .txt 读取规则应替换本文前面的 MP_verify_*.txt 读取规则,以支持小程序提供的其他校验文件名。上传文件直接进入 shared,立即可读取;pnpm deploy 只更新静态页面,服务端程序需按指南单独更新并重启。
