Wasp 应用部署到 Railway 完整指南:手动部署服务端、客户端与 PostgreSQL 数据库
【免费下载链接】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/cloud-providers/railway.md 为核心,讲解如何把 Wasp 全栈应用部署到 Railway 云平台:从创建 PostgreSQL 数据库、配置server/client两个服务、设置环境变量,到推送构建产物并完成更新重部署的完整闭环。读完本文,你将掌握基于 Railway CLI 的手动部署全流程,也能理解 Wasp 官方wasp deploy railway自动部署命令在底层替你做了什么,以及.wasp/out构建产物中Dockerfile、railway.json、Caddyfile各自的作用。
一、自动部署:优先使用 Wasp Deploy
Wasp 官方建议优先使用wasp deploy railway一行命令完成 Railway 上的部署:Wasp CLI 会自动完成客户端、服务端和数据库三个部分的部署,无需手动在控制台创建服务、配置变量。
完整的自动部署教程见 Wasp Deploy 部署到 Railway,本指南聚焦其背后的手动部署流程,帮助你理解自动部署在底层做了什么,也便于在自动部署不满足需求(例如需要自定义域名、自建 PostgreSQL 或精细控制构建方式)时手动完成部署。
二、手动部署前置条件
开始之前,请依次完成以下准备工作:
- 在项目根目录运行
wasp build,确保应用已构建成功。该命令会在项目内生成.wasp/out目录,其中包含服务端部署所需的Dockerfile与客户端静态构建产物(.wasp/out/web-app/build)。 - 注册一个 Railway 账号。
- 安装 Railway CLI 命令行工具。
- 在终端运行
railway login,浏览器会自动打开授权页面完成登录认证。
注意:
wasp build每次都会重新生成.wasp/out目录。如果里面保存了上一次部署遗留的自定义文件(如 Caddyfile 手改版本),重新构建前需要先备份。
三、创建 Railway 项目
登录后在 Railway 控制台按以下步骤创建项目:
- 打开 Railway 控制台,点击New Project,从下拉菜单中选择Deploy PostgreSQL,为应用创建一个托管的 PostgreSQL 数据库服务。
- 项目创建完成后,点击右上角的Create按钮,选择Empty Service创建一个空服务。
- 点击新建的服务,将服务名改为
server。 - 再创建一个空服务,命名为
client。 - 点击顶部的Deploy按钮应用这些变更。
此时项目中应有三个服务:PostgreSQL、server、client,分别对应数据库、Wasp 服务端和 Wasp 客户端。
四、部署应用
4.1 配置域名
server与client两个服务都需要公网域名,以便后续配置环境变量和访问应用:
- 进入
server实例的Settings标签页,点击Generate Domain。 - 端口填写
8080,然后点击Generate Domain生成域名。 - 在
client的Settings下执行同样的操作(端口同样填写8080)。 - 复制两个服务的域名,后续配置环境变量时会用到。
端口8080并非随意选择——查看 Wasp 部署包的 ports.ts 可以看到,serverAppPort与clientAppPort均定义为8080:
// Ports we decided to use for the server and client apps. // These are arbitrary values that are used internally by // Railway containers to run the apps. export const serverAppPort = 8080 as Port; export const clientAppPort = 8080 as Port;也就是说,Railway 容器内部以8080端口运行 Wasp 服务端与客户端静态服务,因此生成域名时必须指定8080才能让 Railway 的健康检查与流量转发命中正确的端口。
4.2 部署服务端
先部署服务端,操作步骤如下:
进入
.wasp/out构建产物目录:cd .wasp/out将当前目录链接到刚创建的 Railway 项目:
railway link当 CLI 提示选择服务时,选择
server。回到 Railway 控制台,为
server服务配置环境变量。点击server服务,进入Variables标签页,依次添加:变量名 值 说明 DATABASE_URL点击Variable reference并选择 DATABASE_URL自动填充PostgreSQL 数据库连接串,由 Railway 自动注入正确值 WASP_WEB_CLIENT_URLclient域名,例如https://client-production-XXXX.up.railway.app客户端地址,必须带 https://前缀WASP_SERVER_URLserver域名,例如https://server-production-XXXX.up.railway.app服务端地址,必须带 https://前缀JWT_SECRET至少 32 字符的随机字符串 用于签名认证 JWT 令牌的密钥 如果你的应用使用了 Wasp 支持的外部认证方式(如 Google、GitHub 登录),还需要额外设置这些认证方式要求的对应环境变量(如 OAuth Client ID / Client Secret 等),详见 外部认证环境变量提醒。
这四个变量正是自动部署命令
wasp deploy railway在setup阶段自动配置的内容。查看 setup.ts 可以看到,Wasp CLI 会读取 Railway 数据库中DATABASE_URL的变量引用,并自动写入JWT_SECRET、WASP_SERVER_URL、WASP_WEB_CLIENT_URL、DATABASE_URL四项:["--variables", `JWT_SECRET=${jwtSecret}`], ["--variables", `WASP_SERVER_URL=${serverUrl}`], ["--variables", `WASP_WEB_CLIENT_URL=${clientUrl}`], ["--variables", `DATABASE_URL=${databaseUrl}`],推送并部署服务端:
railway up --ci使用
--ci标志可以将日志输出限制为仅显示构建过程,避免终端被大量日志刷屏。Railway 会自动定位.wasp/out目录中的Dockerfile并据此构建、部署你的服务端。从源码层面看,server.ts 中的
deployServer通过getServerBuildArtefactsDir定位.wasp/out构建目录,然后调用deployServiceWithStreamingLogs完成部署;而 common.ts 中最终执行的 Railway CLI 命令等价于:railway up <部署目录> --service <服务名> --no-gitignore --path-as-root --ci其中
--no-gitignore确保构建产物(包括.env*之外的敏感文件)被完整打包,--path-as-root则解决 Railway CLI 的一个已知问题,将服务目录作为部署的根路径。
4.3 部署客户端
客户端是静态站点,需要在本地构建后用 Railpack 构建器上传,步骤如下:
在项目根目录,使用
server域名作为 API 地址构建生产版本:REACT_APP_API_URL=<url_to_wasp_backend> npx vite build构建产物输出到
.wasp/out/web-app/build。这个环境变量会被打进前端代码,作为所有 API 请求的基地址,因此必须填写可公网访问的server域名。在
.wasp/out/web-app/build目录下创建railway.json,显式指定构建器为 Railpack,避免 Railway 未来变更默认构建器时导致部署行为不一致:{ "$schema": "https://railway.com/railway.schema.json", "build": { "builder": "RAILPACK" } }在
.wasp/out/web-app/build目录下创建Caddyfile,覆盖 Railpack 的默认 Caddyfile,配置静态文件托管与 SPA 回退:{ admin off persist_config off auto_https off log { format json } servers { trusted_proxies static private_ranges } } :{$PORT:80} { log { format json } respond /health 200 # Security headers header { # Enable cross-site filter (XSS) and tell browsers to block detected attacks X-XSS-Protection "1; mode=block" # Prevent some browsers from MIME-sniffing a response away from the declared Content-Type X-Content-Type-Options "nosniff" # Keep referrer data off of HTTP connections Referrer-Policy "strict-origin-when-cross-origin" # Enable strict Content Security Policy Content-Security-Policy "default-src 'self'; img-src 'self' data: https: *; style-src 'self' 'unsafe-inline' https: *; script-src 'self' 'unsafe-inline' https: *; font-src 'self' data: https: *; connect-src 'self' https: *; media-src 'self' https: *; object-src 'none'; frame-src 'self' https: *;" # Remove Server header -Server } root * . # Handle static files file_server { hide .git hide .env* } # Compression with more formats encode { gzip zstd } # Try files with HTML extension and handle SPA routing # This is where we diverge from the Railpacks's original Caddyfile try_files {path} {path}/index.html /200.html handle_errors { rewrite * /{err.status_code}.html file_server } }这份 Caddyfile 在 Railpack 默认模板(面向纯静态站点)的基础上做了关键改动:
try_files {path} {path}/index.html /200.html这一行让预渲染(prerender)页面能够被正确返回,同时让未预渲染的路由回退到 SPA 外壳(200.html)。这正是 Wasp 的prerender特性(见 示例应用 main.wasp.ts 中route("RootRoute", "/", page(Main), { prerender: true }))在部署阶段得以生效的原因。此外该 Caddyfile 还开启了 gzip/zstd 压缩、JSON 格式访问日志、/health健康检查响应,以及一组安全响应头(XSS 过滤、MIME 嗅探防护、Referrer Policy、Content Security Policy 等),并隐藏.git与.env*文件。Wasp 的部署包会在自动部署时自动生成这两份文件。查看 client.ts 中的
addRailwayBuildConfig函数可以印证:function addRailwayBuildConfig(buildDir: string): void { fs.writeFileSync(path.join(buildDir, "railway.json"), railwayJsonContents); fs.writeFileSync(path.join(buildDir, "Caddyfile"), caddyfileContents); }Wasp 明确要求保持文档中的这两份配置与部署包源码同步——源码中注释标注了「更新这份 railway.json 时,务必同步更新部署包与部署文档」,因此你在文档中看到的配置与 client.ts 内嵌的模板完全一致。
将客户端构建目录链接到
client服务:cd .wasp/out/web-app/build railway link当 CLI 提示选择服务时,选择
client。部署客户端构建产物:
railway up --ci
完成以上步骤后,你的 Wasp 应用就部署完成了。回到 Railway 控制台,可以看到项目中包含三个服务:PostgreSQL、Server、Client。通过client服务的域名即可访问应用。
五、更新与重新部署
当代码更新后需要重新部署时,按以下顺序操作:
在项目根目录运行
wasp build重新构建应用。注意这会重建整个.wasp/out目录,之前手动放入该目录的文件(如果有)会被清空。进入
.wasp/out目录,重新部署服务端:cd .wasp/out railway up --ciRailway 会重新基于
.wasp/out中的 Dockerfile 构建镜像并滚动更新server服务。在项目根目录重新构建客户端:
REACT_APP_API_URL=<url_to_wasp_backend> npx vite build然后进入客户端构建目录部署:
cd .wasp/out/web-app/build railway up --ci由于
wasp build会重建构建目录,railway.json与Caddyfile需要重新创建(自动部署时由 Wasp CLI 代劳,手动部署则需要再次写入这两份文件)。
六、手动部署与自动部署的对应关系
将手动部署流程与 部署包源码 对比,可以清晰看到wasp deploy railway在底层执行的正是本指南中的手动步骤:
| 手动步骤 | 自动部署对应实现 |
|---|---|
railway login | CLI 调用 Railway CLI 完成认证 |
| 创建项目与 PostgreSQL | setup.ts 创建项目、数据库与server/client服务 |
配置DATABASE_URL、JWT_SECRET、WASP_SERVER_URL、WASP_WEB_CLIENT_URL | setup 阶段自动写入四个环境变量 |
wasp build+ 推送.wasp/out | server.ts 的deployServer定位.wasp/out并执行railway up --ci |
写入railway.json+Caddyfile | client.ts 的addRailwayBuildConfig自动生成 |
| 构建客户端并推送 | buildClient以server域名为REACT_APP_API_URL执行 Vite 构建后部署 |
理解这条对应关系后,无论你是想快速上线(使用wasp deploy railway),还是需要精细控制部署过程的每一步(参考本指南手动操作),都能在 Railway 上稳定运行你的 Wasp 全栈应用。
【免费下载链接】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),仅供参考