自 Next.js 9 版本以來,我一直在生產環境中運行它。在這段時間的大部分時間裡,Vercel 是顯而易見的選擇 — 部署、遺忘、繼續前進。但在 2024 年左右,發票開始看起來像汽車付款。當你的行銷網站託管費用超過實際的雲端基礎設施成本時,某些地方出了問題。這時我開始深入研究 OpenNext,在過去一年中將三個生產應用遷出 Vercel 後,我有了一些看法。

這不是一篇「Vercel 很差」的文章。Vercel 確實非常優秀。但它已經不是唯一的選擇了,對許多團隊來說,它不是正確的選擇。讓我為你詳細介紹我所學到的關於使用 OpenNext 自託管 Next.js 的一切 — 優點、缺點和令人驚訝的實惠成本。

目錄

OpenNext: 在 AWS、Cloudflare 或 VPS 上自託管 Next.js,無需 Vercel

什麼是 OpenNext 以及為什麼它存在

Next.js 是為了在 Vercel 上運行而設計的。這不是陰謀 — 這是架構。像 ISR(增量靜態再生成)、中間件、圖像優化和服務器操作這樣的功能都內置了 Vercel 特定的實現。當你嘗試在隨機服務器上運行 next start 時,你只能獲得 Next.js 功能的一個子集。

OpenNext 是一個開源適配器,它獲取你的 Next.js 構建輸出並將其轉換為在其他平台上工作的部署包。它始於 SST 社區項目,專注於 AWS Lambda,但從 v3 版本(2025 年當前的主要版本)開始,它支持多個部署目標,包括 Cloudflare Workers、傳統 Node.js 服務器等。

以下是 OpenNext 實際處理的內容:

  • ISR 和再驗證 — Vercel 使用其內部基礎設施實現的基於標籤的再驗證系統?OpenNext 使用 AWS 上的 DynamoDB + SQS 或 Cloudflare 上的 KV 存儲來重新創建它。
  • 圖像優化 — Next.js 的 <Image> 元件依賴於優化 API。OpenNext 包含基於 Sharp 的優化器或路由到特定於平台的解決方案。
  • 中間件 — 在 Vercel 上在邊緣運行。OpenNext 將其映射到 CloudFront 函數、Cloudflare Workers 或在 VPS 上進程內運行。
  • 服務器操作 — 完整支持,通過適當的服務器函數路由。
  • 流式傳輸和部分預渲染 — OpenNext v3.x 中的支持已顯著成熟。

OpenNext 不是什麼

它不是託管平台。它不是 CDN。它是一個構建適配器 — Next.js 輸出和你的基礎設施之間的轉換層。你仍然需要在某個地方實際運行它。

2025-2026 年自託管景觀

自我首次開始研究此問題以來,生態系統已經爆炸式增長。以下是當前的情況:

平台 OpenNext 支持 成熟度 最適合
AWS(通過 SST) 一等公民 生產就緒 已在 AWS 上的團隊
Cloudflare Workers 官方適配器 穩定(某些邊界情況) 邊緣優先應用、成本優化
Docker/VPS 社區 + 官方 穩定 簡單部署、現有基礎設施
Kubernetes 社區 Helm 圖表 成熟中 企業、現有 K8s 叢集
Netlify 內置(自有適配器) 生產就緒 已投入 Netlify 的團隊
Google Cloud Run 社區 實驗性 GCP 商店

我個人經過實戰測試且可以保證的兩條路徑是通過 SST 的 AWS 和 VPS 上的 Docker。Cloudflare 是令人興奮的新來者,每月都在改進。

部署目標:使用 SST 的 AWS

這是黃金路徑。SST(Serverless Stack)內置了由 OpenNext 提供支持的 Next.js 支持,這是大多數工程工作投入的地方。

架構概述

當你通過 SST 在 AWS 上部署 Next.js 時,會創建以下內容:

  • CloudFront 分佈 — 你的 CDN,處理靜態資產和路由
  • Lambda 函數 — 服務器端渲染、API 路由、服務器操作
  • S3 桶 — 靜態資產、預渲染頁面、ISR 緩存
  • DynamoDB 表 — ISR 標籤映射以進行再驗證
  • SQS 隊列 — 非同步再驗證處理
  • CloudFront 函數或 Lambda@Edge — 中間件執行

