Files
WebDrop/docs/deployment.md
T
justme 1245aedfd2
ci/woodpecker/push/web-build Pipeline was successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/dev-image Pipeline was successful
docs: record how to measure upload speed without the Vite proxy [CI]
2026-10-16 19:42:33 +08:00

7.0 KiB

Podman Quadlet 部署

WebDrop 使用 rootless Podman 运行单个 API 容器。前端先构建成静态文件,再嵌入 NativeAOT 后端;容器镜像使用 OCI 格式。仓库不再维护 Compose 配置。

WSL 本机部署

在 Windows 工作区运行:

.\scripts\update-wsl-podman.ps1

本机开发直接从当前 Windows 工作区调用 WSL Podman。脚本会把源码增量同步到 WSL 的 ~/podman/webdrop/src,在 WSL Linux 文件系统里构建 OCI 镜像,构建成功后重启 Quadlet 服务使用新镜像。构建失败时不会更新正在运行的容器;本机流程不经过镜像仓库。

部署目录:

  • ~/podman/webdrop/src:从当前 Windows 工作区同步的源码副本。
  • ~/podman/webdrop/data:SQLite 数据和服务端帧文件。首次运行时从仓库 data/ 拷贝一次,后续更新不会覆盖它。
  • ~/podman/webdrop/webdrop.container:Quadlet 单元源文件,链接到 ~/.config/containers/systemd/webdrop.container。

服务地址为 http://127.0.0.1:5000。管理服务:

systemctl --user status webdrop.service
systemctl --user stop webdrop.service
systemctl --user start webdrop.service

本机开发前端仍可运行 cd web && npm run dev,Vite 会代理 /api/v1 到本地 API。公网部署时,在 API 前配置 HTTPS 反向代理;不要把未加密 HTTP 直接暴露到公网。只有当 API 端口仅能由可信代理访问时,才信任 forwarded headers。

开发时测上传速度

经 Vite 开发代理(npm run dev 默认)转发上传,速度上限约 20–25 MB/s,这是 Node 代理的限制,和应用本身无关。要测到真实速度,让前端直连后端:

# 后端:允许前端所在的来源跨域(端口按实际的前端端口填)
WebDrop__CorsOrigins__0=http://127.0.0.1:5173 ASPNETCORE_URLS=http://127.0.0.1:5000 dotnet run --project server/src/WebDrop.Api --no-launch-profile

# 前端:把 API 指向后端,不走代理
cd web && VITE_WEBDROP_API_URL=http://127.0.0.1:5000/api/v1 npm run dev

本机实测直连约 90 MB/s(300 MB 随机文件 3.3 秒)。上传帧的限流和普通接口分开计数(WebDrop:FrameRequestsPerMinute,默认 6000/分钟),上传请求体用 Blob 发送(浏览器对字节数组请求体要多拷贝几次,会慢 5 倍以上)。

其他 Linux 主机

构建 OCI 镜像:

podman build --layers --format oci --platform linux/amd64 \
  --file server/Containerfile --tag localhost/webdrop:local .

将 deploy/webdrop.container 安装到 ~/.config/containers/systemd/ 前,把数据卷路径改为该主机专用目录。然后执行:

systemctl --user daemon-reload
systemctl --user start webdrop.service

WSL 更新脚本在每次构建成功后直接重启 Quadlet 服务。这里不使用 registry auto-update,因为新镜像已经在本机刚刚构建完成。

NAS 开发与生产

NAS 开发环境使用 deploy/webdrop-dev.container,镜像固定跟踪 registry.oeo.one/justme/webdrop-api:dev;开发 CI 成功后会推送该标签。此单元设置 AutoUpdate=registry,并将用户级 timer 调整为启动后一分钟检查、之后每五分钟检查一次,发现新镜像就重启 Quadlet 服务;也可以手动执行 podman auto-update 立即检查。它使用独立的 webdrop-dev 容器、5001 本机端口和 ~/podman/webdrop-dev/data,与 WSL 本机开发及生产数据隔离。

在 NAS 安装该单元前,先以 justme 登录 registry 并把凭据保存在用户级 auth file:

