全部文章

环境变量怎么放?从本地配置到密钥边界

分清公开配置与服务端密钥,避免把 API Key 一起打包进前端,或不小心提交到 GitHub。

环境变量让配置和代码分离,但它不是自动生效的保险箱。一个值是否保密,取决于它在哪里被读取、是否进入构建结果,以及最终发送给了谁。

这类教训在真实世界里反复上演:有人把模型服务的 API Key 直接写进前端代码并推送到公开仓库,几小时后账单多了几千美元——爬虫全天候扫描 GitHub 上的密钥,拿到就能用。更多时候泄漏没这么戏剧化:密钥躺在某个被遗忘的预览部署里,或者出现在报错截图中,安静地等着被发现。理解环境变量的边界,就是理解「什么能公开、什么打死也不能公开」。

先区分两类配置

公开配置可以被访客看到,例如站点名称、公开域名和前端可使用的公开标识。就算它出现在网页源代码里,也不会造成损失。

服务端密钥包括模型服务的 API Key、数据库密码、签名密钥等。这类信息只能在可信的服务端环境使用,不能发送给浏览器。一旦出现在前端代码、HTML 或网络请求里,就等于公开了。

在 Astro 中,PUBLIC_ 前缀表示允许在客户端使用。不要用它保存密钥。

# 可以公开的示例配置
PUBLIC_SITE_NAME=AICookCode

# 仅供具备服务端能力的应用使用,不应进入客户端
MODEL_API_KEY=replace_with_your_own_key

变量名没有 PUBLIC_ 也不意味着绝对不会泄漏。如果服务端把值写进 HTML、日志或 API 响应,访客依然可能读到它。前缀只是框架层面的约定,真正的边界在你的代码逻辑里:这个值最终会不会被送到浏览器?

不同框架的前缀规则大同小异,记住自己用的那一套即可:

框架 客户端可用的前缀 服务端专用
Astro PUBLIC_ 无前缀
Vite VITE_ 无前缀
Next.js NEXT_PUBLIC_ 无前缀
通用 Node 服务 — 全部视为服务端

规律很明显:凡是标记为「公开」的变量,构建工具会把它打包进前端代码;没有标记的,默认只在服务端可读。选错前缀,等于亲手把密钥送上门。

本地文件不要提交

在 .gitignore 中排除环境文件,同时允许提交仅包含占位值的示例:

.env
.env.*
!.env.example

.gitignore 只影响尚未跟踪的文件。已经被 Git 跟踪的文件不会因为新增规则而自动从历史消失——这是最常见的误解之一。

光有忽略规则还不够,协作者(或者三个月后的你)需要知道这个项目要配哪些变量。维护一份 .env.example,只放变量名和占位值:

# 复制为 .env 后填入真实值,不要提交真实值
PUBLIC_SITE_NAME=AICookCode
MODEL_API_KEY=your_key_here
DATABASE_URL=your_database_url_here

新成员 clone 仓库后,照着 example 复制一份、填上自己的值就能跑起来,既不用猜,也不会有人把真实密钥提交上来。

提交前检查暂存区:

git status
git diff --staged

密钥也可能出现在截图、调试输出、请求示例和错误日志里。检查时不要只盯着 .env。发 issue 贴报错信息之前,先搜一遍有没有把密钥粘进去;截图之前,先确认终端里没有打印出敏感值。

本地多环境也要分开

除了 .env,常见的做法是按环境拆分:

  • .env:本地开发默认值
  • .env.local:你个人的本地覆盖,不提交
  • .env.production:生产构建用的公开配置(注意:这里只能放公开值)

加载顺序一般是越具体的覆盖越通用的,具体以你用的框架文档为准。关键原则不变:任何名字里带密钥的文件都不进版本控制,生产环境的真实密钥只放在托管平台的设置里。

静态构建与服务端运行不同

静态站点在构建时生成文件,访客访问的是这些已经生成的 HTML、CSS 和 JavaScript。构建环境变量不会自动变成一个运行时服务端接口。

