你已经有 build 好的静态站在 dist/ 里,想 10 分钟之内挂到正式 HTTPS 域名、配好自定义域名,又不想把 Firebase 文档从头读一遍。这篇就按顺序带你跑完,顺便点名 firebase init 里那两个答错就会毁掉站点的问题,以及 macOS 上一个让 firebase serve 看起来”坏了”其实没坏的小坑。
一句话总结
- Firebase Hosting 的 Spark 免费档给你 10 GB 存储、每天 360 MB 流量、自动续期的免费 SSL、全球 CDN,以及自定义域名——而且允许商用、不用绑卡。(firebase.google.com/pricing)
- 命令序列就这么几条:
npm install -g firebase-tools→firebase login→firebase init hosting→firebase deploy --only hosting。 - 两个关键答案:public 目录填 build 产物(是
dist,不是项目根目录);多页站或 Astro / Hugo 站,“是否单页应用”一律选 No。 - macOS 上,hosting 模拟器默认的 5000 端口和 AirPlay 接收器冲突。用
firebase serve --only hosting --port 5050,或者把 AirPlay 接收器关掉。
Firebase Hosting 免费档到底白给什么
Firebase Hosting 是把静态站送上公网、自动配 SSL、走 CDN 的最快方式之一。和 Vercel Hobby 档(免费但只能非商用)不同,Firebase Spark 档允许商用——如果你的站要挂广告、放联盟链接,或者本身就是个产品,这点很重要。
截至 2026 年 6 月,免费档实际覆盖范围和升级门槛如下:
| 资源 | Spark(免费) | Blaze 超量计费 |
|---|---|---|
| 站点存储 | 10 GB | $0.026 / GB |
| 数据流量 | 每天 360 MB | $0.15 / GB |
| 自定义域名 | 包含,免费 SSL | 同左 |
| 一个项目多个 site | 支持 | 同左 |
| 是否需要绑卡 | 否 | 是 |
来源:Firebase 定价。一个普通内容站或营销站,流量基本都在每天 360 MB 以内——在没有 CDN 缓存的极端情况下,这个上限大约相当于每天 12,000 次访问一个 30 KB 的 HTML 页面。真用超了,Blaze 档保留同样的免费额度,只对超出部分计费,所以升级是个计费开关,不是搬家。
开始前准备
- 一个能打开 Firebase 控制台的 Google 账号。
- 一个能本地 build 的静态站项目(Astro / Vite / Hugo / Eleventy / 纯 HTML)。
- Node.js 18 或更高——
firebase-toolsv13+ 已经不再支持 Node 16。跑node -v、npm -v确认都能正常输出版本。 - 你清楚自己的 build 命令和输出目录,通常是
npm run build产出dist/。 - 可选但推荐:自己能改 DNS 记录的域名。
实操步骤
- **先创建 Firebase 项目。**打开 Firebase 控制台,点 “Add project”,填项目名,Google Analytics 按需开关(静态站一般可以跳过),完成创建。跳过这步是后面
firebase init显示项目列表为空的头号原因。 - **启用 Hosting。**进入新项目,打开 Build > Hosting,点 “Get started”。它展示的 quickstart 命令你不用照抄,点一遍只是确认 Hosting 已对这个项目开启。
- **本地 build 一次。**在项目里跑
npm run build,确认输出目录存在且里面有真实 HTML——Astro / Vite 通常是dist/index.html,Create React App 等少数工具是build/index.html。 - **安装并登录 CLI。**跑
npm install -g firebase-tools,再firebase login。如果你有多个 Google 账号,登录后跑firebase login:list,确认当前账号就是拥有该项目的账号——用错账号部署是个很常见、又不报错的坑。 - **把 repo 关联到项目。**运行
firebase init hosting,选 “Use an existing project”,选刚创建的项目,public 目录填 build 产物(dist/build/out)。除非今天就要接 CI,否则 GitHub 自动部署选 “No”。 - **认真回答单页应用那一题。**Astro、Hugo、Eleventy 以及任何多页静态站都选 “No”;只有那种所有路由都要交给
/index.html的客户端路由应用(React Router、Vue Router)才选 “Yes”。误选 “Yes” 会把所有 URL rewrite 到首页,多页站的 SEO 就这么悄无声息地废了。 - 检查生成文件。
.firebaserc里应该是你的 Firebase project ID,firebase.json里的hosting.public应该指向第 3 步确认过的 build 目录。 - 加上生产可用配置(完整配置见下文):
cleanUrls: true去掉 URL 后缀;HTML 用no-cache,让用户每次部署后都拿到新页;带 hash 的静态资源用一年期 immutable 长缓存。 - **用 Firebase 预览,不要只看框架 dev server。**跑
firebase serve --only hosting(或firebase emulators:start --only hosting)。macOS 上默认的 5000 端口会和 AirPlay 接收器撞——如果看到Port 5000 is not open或者空白页,加--port 5050,或者到”系统设置 > 通用 > 隔空投送与接力”里关掉 AirPlay 接收器。测试/、一篇文章页、/404、/sitemap.xml、/robots.txt。 - **正式部署。**再跑一次
npm run build,然后firebase deploy --only hosting。打开命令输出里的https://PROJECT_ID.web.app(Firebase 同样会在PROJECT_ID.firebaseapp.com提供相同内容),按刚才测过的路径再点一遍。 - **绑定自定义域名。**到 Firebase 控制台 > Hosting > Add custom domain,先加 TXT 验证记录,再按 Firebase 给的值添加 A 或 CNAME 记录。
- **等待 DNS 和 SSL。**多数域名几分钟就能连上;先给它几个小时,别同时去动其它 DNS。测试 apex 和
www,以及自动的http://→https://跳转。 - **收尾上线。**更新 canonical URL 和 sitemap base URL,到 Google Search Console 提交 sitemap,并记录 project ID、部署命令、public 目录和 DNS 记录。
参考 firebase.json
适合 Astro / Vite / Hugo 静态站的生产可用配置:
{
"hosting": {
"public": "dist",
"cleanUrls": true,
"trailingSlash": false,
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"headers": [
{
"source": "**/*.@(js|css|woff2|svg|webp|png|jpg)",
"headers": [{ "key": "Cache-Control", "value": "public,max-age=31536000,immutable" }]
},
{
"source": "**/*.html",
"headers": [{ "key": "Cache-Control", "value": "no-cache" }]
}
]
}
}
这两条缓存规则为什么重要:带 hash 的静态资源(比如 app.4f1c.js)在同一个文件名下内容永不变,所以一年期 immutable 长缓存既安全又快。HTML 文件跨版本部署文件名不变,所以用 no-cache 强制浏览器每次回源校验,拿到你的新 build,而不是继续吐旧页面。
会反复用到的命令:
npm run build # 产出 dist/
firebase serve --only hosting --port 5050 # 本地预览(5050 绕开 macOS 的 5000 端口)
firebase deploy --only hosting # 推到线上
firebase hosting:channel:deploy preview --expires 7d # 拉一个会过期的预览链接
firebase hosting:sites:list # 确认部署到了哪个 site
上线后验证
- 用无痕窗口打开
*.web.app和自定义域名,测试首页、深层文章 URL、404、sitemap、robots、移动端布局。 - 跑
firebase hosting:sites:list,确认部署到了目标项目——管理多个 Firebase 项目时这步很关键。 - 在 Firebase 控制台 Hosting > Release history 里确认最新 release 时间和你刚部署的时间一致。
- DNS 稳定后,用 Search Console 的 URL Inspection 检查 Google 能抓到页面,并且 canonical 是你预期的域名。
容易踩的坑
- 还没创建项目就直接
firebase init,结果项目列表是空的。 - 用错 Google 账号部署,把正式站推到了个人测试项目。
public配成了源码目录而不是 build 产物——站能开但是空白页。- 误选”单页应用 = Yes”,所有 URL rewrite 到
/index.html,多页站 SEO 直接废。 - HTML 忘了配
no-cache,部署后用户一直看到旧页。 - 撞上 macOS 的 5000 端口 AirPlay 冲突,误以为模拟器坏了。
- 工作目录脏的时候直接 deploy,没看清传了什么上去。
这篇适合谁,谁该跳过
适合所有想把静态站(Astro、Vite、Hugo、纯 HTML)配上 HTTPS、CDN、自定义域名,又想用免费且允许商用的免费档的人。
如果你的应用需要每次请求都 SSR、需要实时 websocket,或者要按地域路由,就别用 Firebase Hosting——这些应该走框架原生平台,或者走 Firebase App Hosting(这是另一个产品,firebase init 时如果检测到 Next.js 或 Angular SSR,CLI 会主动建议)。
FAQ
- 部署要花钱吗?:不要。Spark 免费档覆盖部署、
*.web.app域名、自定义域名和 SSL,不用绑卡,也没有非商用限制。免费额度是 10 GB 存储、每天 360 MB 流量。 - 自定义域名多久能用?:设好 DNS 后一般 15 分钟到几小时,SSL 同步签发并自动续期。
- 部署错了能回滚吗?:能。Firebase 控制台 Hosting > Release history > 选历史版本 > Rollback,一键即时生效。
- 为什么我 Mac 上
firebase serve是空白页或者报 “port 5000 not open”?:macOS 的 AirPlay 接收器占用了 5000 端口。跑firebase serve --only hosting --port 5050,或者到”系统设置 > 通用 > 隔空投送与接力”里关掉 AirPlay 接收器。 - 环境变量放哪?:静态站的环境变量在 build 时打进去,放 build 流程里(或
.env),不是firebase.json——firebase.json只管文件怎么被服务出去。 - preview 分支怎么搞?:跑
firebase hosting:channel:deploy NAME得到一个会自动过期的临时预览 URL(默认 7 天,可用--expires调整)。