聽起來很多。確實如此。但 SST 將所有這些抽象化為大約 20 行配置。

SST 配置

這是我的一個生產項目中的真實 sst.config.ts

/// <reference path="./.sst/platform/config.d.ts" />

export default $config({
  app(input) {
    return {
      name: "my-nextjs-app",
      removal: input.stage === "production" ? "retain" : "remove",
      home: "aws",
      providers: {
        aws: {
          region: "us-east-1",
        },
      },
    };
  },
  async run() {
    const site = new sst.aws.Nextjs("Site", {
      domain: {
        name: "myapp.com",
        dns: sst.aws.dns(),
      },
      warm: 5, // keep 5 Lambda instances warm
      memory: "1024 MB",
      environment: {
        DATABASE_URL: process.env.DATABASE_URL!,
        NEXT_PUBLIC_API_URL: "https://api.myapp.com",
      },
    });

    return {
      url: site.url,
    };
  },
});

然後部署:

npx sst deploy --stage production

首次部署需要 8-12 分鐘(CloudFront 分佈傳播)。後續部署需要 2-4 分鐘。

Lambda 考慮事項

基於 Lambda 的託管的最大問題是冷啟動。Next.js 服務器函數不是很小 — 根據你的依賴項,你預期 20-80MB 的包。冷啟動範圍從 800ms 到 3 秒。

我使用過的緩解措施:

  1. 預配置並發 — SST 的 warm 參數保持實例溫暖。按 $0.0000041667 每 GB 秒計費,保持 5 個 1GB 函數實例溫暖的成本約為每月 $15。
  2. 更小的包 — 審核你的服務器端依賴項。我發現一個項目在服務器端導入 lodash,而我們只需要 lodash/get。包從 68MB 下降到 31MB。
  3. 區域部署 — 除非你絕對需要,否則不要為 SSR 使用 Lambda@Edge。具有 CloudFront 緩存的單一區域 Lambda 適合 95% 的應用。

OpenNext: 在 AWS、Cloudflare 或 VPS 上自託管 Next.js,無需 Vercel - 架構

部署目標:Cloudflare Workers

Cloudflare 一直在做出認真的舉措。他們的 Workers 運行時現在支持足夠的 Node.js API,以至於 Next.js 可以在那裡實際運行,OpenNext Cloudflare 適配器已經變得相當穩定。

使用 OpenNext Cloudflare 設置

npm install @opennext/cloudflare

添加到你的 wrangler.toml

name = "my-nextjs-app"
main = ".open-next/worker.js"
compatibility_date = "2025-01-01"
compatibility_flags = ["nodejs_compat_v2"]

[assets]
directory = ".open-next/assets"
binding = "ASSETS"

[[kv_namespaces]]
binding = "NEXT_CACHE_KV"
id = "your-kv-namespace-id"

構建和部署:

npx @opennext/cloudflare build
npx wrangler deploy

Cloudflare 的權衡

優點:

  • 沒有冷啟動 — Workers 在全球范圍內以不到 5ms 的速度啟動
  • 默認全球邊緣 — 你的 SSR 在 300+ 個位置運行
  • 荒唐的定價 — 付費計劃上 1000 萬個請求每月 $5

缺點:

  • 內存限制 — 免費 128MB,付費 256MB。大型 Next.js 應用可能會達到此限制。
  • CPU 時間限制 — 付費計劃 30 秒。沉重的 SSR 頁面可能是個問題。
  • Node.js 兼容性差距 — 大多數情況下都有效,但如果你直接使用本機 Node 模塊(如 sharp),你將需要解決方法。Cloudflare Images 可以代替處理優化。
  • 某些 Next.js 功能不支持 — 截至 2025 年初,部分預渲染支持在 Cloudflare 上仍在實驗階段。

對於內容豐富的網站和營銷頁面,Cloudflare Workers 非常引人注目。對於具有複雜服務器端邏輯的 web 應用,我仍然傾向於 AWS 或 Docker。

部署目標:使用 Docker 的 VPS

有時你只想要一個服務器。沒有 Lambda 函數,沒有邊緣運行時,沒有 47 服務架構圖。一個運行你的代碼的盒子。我尊重這一點。

