5.5 从 localhost 到公网——Serverless 部署一次讲清

2 阅读18分钟

模块五:工程质量与生产部署 | 第05讲:从 localhost 到公网——Serverless 部署一次讲清

本讲定位:把 VibeNote 从 localhost:3000 推到可分享、可预览、可回滚的 Serverless 生产环境;以 Vercel 为主线,讲清 环境变量Preview自定义域名Serverless FunctionsEdge Runtime
技术栈:Next.js 14(App Router)、TypeScript、Drizzle、PostgreSQL(托管如 Neon)、Vercel。
延伸阅读课程内容/7.1reference/advanced/12-serverless-deploy-cicd.md


一、Serverless 不是「没有服务器」

Serverless 指你把操作系统、扩容、补丁、机器容量交给平台;你交付的是函数/应用包路由规则。对独立开发者,这意味着:

  • 按用量计费(注意免费额度陷阱)
  • 全球边缘缓存(CDN 内置)
  • 推送即部署(Git 集成)
flowchart TB
    subgraph Dev["开发者"]
        G[Git Push]
    end
    subgraph Vercel["Vercel 平台"]
        B[Build: pnpm install + build]
        D[Deploy 到边缘/区域]
        F[Serverless Function 运行时]
    end
    subgraph Data["数据层"]
        PG[(PostgreSQL Neon)]
    end
    G --> B --> D
    D --> F
    F --> PG

二、Vercel 部署逐步走(第一次上线)

