ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Wasp 应用自托管部署到 Caprover 完整指南:GitHub Actions + GHCR 全自动 CI/CD

Wasp 应用自托管部署到 Caprover 完整指南:GitHub Actions + GHCR 全自动 CI/CD Wasp 应用自托管部署到 Caprover 完整指南GitHub Actions GHCR 全自动 CI/CD【免费下载链接】waspThe batteries-included full-stack framework for the AI era. Develop JS/TS web apps (React, Node.js, and Prisma) using declarative code that abstracts away complex full-stack features like auth, background jobs, RPC, email sending, end-to-end type safety, single-command deployment, and more.项目地址: https://gitcode.com/GitHub_Trending/wa/wasp本指南基于 Wasp 开源仓库官方文档 web/docs/guides/deployment/self-hosted/caprover.md详细讲解如何将一个 Wasp 全栈应用React 客户端 Node.js 服务端 PostgreSQL 数据库部署到自托管的 Caprover PaaS 平台。读完本文你将掌握在 Caprover 中创建数据库、服务端、客户端三个应用配置域名与 HTTPS以及通过 GitHub Actions 在推送main分支时自动构建 Docker 镜像、推送到 GitHub Container RegistryGHCR并触发 Caprover 滚动部署的完整实战流程。版本说明本指南经 Wasp 0.24 与 Caprover 1.14.1 验证见文档头部LastCheckedWithVersionsNotice标记文中的命令与配置适用于这两个版本及其相邻版本。为什么 Wasp 应用要拆成三部分部署Wasp 是batteries-included的全栈框架一个main.wasp.ts声明文件同时描述客户端React Vite、服务端Node.js Express和数据模型Prisma PostgreSQL。当你在本地运行wasp build时生成器会把这三部分分别输出到.wasp/out目录下的web-app/、server/和db/等子目录中可参考 CLI 文档 对wasp build的描述generates the complete web app code, which is ready for deployment. The generated code is stored in the.wasp/outfolder。正因为构建产物天然分离生产部署也遵循同样的三件套模式客户端wasp build输出的web-app经过 Vite 构建后是一堆纯静态文件HTML/JS/CSS需要一个静态文件服务器来托管服务端.wasp/out/server是一个可独立运行的 Node.js 服务对外提供 REST API、WebSocket 和认证逻辑数据库Wasp 服务端依赖 PostgreSQL通过DATABASE_URL连接由 Prisma 管理 schema 与迁移。Caprover 恰好以应用 容器为基本单位三者可以各自成为一个 Caprover 应用互不干扰、独立伸缩这正是本文方案的架构基础。部署总览将 Wasp 应用部署到 Caprover 的核心链路如下在 Caprover 中创建三个应用数据库myapp-db、服务端myapp-server、客户端myapp-client使用 GitHub Actions 在 CI 中执行wasp build分别构建服务端与客户端的 Docker 镜像将两个镜像推送到 GitHub Container RegistryGHCR通过 Caprover 官方 Action 触发 Caprover 拉取并部署新镜像。下面按照原文档的步骤顺序逐一展开。前置条件开始之前请确认你已具备以下资源一台安装了 Caprover 的服务器Caprover 是一个自托管的 PaaSPlatform as a Service负责管理你的应用部署。安装方式参考 Caprover 官方快速开始文档一个域名用于对外提供服务的入口一个托管着 Wasp 应用代码的 GitHub 仓库CI/CD 的触发源与镜像仓库载体。:::tip 快速测试路径 如果你在安装 Caprover 时配置了*.apps通配子域名可以直接使用https://myapp-client.apps.mydomain.com和https://myapp-server.apps.mydomain.com这类地址做快速联调不必先解析两条 DNS A 记录。 :::Step 1设置域名解析在域名服务商处添加两条 DNS A 记录将流量指向你的服务器 IP记录指向用途根域名服务器 IP客户端入口如myapp.comapi子域名服务器 IP服务端入口如api.myapp.com注意保持与后续 Caprover 应用 HTTP 设置中的域名一致DNS 生效后才能顺利签发 HTTPS 证书Caprover 使用 Lets Encrypt 自动颁发。Step 2在 Caprover 中创建三个应用2.1 创建数据库PostgreSQL进入 Caprover 面板打开One-Click Apps选择PostgreSQL将应用命名为myapp-db版本选择18或当前最新版本点击部署等待数据库容器就绪记下数据库连接串格式形如postgresql://postgres:passwordsrv-captain--myapp-db:5432/postgres其中srv-captain--myapp-db是 Caprover 内部网络中该应用的固定主机名服务端应用必须通过这个内部地址访问数据库而不是公网域名——这样既快又安全数据库不对外暴露端口。2.2 创建服务端应用myapp-server新建应用命名为myapp-server进入HTTP SettingsConnect domainhttps://api.your-domain点击Enable HTTPS自动签发证书Container HTTP Port3001开启Force HTTPS与Websocket Support点击Save Restart。端口3001是 Wasp 服务端的默认监听端口开发环境下 Wasp 默认在 3001 启动服务器生产构建的服务端镜像也通过PORT环境变量读取监听端口见下文 Step 3 的环境变量表。开启Websocket Support是因为 Wasp 的实时功能如 WebSocket 订阅、部分认证流程依赖 WebSocket 长连接。2.3 创建客户端应用myapp-client新建应用命名为myapp-client进入HTTP SettingsConnect domainhttps://your-domain点击Enable HTTPSContainer HTTP Port8043开启Force HTTPS与Websocket Support点击Save Restart。客户端镜像基于静态文件服务器pierrezemb/gostatic构建该镜像默认监听 8043 端口因此容器 HTTP 端口要填8043。WebSocket Support 同样建议开启避免反向代理中断客户端与服务器之间的实时连接。Step 3配置服务端环境变量在 Caprover 中打开myapp-server应用进入App Configs Environment Variables添加以下变量变量值作用DATABASE_URLpostgresql://postgres:passwordsrv-captain--myapp-db:5432/postgresPostgreSQL 连接串Wasp 服务端与 Prisma 迁移都依赖它JWT_SECRET至少 32 字符的随机字符串用于生成安全的 JWT token开发环境默认值为DEVJWTSECRET生产环境必须显式设置PORT3001服务端监听端口必须与 Caprover 中设置的 Container HTTP Port 一致WASP_WEB_CLIENT_URLhttps://your-domain客户端对外 URL服务端用它生成邮件中的应用链接等WASP_SERVER_URLhttps://api.your-domain服务端对外 URLOAuth 登录如 Google、GitHub回调时依赖它做重定向以上变量的具体语义可查阅 环境变量文档 中Server General Configuration一节DATABASE_URL是必填的数据库地址WASP_WEB_CLIENT_URL与WASP_SERVER_URL是生产环境必填的开发环境由 Wasp 自动填充生产环境缺失会导致服务端启动失败JWT_SECRET需要至少 32 个字符的随机串。另外把.env.server中应用需要的其他环境变量一并添加进来例如邮件服务商相关SMTP_HOST、SMTP_PORT、SMTP_USERNAME、SMTP_PASSWORDSMTP 发送器、SENDGRID_API_KEY、MAILGUN_API_KEY、RESEND_API_KEY等OAuth 相关GOOGLE_CLIENT_ID、GOOGLE_CLIENT_SECRET、GITHUB_CLIENT_ID、GITHUB_CLIENT_SECRET等命名规则为PROVIDER_NAME_CLIENT_ID/PROVIDER_NAME_CLIENT_SECRET你自定义的任意服务端变量如 Stripe 密钥。:::caution 客户端环境变量的区别 与服务端不同客户端环境变量REACT_APP_*前缀是在构建期注入到静态文件中的Vite 构建时会替换import.meta.env.REACT_APP_XXX因此在 Caprover 面板里给客户端应用设置环境变量是无效的——它们必须在 GitHub Actions 构建时通过命令行提供详见 部署期环境变量文档。客户端变量不能存放任何密钥因为它们对浏览器公开可见。 :::Step 4配置 GitHub Container Registry 访问为了让 Caprover 能拉取 GHCR 上的私有镜像需要在 Caprover 中登记远端镜像仓库进入 Caprover 的Cluster页面添加新的Remote RegistryUsername你的 GitHub 用户名Password你的 GitHub personal access token需具备write:packages权限Domainghcr.ioImage Prefix你的 GitHub 用户名这样 Caprover 在部署ghcr.io/username/myapp-server这类镜像时就能通过认证拉取。Step 5编写 GitHub Actions 工作流在你的仓库中创建.github/workflows/deploy.yml内容如下完整保留原文档配置name: Deploy on: push: branches: - main concurrency: group: deployment cancel-in-progress: true env: WASP_VERSION: {pinnedLatestWaspVersion} SERVER_APP_NAME: myapp-server SERVER_APP_URL: https://api.myapp.com CLIENT_APP_NAME: myapp-client DOCKER_REGISTRY: ghcr.io DOCKER_REGISTRY_USERNAME: ${{ github.repository_owner }} DOCKER_REGISTRY_PASSWORD: ${{ secrets.GITHUB_TOKEN }} jobs: build-and-push-images: permissions: contents: read packages: write runs-on: ubuntu-latest # Remove this block if your app is NOT in an app folder defaults: run: working-directory: ./app steps: - name: Checkout repository uses: actions/checkoutv4 - name: Log in to Container registry uses: docker/login-actionv3 with: registry: ghcr.io username: ${{ env.DOCKER_REGISTRY_USERNAME }} password: ${{ env.DOCKER_REGISTRY_PASSWORD }} - name: (server) Extract metadata for Docker id: meta-server uses: docker/metadata-actionv5 with: images: ${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_REGISTRY_USERNAME }}/${{ env.SERVER_APP_NAME }} - name: (client) Extract metadata for Docker id: meta-client uses: docker/metadata-actionv5 with: images: ${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_REGISTRY_USERNAME }}/${{ env.CLIENT_APP_NAME }} - name: Setup Node.js uses: actions/setup-nodev6 with: node-version: {minimumNodeJsVersion} - name: Install Wasp shell: bash run: npm i -g wasp.sh/wasp-cli${{ env.WASP_VERSION }} - name: Install Wasp app dependencies run: wasp install - name: Build Wasp app run: wasp build - name: (client) Build run: REACT_APP_API_URL${{ env.SERVER_APP_URL }} npx vite build - name: (client) Prepare Dockerfile run: | cd ./.wasp/out/web-app echo FROM pierrezemb/gostatic Dockerfile echo CMD [\-fallback\, \200.html\, \-enable-logging\] Dockerfile echo COPY ./build /srv/http Dockerfile - name: (server) Build and push Docker image uses: docker/build-push-actionv6 with: # Remove app/ if your app is at the repo root context: ./app/.wasp/out file: ./app/.wasp/out/Dockerfile push: true tags: ${{ steps.meta-server.outputs.tags }} labels: ${{ steps.meta-server.outputs.labels }} - name: (client) Build and push Docker image uses: docker/build-push-actionv6 with: # Remove app/ if your app is at the repo root context: ./app/.wasp/out/web-app file: ./app/.wasp/out/web-app/Dockerfile push: true tags: ${{ steps.meta-client.outputs.tags }} labels: ${{ steps.meta-client.outputs.labels }} - name: (server) Deploy to Caprover uses: caprover/deploy-from-githubv1.1.2 with: server: ${{ secrets.CAPROVER_SERVER }} app: ${{ env.SERVER_APP_NAME }} token: ${{ secrets.SERVER_APP_TOKEN }} image: ${{ steps.meta-server.outputs.tags }} - name: (client) Deploy to Caprover uses: caprover/deploy-from-githubv1.1.2 with: server: ${{ secrets.CAPROVER_SERVER }} app: ${{ env.CLIENT_APP_NAME }} token: ${{ secrets.CLIENT_APP_TOKEN }} image: ${{ steps.meta-client.outputs.tags }}工作流逐段拆解WASP_VERSION请替换为当前固定的 Wasp CLI 版本号如0.24.x。CI 中执行npm i -g wasp.sh/wasp-cli${{ env.WASP_VERSION }}全局安装指定版本的 CLI避免构建结果因 CLI 版本漂移而不可复现node-version替换为 Wasp 要求的最低 Node.js 版本concurrency段group: deployment保证同一时间只有一个部署任务在跑cancel-in-progress: true允许新推送中断旧的进行中任务登录 GHCRdocker/login-actionv3使用 GitHub 自动提供的GITHUB_TOKEN完成认证工作流顶层已声明permissions: packages: write这是推包所必需的权限wasp install/wasp build分别安装依赖并生成.wasp/out完整构建产物。wasp build的产物结构见 CLI 文档生成代码存放在.wasp/out目录其中web-app是 Vite 客户端工程、server是服务端工程客户端构建REACT_APP_API_URL${{ env.SERVER_APP_URL }} npx vite build在构建时把服务端地址注入客户端代码REACT_APP_API_URL是 Wasp 客户端连接服务端所用的必填变量见 环境变量文档。这一步必须在wasp build之后、位于web-app目录内执行客户端 Dockerfilewasp build不会为客户端生成 Dockerfile所以工作流用三条echo命令现场拼装一个基于pierrezemb/gostatic的极简静态托管镜像通过-fallback 200.html实现 SPA 前端路由回退任何未知路径都返回200.html交给 React Router 处理并把build目录复制到镜像的/srv/http服务端镜像直接使用wasp build在.wasp/out/Dockerfile中生成的官方 Dockerfile 构建docker/build-push-actionv6负责构建并推送到 GHCR部署触发caprover/deploy-from-githubv1.1.2分别以各自的 app token 通知 Caprover 拉取服务端与客户端的新镜像并滚动更新。Wasp 生成的服务端 Dockerfile 原理服务端镜像的质量取决于 Wasp 生成器产出的 Dockerfile。在仓库中可找到该模板 waspc/data/Generator/templates/Dockerfile它采用标准的多阶段构建node/base阶段固定使用node:{版本}-alpine3.23基础镜像模板注释说明固定 alpine 小版本是为了避免本地与 GitHub CI 构建出不同的环境并安装openssl——Prisma 原生引擎在构建和运行时都需要 libsslserver-builder阶段安装编译工具链python3 build-base libtool autoconf automake用于 Apple Silicon 上编译原生依赖将.wasp/out/server、.wasp/out/sdk等拷贝进镜像并执行npm install、prisma generate与npm run bundle产出打包后的服务端 bundleserver-production阶段从 builder 阶段仅拷贝运行所需的node_modules、bundle 与 Prisma 文件设置NODE_ENVproductionEXPOSE ${PORT}最终以npm run start-production作为入口启动。也就是说你在 CI 里对.wasp/out目录执行的docker build其实是在构建一个已经过 Prisma 生成、依赖精简、生产就绪的 Node 服务镜像。这一环节无需手工编写 Dockerfilewasp build已经替你做好了。Step 6配置 GitHub Secrets在 GitHub 仓库的Settings Secrets and variables Actions中新增以下三个 SecretCAPROVER_SERVER你的 Caprover 控制面板地址例如https://captain.apps.mydomain.com。它是caprover/deploy-from-githubAction 连接 Caprover 的目标服务器。SERVER_APP_TOKEN与CLIENT_APP_TOKEN两个应用的部署令牌获取方式相同分别对myapp-server和myapp-client操作一次在 Caprover 中打开对应应用进入Deployment标签找到Method 1: Official CLI点击Enable App Token复制生成的 token分别保存为SERVER_APP_TOKEN与CLIENT_APP_TOKEN。这两个令牌是独立的分别控制服务端与客户端应用的部署权限即使泄露也只会影响单个应用便于按应用隔离与回收。Step 7部署与验证完成以上全部配置后向main分支推送代码GitHub Actions 将自动执行wasp installwasp build构建 Wasp 应用分别构建服务端与客户端的 Docker 镜像将两个镜像推送到 GitHub Container Registry通过 Caprover 部署 Action 将新镜像滚动部署到myapp-server与myapp-client。首次部署成功后建议按以下清单验证打开https://your-domain确认客户端页面正常加载且浏览器 Network 面板中的 API 请求指向https://api.your-domain在myapp-server的App Logs中检查服务端是否成功连接数据库、是否打印启动日志测试一个涉及认证的流程注册/登录验证JWT_SECRET与WASP_SERVER_URL是否正确——OAuth 回调失败通常是WASP_SERVER_URL配置错误所致若页面路由刷新后 404说明客户端镜像的-fallback 200.html参数缺失或 Dockerfile 未生效若浏览器报 CORS 错误确认WASP_WEB_CLIENT_URL与客户端实际访问域名完全一致含https://前缀Wasp 默认只允许来自该域的跨域请求多域场景可参考 CORS 多域名配置指南。常见问题排查现象可能原因与对策服务端启动失败检查DATABASE_URL、JWT_SECRET、PORT、WASP_WEB_CLIENT_URL、WASP_SERVER_URL五个必填变量是否都已设置详见 部署环境变量文档CI 构建报错确认WASP_VERSION与node-version两个占位符已替换为实际版本确认应用在app/子目录时保留了working-directory: ./app与路径前缀否则应移除镜像推不上去检查工作流permissions是否包含packages: writeGHCR 要求镜像名小写Caprover 拉不到镜像回到 Step 4 检查 Remote Registry 的凭据与 Image Prefix 是否正确客户端白屏/接口 404确认构建时REACT_APP_API_URL已注入可通过查看浏览器加载的 JS 中是否包含服务器地址验证部署成功但服务未更新检查两个应用的 App Token 是否都已启用并正确填入 Secrets与其他自托管方案的对比Caprover 并不是唯一选择Wasp 官方还提供了 Coolify 部署指南 与 VPS 手动部署指南。三者共享相同的 Wasp 构建产物与客户端静态托管 服务端容器模型区别主要在于触发方式本文的 Caprover 方案使用caprover/deploy-from-githubAction 直连部署Coolify 方案通过 Deploy Webhook 触发而纯 VPS 方案则需要自行处理 Nginx 反代、进程守护与镜像更新。如果你的团队已经熟悉 Caprover 的界面与 API token 体系本文方案是维护成本较低的一条路径。小结至此你已经拥有了一条完整的 Wasp → Caprover 生产部署流水线DNS 与 HTTPS 就绪、PostgreSQL 数据库就绪、服务端与客户端应用就绪、环境变量就绪、CI/CD 就绪。此后每次推送main分支代码都会经过构建、打包、推送、部署四步自动上线。配合 Wasp 的单命令本地开发体验这套方案可以让小团队以极低的运维成本长期运行自托管应用。文中涉及的所有仓库文档与源码均可在当前仓库中继续深入查阅构建命令细节见 CLI 文档环境变量全集见 环境变量文档服务端镜像模板见 waspc/data/Generator/templates/Dockerfile。【免费下载链接】waspThe batteries-included full-stack framework for the AI era. Develop JS/TS web apps (React, Node.js, and Prisma) using declarative code that abstracts away complex full-stack features like auth, background jobs, RPC, email sending, end-to-end type safety, single-command deployment, and more.项目地址: https://gitcode.com/GitHub_Trending/wa/wasp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表