mkdir -p ~/.config/containers
printf '%s' "$ZOT_SECRET" | podman login --authfile ~/.config/containers/auth.json \
  --username justme --password-stdin registry.oeo.one
chmod 600 ~/.config/containers/auth.json
mkdir -p ~/.config/containers/systemd ~/podman/webdrop-dev/data
cp deploy/webdrop-dev.container ~/.config/containers/systemd/
mkdir -p ~/.config/systemd/user/podman-auto-update.timer.d
cp deploy/podman-auto-update.timer.d/override.conf \
  ~/.config/systemd/user/podman-auto-update.timer.d/override.conf
systemctl --user daemon-reload
systemctl --user start webdrop-dev.service
systemctl --user enable --now podman-auto-update.timer
systemctl --user restart podman-auto-update.timer

为确保 NAS 注销 SSH 会话后 user service 仍持续运行,管理员需要为该账号启用 lingering:sudo loginctl enable-linger justme。

不要把 ZOT_SECRET 写入仓库或 Quadlet 文件。生产使用 release workflow 发布的 vMAJOR.MINOR.PATCH 标签,应固定到明确版本,不要跟踪 dev。

验证码配置写在 Quadlet 的 [Container] 段,例如:

Environment=WebDrop__Captcha__Provider=cap
Environment=WebDrop__Captcha__ApiEndpoint=https://captcha.example.com/<site-key>/
Environment=WebDrop__Captcha__SiteverifyUrl=https://captcha.example.com/<site-key>/siteverify
Environment=WebDrop__Captcha__Secret=<server-side-secret>

SiteverifyUrl 和 Secret 仅供 API 容器使用。修改后运行 systemctl --user daemon-reload 并重启服务。

Woodpecker CI

.woodpecker/ci.yml 在默认分支 push、pull request 和手动运行时执行 API 契约与服务端检查;.woodpecker/web-build.yml 同时执行 Core 测试向量、类型检查、Web CSS lint、测试和构建。两个 workflow 独立运行,让前后端验证并行。默认分支当前为 master,配置也兼容迁移后的 main。

默认分支每次 push 和 PR 都会跑常规检查。提交信息含 [SKIP TESTS] 时只跳过服务端测试;API 契约检查和前端/Core 检查照常运行。提交信息含 [CI] 时,.woodpecker/dev-image.yml 会等 ci 和 web-build 都通过后,构建并推送带提交 SHA 的开发镜像以及可变 dev 标签。开发镜像不会覆盖 release tag 或 latest。发布目标为 registry.oeo.one/justme/webdrop-api;Buildah 使用 Woodpecker secret zot_secret 作为 Zot API key 的密码字段,用户名为 justme,并启用 TLS 校验。Gitea clone 凭据保存在 gitea_clone_webdrop secret。

.woodpecker/release-backend.yml 响应 vMAJOR.MINOR.PATCH SemVer tag;也可手动运行并传入 RELEASE_TAG。发布 workflow 会重新执行 Core、Web 和服务端完整检查,全部通过后才用 Linux native agent 的 Buildah 构建 OCI 镜像并推送后端镜像 tag 与 latest。所有 workflow 都通过 Woodpecker secret gitea_clone_webdrop 从 https://git.oeo.one 克隆公开仓库。

两条流水线固定到 ci: domain-linux-native 的 linux/amd64 Agent;该主机需要 Node 24、.NET 10 和 Buildah。release job 在 WOODPECKER_BACKEND_LOCAL_TEMP_DIR 对应的持久目录缓存 Buildah 层;server/Containerfile 使用带 NativeAOT 前置工具的 10.0-noble-aot SDK 镜像,不再运行 apt 安装 clang/zlib;NuGet restore 层也由 Buildah 缓存。Gitea webhook 使用 Woodpecker server 所在网络,代码 clone 走公网 Git 域名。

数据备份

停止服务或使用一致性快照后备份 ~/podman/webdrop/data。目录里保存 SQLite 元数据和服务端收到的帧字节;加密频道/分享的内容帧是密文。备份仍需按敏感数据保护,因为 raw 频道按设计保存明文负载。