Dockerfile

這是我使用的生產 Dockerfile。它是多階段、優化的,並且實際有效:

# Stage 1: Dependencies
FROM node:20-alpine AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN corepack enable pnpm && pnpm install --frozen-lockfile

# Stage 2: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

ENV NEXT_TELEMETRY_DISABLED=1
ENV NODE_ENV=production

RUN corepack enable pnpm && pnpm build

# Stage 3: Production
FROM node:20-alpine AS runner
WORKDIR /app

ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"

CMD ["node", "server.js"]

重要的是,你需要在 next.config.js 中設置 output: 'standalone'

/** @type {import('next').NextConfig} */
const nextConfig = {
  output: 'standalone',
};

module.exports = nextConfig;

VPS 建議

我已在多個提供商上運行此設置:

提供商 規格 月費 備註
Hetzner CAX21 4 vCPU ARM, 8GB RAM €7.49(約 $8) 最佳價值,歐盟數據中心
DigitalOcean Droplet 2 vCPU, 4GB RAM $24 良好的美國覆蓋
Fly.io(機器) 2 vCPU, 4GB RAM ~$30 自動擴展,全球區域
Railway 基於使用量 $5-50 最簡單的設置,Vercel 般的開發體驗
AWS EC2 t4g.medium 2 vCPU, 4GB RAM ~$25 已在 AWS 上

對於簡單的 Docker 部署,Hetzner 的價值荒唐得好。我在 €7.49 的 Hetzner ARM 實例上運行一個 Next.js 應用,服務於 200 多萬+ 頁面瀏覽/月,位於 Cloudflare 的免費 CDN 層後面。服務器幾乎沒有費力。

使用 Docker/VPS 失去的東西

讓我們誠實地談論與 Vercel 或 SST 設置相比,VPS 上的 next start 不提供什麼:

  • ISR 再驗證是基本的 — 僅限文件系統緩存。沒有跨多個實例的分佈式緩存。如果你運行單個服務器,這很好。多服務器?你需要 Redis 或共享緩存層。
  • 沒有邊緣中間件 — 中間件在進程內運行,對大多數用例來說完全沒問題。
  • 圖像優化 — 通過 Sharp 有效,但你從單個源提供優化圖像。放在 Cloudflare 或 CDN 後面。
  • 沒有原子部署 — 你需要自己處理零停機部署(Docker Compose 帶健康檢查,或反向代理如 Caddy/Traefik)。

對於大多數應用程序,特別是我們通過 headless CMS 開發 工作完成的無頭 CMS 構建,單個 VPS 和 CDN 在前面完全足夠。

成本比較:Vercel vs 自託管

讓我們談論金錢。這基於運行 ~500 萬個請求/月的 Next.js 應用的真實賬單數據,具有 ISR、圖像優化和適度的服務器端渲染。

成本因素 Vercel Pro Vercel Enterprise AWS/SST Cloudflare Hetzner VPS
基礎平台 $20/用戶/月 自定義(~$3k+/月) $0 $5/月 €7.49/月
計算/請求 $150-400/月 包含 $40-80/月 $0-15/月 包含
帶寬(100GB) 包含 包含 $8.50(CloudFront) 包含 包含
圖像優化 $50-200/月 包含 $5-15/月(Lambda) $5/月(CF Images) 包含(Sharp)
ISR/緩存 包含 包含 $2-5/月(DynamoDB) $0-5/月(KV) $0
估計總計 $300-700/月 $3,000+/月 $55-110/月 $10-25/月 $8-15/月

那些 Vercel 數字不是假設的。我見過發票。按座位定價、函數執行超額和 Pro 層帶寬費用對 5+ 人的團隊來說快速增長。

AWS/SST 數字假設具有預配置並發的適度流量。Cloudflare 的定價確實很瘋狂 — 除非你做一些奇特的事情,否則很難在那裡花費真正的錢。

何時離開 Vercel

不要只是因為你能就離開。因為你應該就離開。這是我的框架:

