OpenNext:在 AWS、Cloudflare 或 VPS 上自託管 Next.js,無需 Vercel
自 Next.js 9 版本以來,我一直在生產環境中運行它。在這段時間的大部分時間裡,Vercel 是顯而易見的選擇 — 部署、遺忘、繼續前進。但在 2024 年左右,發票開始看起來像汽車付款。當你的行銷網站託管費用超過實際的雲端基礎設施成本時,某些地方出了問題。這時我開始深入研究 OpenNext,在過去一年中將三個生產應用遷出 Vercel 後,我有了一些看法。
這不是一篇「Vercel 很差」的文章。Vercel 確實非常優秀。但它已經不是唯一的選擇了,對許多團隊來說,它不是正確的選擇。讓我為你詳細介紹我所學到的關於使用 OpenNext 自託管 Next.js 的一切 — 優點、缺點和令人驚訝的實惠成本。
目錄
- 什麼是 OpenNext 以及為什麼它存在
- 2025-2026 年自託管景觀
- 部署目標:使用 SST 的 AWS
- 部署目標:Cloudflare Workers
- 部署目標:使用 Docker 的 VPS
- 成本比較:Vercel vs 自託管
- 何時離開 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 秒。
我使用過的緩解措施:
- 預配置並發 — SST 的
warm參數保持實例溫暖。按 $0.0000041667 每 GB 秒計費,保持 5 個 1GB 函數實例溫暖的成本約為每月 $15。 - 更小的包 — 審核你的服務器端依賴項。我發現一個項目在服務器端導入
lodash,而我們只需要lodash/get。包從 68MB 下降到 31MB。 - 區域部署 — 除非你絕對需要,否則不要為 SSR 使用 Lambda@Edge。具有 CloudFront 緩存的單一區域 Lambda 適合 95% 的應用。

部署目標: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.js 或 Astro 構建,目標平台選擇顯著影響你的架構決策。
第 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 轉換
實際遷移時刻。我總是建議:
- 與 Vercel 並行部署到新基礎設施
- 使用預備域進行徹底測試
- 在前一天將 DNS TTL 降低到 60 秒
- 在低流量時段進行 DNS 轉換
- 將 Vercel 部署保持運行 48 小時作為備用
- 密切監視錯誤率、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 標籤再驗證和邊緣中間件。這是優雅的降級,而不是懸崖。