2.1 前置条件

  • 代码已在 GitHub(或 GitLab/Bitbucket)
  • package.jsonbuild/start 脚本正确(Next 默认 next build
  • 使用 Node 版本与本地一致:在 package.json 增加:
{
  "engines": {
    "node": ">=20"
  }
}

或在 Vercel Project Settings 指定 Node 20/22。

2.2 连接仓库

  1. 登录 Vercel → New Project → Import Git Repository。
  2. Framework Preset 选 Next.js
  3. Root Directory 若项目在 monorepo 子目录需指定。
  4. Build Command / Output 通常自动识别。

2.3 环境变量(最容易翻车的环节)

在 Vercel → Settings → Environment Variables:

  • DATABASE_URL(Production / Preview / Development 三类可分别配置)
  • AUTH_SECRETNEXTAUTH_URL(若使用 Auth.js)
  • OPENAI_API_KEY(仅服务端使用)
  • 任何 NEXT_PUBLIC_*:记住它会进浏览器

关键认知.gitignore 阻止 .env 上传 Git → 平台不知道你的本地密钥 → 必须手工录入或使用 Vercel CLI 导入。

pnpm i -g vercel
vercel login
vercel link
vercel env pull .env.local

三、Preview Deployments:每个 PR 一条临时公网

价值

  • 产品/设计在合并前可点真实链接
  • E2E 可对 VERCEL_URL 跑冒烟(与第02讲联动)

实践

  • 在 PR 描述贴 Preview 链接
  • 对长耗时功能,Preview 环境降低 LOG_LEVEL 或关闭 AI 真调用(用 mock)
sequenceDiagram
    participant Dev as 开发者
    participant GH as GitHub
    participant V as Vercel
    participant Reviewer as Reviewer
    Dev->>GH: 打开 PR
    GH->>V: webhook 触发 build
    V-->>GH: Preview URL comment
    Reviewer->>V: 访问 Preview

四、自定义域名与 HTTPS

  1. 在 Vercel → Domains 添加 www.example.com / example.com
  2. 到 DNS 提供商添加 A/CNAME 记录(按 Vercel 提示)。
  3. 等待签发 TLS 证书(通常自动 ACME)。
  4. NEXTAUTH_URL / NEXT_PUBLIC_APP_URL 改为正式域名。

常见坑

  • 只配了 www 没配 apex(或反之)导致回调 URL 不一致。
  • DNS 缓存导致「明明改了却不生效」——用 dig/nslookup 验证。

五、Serverless Functions 与 Route Handlers

在 App Router 中,app/api/**/route.ts 默认在 Node.js Serverless 运行(具体以路由 segment runtime 配置为准)。

注意

  • 执行时间上限内存受平台约束;长任务应改 后台队列Edge 友好拆分
  • 冷启动:依赖体积越大,冷启动越慢;把重型 SDK 只放在需要的路由文件中。

5.1 显式选择运行时(示例)

// app/api/health/route.ts
export const runtime = "nodejs";

export async function GET() {
  return Response.json({ ok: true, ts: Date.now() });
}

5.2 Edge Runtime 适用场景

  • 低延迟鉴权、地理路由、轻量改写请求
  • 不能用 Node 专属 API(部分库不兼容)——Drizzle + pg 往往在 Node 更稳

对 VibeNote:数据库访问建议留在 Node Serverless;边缘层做 A/B、限流、简单重定向 即可。

flowchart LR
    subgraph Edge["Edge"]
        E1[轻量 middleware]
    end
    subgraph Node["Node Serverless"]
        A1["/api/notes"]
        A2["/api/ai/summarize"]
    end
    Edge --> Node

六、构建失败排障清单

症状可能原因处理
Node 版本报错平台默认过旧指定 engines / 项目设置
module not found依赖未写入 package.json修正 lockfile
构建通过运行崩环境变量缺失对照 Production/Preview
数据库连不上IP 白名单 / SSL 模式Neon 通常需 ?sslmode=require
Edge 引入 Node APIruntime 选错nodejs 或拆代码

七、与 Drizzle + Neon 的连接串示例(可运行配置片段)

.env.example(不含真实密码):

DATABASE_URL="postgresql://USER:PASS@HOST/DB?sslmode=require"
AUTH_SECRET="replace-with-openssl-rand-base64-32"
NEXTAUTH_URL="https://your-domain.com"
OPENAI_API_KEY="sk-..."

db/index.ts 确保仅在服务端导入,可用 import "server-only" 标记模块。


七点五、国内访问与双部署策略:延迟不等于「挂了」

Vercel 的默认边缘网络对海外用户体验极佳;若你的核心用户在中国大陆,可能遇到:

  • 首屏慢、偶发超时
  • Webfont/分析脚本加载慢

工程上可选项(按成本从低到高):

  1. 域名与 DNS 选国内解析更稳的线路;静态资源尽量小而少。
  2. 数据与模型:把数据库放在离用户近的 region;模型 API 选型考虑国内供应商。
  3. 第二部署平台:腾讯云 EdgeOne Pages、阿里云 ESA 等(参考 reference 12 对比表),把同一 Git 仓库接两条流水线——主用国内、海外镜像或反之。

关键原则:架构解耦(Drizzle + 标准 PG)让你保留迁移权,而不是被某一家平台锁死。


七点六、CI/CD 与 Vercel:推送即部署的心智

当你把 GitHub 与 Vercel 绑定后,持续部署天然成立:

  • main → Production
  • PR → Preview

这与 reference 中强调的「保存即发布」一致。你要补的两块通常是:

  1. GitHub Actions 跑测试(失败则阻止合并,而不是部署后再哭)
  2. 环境变量同步纪律:新变量上线必须同时更新 Vercel 三个环境

七点七、灰度发布:个人产品要不要?

大量用户才需要严格灰度;早期你可以用:

  • 按部署回滚代替复杂百分比灰度
  • 功能开关控制新功能可见性

理解灰度有助于你阅读大厂的发布笔记:「为什么我没有新功能」——你可能在较后的批次。


七点八、缓存三层:为什么你「改了代码用户看不到」

  1. 浏览器缓存:强刷或改文件名 hash。
  2. CDN 缓存:部署后旧 HTML 仍指向旧 JS。
  3. 服务端缓存(若你启用了 fetch cache 或 Route Segment Config):需要 revalidate 策略。

VibeNote 若在笔记列表用激进缓存,记得在创建/更新后做 tag revalidatemutate


七点九、成本与账单:免费额度的「甜蜜陷阱」

reference 12 提醒:免费额度适合验证,不适合长期生产。你要设置:

  • 模型供应商预算告警
  • Vercel/数据库账单阈值
  • AI 接口按用户限额(防刷)

否则一次密钥泄露 + 爬虫可以把「零成本项目」变成「信用卡惊喜」。


七点十、部署完成的定义:不是绿勾,是证据

上线完成的判据应是:

  • /api/health 200
  • 生产烟雾测试记录(截图或录屏)
  • Sentry 无异常飙升
  • 关键 E2E 在 Production URL 通过(或在 Preview 等价验证)

八、思考题

  1. 为什么 Preview 环境不应与 Production 共用同一数据库(默认情况下)?你会如何拆分?
  2. 把一个重 CPU 的 Markdown 渲染从 Edge 迁到 Node 的权衡是什么?
  3. NEXT_PUBLIC_* 与私有环境变量在构建时注入行为上有何差异?
  4. 如果你在国内用户为主,Vercel 访问慢,你会采用哪些架构层面的补救(不改写业务逻辑的前提下)?

九、本节小结

  • Serverless 让独立开发者跳过运维,但不跳过配置纪律
  • 环境变量是部署成败的分水岭
  • Preview 是移动 PR 评审台
  • 运行时选择是性能与兼容性的杠杆。

十、下讲预告

第06讲:VPS 部署与运维——Docker + Nginx + HTTPS 生产级方案
当你需要完全控制跑平台不支持的进程、或降低成本曲线,VPS + Docker 是另一条正路。下一讲将走 Ubuntu 初始化Docker ComposeNginx 反代Let’s Encrypt最小监控


课后动作:为 VibeNote 开一个 Preview PR,记录构建日志里实际 Node 版本构建耗时,把链接保存为团队知识库第一条「部署证据」。


补篇:Vercel 与数据库连接池

Serverless 高并发下数据库连接可能飙升;使用 Neon 等支持 serverless driver 的方案,或 pgbouncer,或限制函数并发。否则错误日志会出现 too many connections

补篇:Edge Config 与特性开关

可把简单开关放 Edge Config,做到快速降级 AI 功能而无需重新部署代码(按平台能力评估)。

补篇:ISR 与笔记列表

若你用增量静态化缓存列表页,记得在笔记变更时 revalidate,否则用户看到旧列表误以为同步失败。

补篇:Image Optimization

Next Image 默认优化外链需配置 domains/remotePatterns。笔记封面若来自对象存储,记得白名单。

补篇:Analytics 与隐私

接入分析脚本时同步更新 Cookie 提示与隐私政策。技术部署不仅是工程,也是合规。

补篇:多环境配置表

用表格维护 Dev/Preview/Prod 的变量差异:哪些 key 只在 prod,哪些用测试 key。避免「Preview 误打生产库」。

补篇:结语

部署的本质是把运行假设写下来:Node 版本、环境变量、运行时、区域——任何沉默假设都会在半夜变成报警。


精读延展:工程化的「慢变量」

工程化里真正改变命运的往往是慢变量:习惯、流程、清单、自动化。它们不像新功能那样在演示视频里闪闪发光,却决定你在第六个月还能不能持续交付。VibeNote 这类产品的竞争,表面是功能,底层是可靠性与迭代效率。把每一讲的知识点写成你可执行的规则文件,比收藏一百篇文章更有用。

精读延展:独立开发者的「风险预算」

你不可能同时买到所有保险,所以要明确风险预算:本周最不能承受的是数据泄露、服务不可用、还是成本失控?把预算花在对应加固上,其他的先记录为「已知风险」。这比假装自己什么都防住了更诚实,也更专业。

精读延展:从教程到产品的距离

教程代码默认跑在 happy path;产品代码默认会遇到蠢问题、坏网络、恶意输入与误操作。模块五的意义,就是把你从教程态推进到产品态:你会开始问「如果失败呢?」「如果被攻击呢?」「如果同事离职呢?」这些问题不浪漫,但决定你能不能靠作品吃饭。

精读延展:与用户的信任契约

用户把笔记交给你,是信任契约。契约内容包括可用性、隐私、透明度与纠错机制。工程措施是契约的底层支撑:备份、监控、安全响应、版本回滚。你可以把契约写得很短,但不能心里没有。

精读延展:把知识变成肌肉记忆

看完专栏不等于学会。请把本模块至少三条规则落实进仓库:例如 .env 纪律、一个 E2E、一个 requestId。肌肉记忆来自重复执行,而不是重复阅读。

精读延展:面向下一阶段的接口

当你完成模块五,你就为增长、商业化、协作功能留下了「干净的接口」:你不会在广告接入时才发现安全头拦了一切;也不会在招聘兼职时才发现没有测试与 PR 规范。提前支付成本,是在给未来打折。


终篇延展:构建缓存

Vercel 与 GitHub Actions 都支持缓存 node_modules 或 pnpm store;正确配置能显著缩短「等部署」的焦虑时间。

终篇延展:环境变量分组

把变量按「构建期」「运行期」「仅服务端」分组写在内部文档,减少新人误把运行期变量写进 build args。

终篇延展:Serverless 超时与 UX

若 AI 摘要可能超过平台限制,应在前端显示进度与可取消,而不是让用户面对 504 茫然。

终篇延展:Edge Middleware 日志

Middleware 日志字段要与 API 日志对齐 requestId,否则链路断裂。

终篇延展:回滚与数据库迁移

部署回滚不等于数据回滚;迁移要向前兼容或准备 down 脚本策略。独立产品至少做到「新代码能读旧 schema」。

终篇延展:收束

部署是把假设写下来;运行是把假设交给现实世界检验。

诵读延展 1

把专栏知识映射成仓库里的真实改动,才算完成学习闭环。把专栏知识映射成仓库里的真实改动,才算完成学习闭环。把专栏知识映射成仓库里的真实改动,才算完成学习闭环。把专栏知识映射成仓库里的真实改动,才算完成学习闭环。把专栏知识映射成仓库里的真实改动,才算完成学习闭环。把专栏知识映射成仓库里的真实改动,才算完成学习闭环。把专栏知识映射成仓库里的真实改动,才算完成学习闭环。把专栏知识映射成仓库里的真实改动,才算完成学习闭环。

诵读延展 2

独立开发最怕的是‘看过等于会了’;用 issue 与 commit 给自己留证据。独立开发最怕的是‘看过等于会了’;用 issue 与 commit 给自己留证据。独立开发最怕的是‘看过等于会了’;用 issue 与 commit 给自己留证据。独立开发最怕的是‘看过等于会了’;用 issue 与 commit 给自己留证据。独立开发最怕的是‘看过等于会了’;用 issue 与 commit 给自己留证据。独立开发最怕的是‘看过等于会了’;用 issue 与 commit 给自己留证据。独立开发最怕的是‘看过等于会了’;用 issue 与 commit 给自己留证据。独立开发最怕的是‘看过等于会了’;用 issue 与 commit 给自己留证据。

诵读延展 3

工程习惯是复利:第一周痛苦,第二个月麻木,第六个月碾压。工程习惯是复利:第一周痛苦,第二个月麻木,第六个月碾压。工程习惯是复利:第一周痛苦,第二个月麻木,第六个月碾压。工程习惯是复利:第一周痛苦,第二个月麻木,第六个月碾压。工程习惯是复利:第一周痛苦,第二个月麻木,第六个月碾压。工程习惯是复利:第一周痛苦,第二个月麻木,第六个月碾压。工程习惯是复利:第一周痛苦,第二个月麻木,第六个月碾压。工程习惯是复利:第一周痛苦,第二个月麻木,第六个月碾压。

诵读延展 4

别低估文档:未来的你是团队里最贵的合作者。别低估文档:未来的你是团队里最贵的合作者。别低估文档:未来的你是团队里最贵的合作者。别低估文档:未来的你是团队里最贵的合作者。别低估文档:未来的你是团队里最贵的合作者。别低估文档:未来的你是团队里最贵的合作者。别低估文档:未来的你是团队里最贵的合作者。别低估文档:未来的你是团队里最贵的合作者。

诵读延展 5

安全、测试、日志、协作、部署,是同一套‘可交付’语言的五种方言。安全、测试、日志、协作、部署,是同一套‘可交付’语言的五种方言。安全、测试、日志、协作、部署,是同一套‘可交付’语言的五种方言。安全、测试、日志、协作、部署,是同一套‘可交付’语言的五种方言。安全、测试、日志、协作、部署,是同一套‘可交付’语言的五种方言。安全、测试、日志、协作、部署,是同一套‘可交付’语言的五种方言。安全、测试、日志、协作、部署,是同一套‘可交付’语言的五种方言。安全、测试、日志、协作、部署,是同一套‘可交付’语言的五种方言。

诵读延展 6

当你能向非技术合作者解释清楚回滚路径,你的工程能力已经进阶。当你能向非技术合作者解释清楚回滚路径,你的工程能力已经进阶。当你能向非技术合作者解释清楚回滚路径,你的工程能力已经进阶。当你能向非技术合作者解释清楚回滚路径,你的工程能力已经进阶。当你能向非技术合作者解释清楚回滚路径,你的工程能力已经进阶。当你能向非技术合作者解释清楚回滚路径,你的工程能力已经进阶。当你能向非技术合作者解释清楚回滚路径,你的工程能力已经进阶。当你能向非技术合作者解释清楚回滚路径,你的工程能力已经进阶。

诵读延展 7

产品价值=功能×可靠性×迭代速度;模块五主要拉升后两项。产品价值=功能×可靠性×迭代速度;模块五主要拉升后两项。产品价值=功能×可靠性×迭代速度;模块五主要拉升后两项。产品价值=功能×可靠性×迭代速度;模块五主要拉升后两项。产品价值=功能×可靠性×迭代速度;模块五主要拉升后两项。产品价值=功能×可靠性×迭代速度;模块五主要拉升后两项。产品价值=功能×可靠性×迭代速度;模块五主要拉升后两项。产品价值=功能×可靠性×迭代速度;模块五主要拉升后两项。

诵读延展 8

遇到争议,用数据与日志说话,不要用音量说话。遇到争议,用数据与日志说话,不要用音量说话。遇到争议,用数据与日志说话,不要用音量说话。遇到争议,用数据与日志说话,不要用音量说话。遇到争议,用数据与日志说话,不要用音量说话。遇到争议,用数据与日志说话,不要用音量说话。遇到争议,用数据与日志说话,不要用音量说话。遇到争议,用数据与日志说话,不要用音量说话。

诵读延展 9

把‘临时方案’三个字从口头语里删掉,改成‘带截止日的技术债’。把‘临时方案’三个字从口头语里删掉,改成‘带截止日的技术债’。把‘临时方案’三个字从口头语里删掉,改成‘带截止日的技术债’。把‘临时方案’三个字从口头语里删掉,改成‘带截止日的技术债’。把‘临时方案’三个字从口头语里删掉,改成‘带截止日的技术债’。把‘临时方案’三个字从口头语里删掉,改成‘带截止日的技术债’。把‘临时方案’三个字从口头语里删掉,改成‘带截止日的技术债’。把‘临时方案’三个字从口头语里删掉,改成‘带截止日的技术债’。

诵读延展 10

VibeNote 是练手场,也是作品场:用同样标准要求自己。VibeNote 是练手场,也是作品场:用同样标准要求自己。VibeNote 是练手场,也是作品场:用同样标准要求自己。VibeNote 是练手场,也是作品场:用同样标准要求自己。VibeNote 是练手场,也是作品场:用同样标准要求自己。VibeNote 是练手场,也是作品场:用同样标准要求自己。VibeNote 是练手场,也是作品场:用同样标准要求自己。VibeNote 是练手场,也是作品场:用同样标准要求自己。

诵读延展 11

每一次线上事故,都是一次免费且昂贵的培训;写复盘才不浪费学费。每一次线上事故,都是一次免费且昂贵的培训;写复盘才不浪费学费。每一次线上事故,都是一次免费且昂贵的培训;写复盘才不浪费学费。每一次线上事故,都是一次免费且昂贵的培训;写复盘才不浪费学费。每一次线上事故,都是一次免费且昂贵的培训;写复盘才不浪费学费。每一次线上事故,都是一次免费且昂贵的培训;写复盘才不浪费学费。每一次线上事故,都是一次免费且昂贵的培训;写复盘才不浪费学费。每一次线上事故,都是一次免费且昂贵的培训;写复盘才不浪费学费。

诵读延展 12

别等‘有空再做测试’;测试是给你空出时间的机器。别等‘有空再做测试’;测试是给你空出时间的机器。别等‘有空再做测试’;测试是给你空出时间的机器。别等‘有空再做测试’;测试是给你空出时间的机器。别等‘有空再做测试’;测试是给你空出时间的机器。别等‘有空再做测试’;测试是给你空出时间的机器。别等‘有空再做测试’;测试是给你空出时间的机器。别等‘有空再做测试’;测试是给你空出时间的机器。

诵读延展 13

密钥、备份、监控,是独立产品的三件套,缺一则夜不能寐。密钥、备份、监控,是独立产品的三件套,缺一则夜不能寐。密钥、备份、监控,是独立产品的三件套,缺一则夜不能寐。密钥、备份、监控,是独立产品的三件套,缺一则夜不能寐。密钥、备份、监控,是独立产品的三件套,缺一则夜不能寐。密钥、备份、监控,是独立产品的三件套,缺一则夜不能寐。密钥、备份、监控,是独立产品的三件套,缺一则夜不能寐。密钥、备份、监控,是独立产品的三件套,缺一则夜不能寐。