留在 Vercel 上,如果:

  • 你的團隊很小(1-3 名開發者),開發者時間是你最昂貴的資源
  • 你在 Vercel 上的支出低於 $100/月
  • 沒有人喜歡基礎設施工作
  • 你正在快速迭代,需要每個 PR 的即時預覽
  • 你正在使用 Vercel 特定的功能,如 Analytics、Speed Insights 或 Vercel AI SDK 集成

離開 Vercel,如果:

  • 月費超過 $500 且在增長
  • 你需要特定區域的基礎設施以遵守合規性(GDPR、數據駐留)
  • 你已經運行重要的 AWS/GCP/Cloudflare 基礎設施
  • Serverless 的冷啟動對你的用例不可接受
  • 你需要不適合 Vercel 模型的自定義緩存策略
  • 你已達到 Vercel 的函數大小限制或執行時間限制

認真考慮離開,如果:

  • 你在 Vercel Enterprise 定價上,合同續期剛剛生效
  • 你的應用主要是靜態/ISR,而你支付動態 SSR 價格
  • 你想在同一基礎設施中運行你的前端和後端

遷移手冊

我已經做過三次了。這是我遵循的流程,通過痛苦的經驗進行了改進。

第 1 步:審核你的 Next.js 功能

在你開始做任何事情之前,請編製你實際使用的 Next.js 功能的目錄:

# Find middleware
find . -name "middleware.ts" -o -name "middleware.js"

# Find API routes
find ./app -name "route.ts" -o -name "route.js" | head -20

# Check for ISR
grep -r "revalidate" ./app --include="*.ts" --include="*.tsx" | head -20

# Check for server actions
grep -r "use server" ./app --include="*.ts" --include="*.tsx" | head -20

# Check next.config for special features
cat next.config.js

第 2 步:選擇你的目標

基於審核:

  • 重型 ISR + 中間件 + 圖像優化 → AWS/SST
  • 簡單 SSR + 內容網站 → Cloudflare 或 VPS
  • 已有 Docker/K8s 基礎設施 → VPS/Docker
  • 需要在週五完成 → Docker on Railway 或 Fly.io

如果你正在使用 Next.jsAstro 構建,目標平台選擇顯著影響你的架構決策。

第 3 步:設置 CI/CD

Vercel 的 CI/CD 確實很棒。你會想念它。使用 GitHub Actions 複製它:

# .github/workflows/deploy.yml
name: Deploy
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: pnpm/action-setup@v4
        with:
          version: 9

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'pnpm'

      - run: pnpm install --frozen-lockfile
      - run: pnpm build
      - run: pnpm test

      # For SST:
      - run: npx sst deploy --stage production
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

      # For Docker/VPS (alternative):
      # - run: docker build -t myapp .
      # - run: docker push registry.example.com/myapp:latest
      # - run: ssh deploy@server 'cd /app && docker compose pull && docker compose up -d'

第 4 步:預覽部署

這是人們最想念 Vercel 的一件事。對於 SST,使用階段:

# In your PR CI workflow
npx sst deploy --stage pr-${{ github.event.pull_request.number }}

對於 Docker,像 Coolify(自託管)或 Railway 這樣的工具很好地處理預覽部署。

第 5 步:DNS 轉換

實際遷移時刻。我總是建議:

  1. 與 Vercel 並行部署到新基礎設施
  2. 使用預備域進行徹底測試
  3. 在前一天將 DNS TTL 降低到 60 秒
  4. 在低流量時段進行 DNS 轉換
  5. 將 Vercel 部署保持運行 48 小時作為備用
  6. 密切監視錯誤率、TTFB 和 Core Web Vitals

第 6 步:拆除 Vercel

一旦你確信(至少給它一週),取消 Vercel 訂閱並刪除項目。不要留下殭屍項目積累費用。

常見陷阱及如何避免

環境變數消失。 Next.js 有 NEXT_PUBLIC_ 前綴的變數(在構建時捆綁)和僅限服務器的變數(在運行時可用)。在 Vercel 上,這種區別有些模糊。在自託管上,它很嚴格。確保所有 NEXT_PUBLIC_ 變數在 CI 中的構建時可用。

ISR 緩存未持續。 在 Docker 上,.next/cache 目錄需要在持久卷上。否則,每次容器重啟都會丟失你緩存的頁面:

# docker-compose.yml
services:
  web:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - next-cache:/app/.next/cache

volumes:
  next-cache:

