对静态 Astro 站来说,Firebase Hosting 是个便宜又稳的归宿:免费 SSL、全球 CDN,免费额度还允许商用。部署本身就两条命令,真正要花心思的全在 firebase.json 里——rewrite 和缓存头配对一次,以后基本再也不用碰。
一句话总结
- public 目录填
dist,“配置成单页应用(SPA)rewrite”那一项一定选 No。Astro 输出的是真实 HTML 路由,不是 SPA 外壳——接受 SPA rewrite 会让每个本该 404 的路径都返回 HTTP 200。 - 在
firebase.json里加三条缓存规则:/_astro/**哈希资源缓存一年且 immutable,图片和字体缓存 30 天,HTML 给短缓存。 astro.config.mjs里的site:必须配,否则 sitemap 和 canonical 标签都会失效。- Spark(免费)档给你 10 GB 存储、每天 360 MB 流量、自定义域名,以及自动签发的 SSL,全部免费——而且允许商用。
什么时候该选 Firebase Hosting
满足下面任意一条,Firebase Hosting 就合适:
- 想要可预测的账单,以及一个真能覆盖小站的免费额度。
- 已经在用 Firestore、Auth 或 Cloud Storage,想统一到一个控制台、一个 CLI。
- Astro 项目是静态输出(默认就是)——不需要服务端渲染。
- 能接受跑一条 CLI 部署命令(或把它接进 GitHub Action)。
如果你重度依赖 SSR、边缘中间件,或者想要开箱即用、带预览链接的零配置 Git 部署,那就选 Vercel 或 Cloudflare Pages。完整取舍见 Firebase 和 Vercel 怎么选。
计费档位与额度(截至 2026 年 6 月)
| Spark(免费) | Blaze(按量付费) | |
|---|---|---|
| 价格 | $0 | 按用量、按月结算 |
| Hosting 存储 | 10 GB | 10 GB 免费,超出约 $0.026/GB |
| 数据流量 | 每天 360 MB | 每天 360 MB 免费,超出约 $0.15/GB |
| 自定义域名 | 包含 | 包含 |
| 免费 SSL | 有(自动签发) | 有(自动签发) |
| 商用 | 允许 | 允许 |
几百页的内容站基本能一直待在免费的 Spark 额度里。只有当你需要其他付费 Firebase 产品(比如用 Cloud Functions 做 SSR),或者每天流量超过 360 MB 时,才需要升 Blaze。下手前去 Firebase 定价页 核对当前数字——这些是用量配额,不是固定套餐。
实操步骤
1. 装 CLI 并登录
框架感知(framework-aware)的 hosting 需要 Firebase CLI 12.1.0 或更高版本。
npm install -g firebase-tools
firebase --version # 应为 12.1.0 或更高
firebase login
2. 初始化 hosting——对 SPA rewrite 说 No
在 Astro 项目根目录跑。唯一关键的回答:问到是否配置成单页应用时,选 No。Astro 每个路由都出一个 HTML 文件,SPA rewrite 会把所有路径都指向 index.html——包括那些本该 404 的路径。
firebase init hosting
# ? What do you want to use as your public directory? dist
# ? Configure as a single-page app (rewrite all urls to /index.html)? No
# ? Set up automatic builds and deploys with GitHub? (自己选)
3. 写一份规避所有常见坑的 firebase.json
{
"hosting": {
"public": "dist",
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"cleanUrls": true,
"trailingSlash": true,
"headers": [
{
"source": "/_astro/**",
"headers": [
{ "key": "Cache-Control", "value": "public, max-age=31536000, immutable" }
]
},
{
"source": "**/*.@(jpg|jpeg|png|webp|avif|svg|woff2)",
"headers": [
{ "key": "Cache-Control", "value": "public, max-age=2592000" }
]
},
{
"source": "**/*.html",
"headers": [
{ "key": "Cache-Control", "value": "public, max-age=300, s-maxage=3600" }
]
}
]
}
}
每一行为什么值得留着:
cleanUrls: true去掉.html后缀,并把/about.html301 重定向到/about。trailingSlash: true让 Firebase 补上结尾斜杠,这必须和 Astro 配置里的trailingSlash: 'always'一致,否则访问者会被卡进重定向循环。/_astro/**是 Astro 带内容哈希的 JS 和 CSS。文件名每次构建都变,所以一年的immutable缓存很安全,还能让回访者秒开。- 图片和字体给 30 天(
max-age=2592000)。 - HTML 给短浏览器缓存(5 分钟)外加更长的共享 CDN 缓存(
s-maxage=3600),这样重新部署能很快被看到,同时 CDN 仍在分担流量。
4. 在 astro.config.mjs 里配 site:
sitemap 生成和 canonical URL 都读 site:。漏配的话,上线当天 sitemap 就是坏的。
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';
export default defineConfig({
site: 'https://yourdomain.com',
trailingSlash: 'always',
build: { format: 'directory' },
integrations: [sitemap()],
});
5. 构建并部署
npm run build
firebase deploy --only hosting
# Hosting URL: https://your-project.web.app
6. 接上自定义域名
进 Firebase Console 的 Hosting,点 Add custom domain,按 DNS 提示配置——通常是两条指向 Firebase IP 的 A 记录。DNS 生效后 SSL 会自动签发,一般 1-24 小时。证书还没显示已签发就别把生产 DNS 切过去,否则这段空档里访问者会撞上证书警告。
7. 在生产环境核对缓存头
curl -sI https://yourdomain.com/ | grep -i cache-control
# cache-control: public, max-age=300, s-maxage=3600
curl -sI https://yourdomain.com/_astro/index.abc123.css | grep -i cache-control
# cache-control: public, max-age=31536000, immutable
8. 确认 404 真的返回 404
故意访问一个不存在的 URL,比如 /this-does-not-exist/,看状态码。如果返回 HTTP 200 还渲染了首页,说明 SPA rewrite 还在起作用——回去把它从 firebase.json 删掉。Google 会把软 404 当成薄内容,所以这一步每次部署都值得做。
curl -sI https://yourdomain.com/this-does-not-exist/ | head -1
# HTTP/2 404
Firebase 如何解析一个请求(rewrite 优先级)
当你想要的 rewrite 悄悄没生效时,几乎都是优先级顺序的问题。Firebase Hosting 按固定顺序应用规则,而且在 redirects 或 rewrites 内部,只有第一条匹配的规则会生效:
- 保留的
/__/*命名空间(Firebase 内部) - 配置的
redirects - 精确匹配的静态内容(
dist/里真实存在的文件) - 配置的
rewrites - 你的自定义
404.html - 默认 404
实际要点:真实文件永远盖过 rewrite,每个块内部的规则顺序也很重要。如果一条 rewrite 被静态文件或更靠前的规则挡住了,参见 Firebase rewrite 没触发。
容易踩的坑
- 接受了默认的 SPA rewrite。 404 页面返回 200,Google 会把它们当薄页面收录。这是 Astro 部署到 Firebase 最常见的错误。
- 忘了配缓存头。 Firebase 默认缓存保守,回访时会重新下载那些根本没变的资源。
- DNS 切在 SSL 之前。 证书还没签发就把生产 DNS 指向 Firebase,访问者会一直看到安全警告,直到全网生效。
- 指望纯 Hosting 跑 SSR。 静态 Hosting 只 serve 文件。SSR 需要 Astro 的 Node adapter 加上 Cloud Function 或 Cloud Run 后端,而这要 Blaze 计划。接好的函数若返回「function not found」,通常是区域或函数名对不上,不是部署失败(Firebase function not found)。
- 漏配 astro.config.mjs 的
site:。 sitemap 和 canonical 标签都会失效。
常见问题
- Firebase Hosting 真的免费吗: 小站是免费的。Spark 计划包含 10 GB 存储、每天 360 MB 流量、自定义域名和自动签发的 SSL,全部免费,而且允许商用。超出额度后转到 Blaze,按量付费,对静态内容来说非常便宜(截至 2026 年 6 月,超出流量约 $0.15/GB)。
- 怎么在 Firebase 跑 Astro SSR: 加上 Astro 的 Node adapter,用 Cloud Function 或 Cloud Run 来 serve,这需要 Blaze 计划。大部分内容站和营销站用不上——静态输出更快也免费。
- 能从 GitHub 自动部署吗: 可以。跑
firebase init hosting:github生成一个 GitHub Action,推送时自动构建并部署,还能给 PR 创建预览频道。比手动部署更省心也更可靠。 - 部署翻车怎么回滚: Firebase 保留发布历史。用
firebase hosting:versions:list列出版本,用firebase hosting:versions:clone克隆好的那一版,再firebase deploy --only hosting。或者在 Console 的 Hosting 里悬停到上一个发布、点 Roll back。两种都是几秒钟的事。 - cleanUrls 和 trailingSlash 都要吗:
trailingSlash: true要和 Astro 里的trailingSlash: 'always'一起用,让两层保持一致。结尾斜杠设置不一致会导致重定向循环,或者产生重复 URL、分散你的 SEO 权重。