这句话值得展开:静态站点的「构建时」和「运行时」是两个完全不同的时刻。构建时你电脑上的环境变量可以参与生成页面,但一旦 HTML 生成完毕,访客拿到的就是死文件——之后再改环境变量,已经生成的页面不会有任何变化,必须重新构建。

如果你在静态页面里使用密钥生成内容,仍要检查最终产物是否包含密钥或不该公开的数据。一个简单的自查方法:构建完成后,在 dist 目录里搜索你的密钥片段,确认它没有出现在任何输出文件里。

本站只是静态博客,本身不需要模型密钥。未来如果要做 AI 工具,可以单独部署 API 服务,并在对应平台的服务端密钥设置中配置凭据。静态前端只负责调用你自己的 API,密钥永远不出服务端的门。

云端分别设置环境

正式环境和预览环境最好使用不同的凭据与额度。预览部署的访问范围可能不同,也更容易运行尚未验证的代码——用同一套密钥,等于把生产钥匙交给了实验环境。

在托管平台(Cloudflare Pages、Vercel、Netlify 等)设置变量后,根据平台要求重新部署。不要假设修改配置后,已经生成的静态文件会自动变化。大部分平台的流程是:改变量 → 触发重新部署 → 新构建读取新值。

在 CI 里使用密钥时,用平台提供的 Secrets 功能,而不是把密钥写进 workflow 文件:

# GitHub Actions 示例:密钥从 Secrets 读取,不会出现在日志和代码里
- name: Build
  env:
    MODEL_API_KEY: ${{ secrets.MODEL_API_KEY }}
  run: npm run build

构建日志只记录必要状态。不要通过打印全部环境变量来排查配置问题,可以只输出「配置是否存在」这样的布尔值。排查时多问一句:这个日志谁能看到?CI 日志、错误追踪平台的访问范围,往往比你想象的广。

发现泄漏时,先撤销密钥

如果密钥已经进入公开仓库,按这个顺序处理:

  1. 立刻撤销或轮换:在服务提供方的后台作废旧密钥、生成新密钥,并检查异常用量。这是第一步,而且越快越好。
  2. 更新所有使用方:本地 .env、云端环境设置、CI Secrets,全部换成新密钥并重新部署。
  3. 再处理仓库历史:从历史记录中清除密钥(参考 GitHub 的敏感数据移除文档)。注意重写共享仓库历史会影响协作者,应协调完成。

仅删除最新版本中的字符串,无法让已经复制出去的密钥失效。顺序不能反:先止血(撤销),再清创(清理历史)。很多人第一反应是删代码、改历史,结果旧密钥还在外面裸奔。

公开配置、构建配置、运行时密钥,三者各有位置。把这条边界想清楚,比记住某一种文件命名方式更有用。下次新建项目时,先花五分钟定好:哪些变量公开、密钥放哪里、example 文件长什么样——这五分钟能帮你避开未来最贵的那几堂课。

参考:Astro 环境变量 · GitHub 移除敏感数据

ABOUT THE AUTHOR

我是 AI 煮代码汤

记录 AI、编程和成长路上的日常折腾。这里会分享能直接上手的代码技巧、最近好玩的 AI 工具,也写一点技术之外的真实感受。希望你看完,不只是收藏一篇文章,而是真的多一个可以试试的办法。

KEEP IN TOUCH

继续保持连接.

如果这篇文章对你有帮助,可以用下面的方式继续关注。

RSS 订阅

按自己的节奏阅读更新

没有算法排序,用 RSS 获取新文章,不错过每一次实践更新。

微信公众号·AI 煮代码汤

扫码关注,获取 AI、编程和开发实践的最新分享。
微信公众号 AI 煮代码汤二维码
把这篇笔记分享给同样好奇的人。

搜索文章

输入关键词,发现一篇好文章。

AICookCode / 站内搜索