Sharp 安裝失敗。 sharp 圖像優化庫需要特定於平台的二進制文件。在 Docker 中,確保你在與運行時相同的架構中安裝依賴項。上面的 Dockerfile 通過使用具有相同基礎映像的多階段構建來處理這個問題。

中間件行為差異。 Vercel 在其邊緣網路上運行中間件。在 AWS/SST 上,它作為 CloudFront 函數運行(限制為 10ms 執行,2MB 大小)。複雜的中間件可能需要移動到服務器函數。我必須重構認證中間件,因為這些限制。

缺少頭部和重寫。 如果你依賴 vercel.json 進行頭部、重定向或重寫,你需要將這些移動到 next.config.js 或你的 CDN/反向代理配置。

如果這一切感到不堪重負,那正是我們在 Social Animal 處理的基礎設施工作類型。查看我們的 定價聯繫我們 — 我們已經完成過足夠多次這些遷移,以至於有了精煉的流程。

常見問題

OpenNext 在 2025 年生產就緒嗎? 是的。OpenNext v3.x 為數千家公司運行生產工作負載。SST/AWS 路徑最經過實戰測試,Cloudflare 支持緊隨其後。我不會說 Google Cloud 或裸 Kubernetes 支持成熟,但 AWS 和 Cloudflare 是穩固的。

OpenNext 支持 Next.js App Router 和服務器元件嗎? 完整支持。App Router、服務器元件、服務器操作、流式傳輸和 Suspense 都有效。OpenNext 團隊密切跟蹤 Next.js 版本,儘管通常在主要 Next.js 版本之後有 1-3 週的滯後時間,OpenNext 才會趕上。

通過離開 Vercel,我實際上可以節省多少? 這在很大程度上取決於你的使用模式。對於運行中等流量應用的 5 名開發者的團隊,我見過團隊從 Vercel Pro 上的每月 $600-800 下降到 AWS/SST 上的 $30-80/月或 VPS 上的不到 $20/月。節省是真實的,但維護負擔也是如此。

我可以在沒有 Vercel 的情況下使用 ISR(增量靜態再生成)嗎? 絕對可以。在 AWS/SST 上,ISR 使用 DynamoDB 進行標籤緩存,SQS 進行非同步再驗證 — 它是完全功能性的,包括通過 revalidateTag()revalidatePath() 的按需再驗證。在 VPS 上,ISR 使用文件系統緩存工作,對單服務器部署很好。

Vercel 的預覽部署呢?我可以複製那些嗎? 你可以獲得 80% 的體驗。SST 支持基於階段的部署,因此每個 PR 可以獲得自己的堆棧。Coolify 和類似工具為基於 Docker 的設置提供預覽部署。你不會輕易複製的是 Vercel 的視覺評論系統和緊密的 GitHub 集成以進行部署狀態。大多數團隊發現權衡是可以接受的。

對於無頭 CMS 網站,我應該使用 OpenNext 配合 Cloudflare 還是 AWS? 對於內容豐富的無頭 CMS 網站(Sanity、Contentful、Storyblok),Cloudflare Workers 是一個很好的選擇。這些網站傾向於 ISR 繁重,相對輕的服務器端邏輯 — 完美適合 Cloudflare 的定價模型。我只會在 Cloudflare 還不支持的功能或已深入 AWS 生態系統時才使用 AWS。

自託管 Next.js 比自託管 Astro 或 Remix 更難嗎? 說實話?是的。Next.js 因 ISR、中間件、圖像優化和部分預渲染等功能具有任何框架中最複雜的構建輸出。Astro 和 Remix 有簡單得多的部署故事。如果你正在啟動一個新項目並且自託管是優先事項,請考慮 Astro — 託管它要簡單得多。但如果你已經在 Next.js 上,OpenNext 使遷移變得實用。

如果 OpenNext 停止維護會怎樣? OpenNext 由 SST 支持,並擁有一個活躍的社區,有主要的贊助商。也就是說,這是任何開源依賴項的合理關切。緩解措施是 Docker/獨立方法(next start)不需要 OpenNext 就可以工作 — 你只是失去更高級的功能,如 ISR 標籤再驗證和邊緣中間件。這是優雅的降級,而不是懸崖。