昨天結尾提到,今天要講 wrangler.toml 裡的 [vars] 跟用 wrangler secret put 設定的 secret,這兩者要怎麼分。line-notion-bot 的 wrangler.toml 其實很短:
name = "line-notion-bot"
main = "src/index.js"
compatibility_date = "2026-08-01"
[vars]
# 非機密設定放這裡。模型可自行替換成其他 OpenRouter 免費模型。
AI_MODELS = ["meta-llama/llama-4-maverick:free", "meta-llama/llama-4-scout:free", "openrouter/free"]
# 以下是機密,不要寫在這個檔案裡,用 wrangler secret put 設定:
# LINE_CHANNEL_SECRET
# LINE_CHANNEL_ACCESS_TOKEN
# OPENROUTER_API_KEY
# MISTRAL_API_KEY(選填,設定後 AI 分類優先打 Mistral,失敗才退回上面的 OpenRouter 陣列)
# NOTION_TOKEN
# NOTION_DATABASE_ID
[vars] 只放了一個 AI_MODELS,其餘全部走 secret。程式裡兩種存取方式完全一樣,都是 env.AI_MODELS、env.LINE_CHANNEL_SECRET 這樣讀,差別在 wrangler.toml 這個檔案會被 commit 進 git,vars 裡的值就等於公開在 GitHub 上;secret 是用 wrangler secret put NAME 個別上傳、加密存在 Cloudflare 那邊,連自己之後想看都看不到明文,只能覆蓋重設。
所以判斷該放哪邊,標準不是「這個值敏不敏感」,而是「這個值出現在公開的 git 歷史裡,會不會有資安風險」。AI_MODELS 不介意,甚至希望讀這個 repo 的人一眼就看到目前用哪幾個免費模型、上限是 3 個,改起來也方便,直接改 wrangler.toml 這行、git commit、wrangler deploy 就生效,不用敲指令、不用互動輸入。
真正不能見光的當然是 LINE_CHANNEL_SECRET、LINE_CHANNEL_ACCESS_TOKEN、OPENROUTER_API_KEY、MISTRAL_API_KEY、NOTION_TOKEN 這幾個,外流了就是任何人都能冒用我的帳號額度、甚至改我的 Notion 資料庫。但清單裡還有兩個嚴格來說不算「密碼」的東西也丟進了 secret:NOTION_DATABASE_ID 跟 OWNER_USER_ID。資料庫 ID 本身洩漏了頂多讓人知道我 Notion 裡哪個資料庫是這支 bot 在用,不像 token 那樣能直接拿去做壞事,但它一樣是「只跟我這個部署有關、換一個人跑就要換一個值」的資訊,沒有必要跟著程式碼一起公開,所以還是走 secret,跟 LINE_CHANNEL_SECRET 待遇一樣。
實際部署指令依序是這樣:
npm install -g wrangler
wrangler login
cd line-notion-bot
wrangler secret put LINE_CHANNEL_SECRET
wrangler secret put LINE_CHANNEL_ACCESS_TOKEN
wrangler secret put OPENROUTER_API_KEY
wrangler secret put MISTRAL_API_KEY # 選填
wrangler secret put JINA_API_KEY
wrangler secret put NOTION_TOKEN
wrangler secret put NOTION_DATABASE_ID
wrangler secret put OWNER_USER_ID
wrangler deploy
wrangler secret put 每敲一次,終端機會停下來要你貼值進去,貼完按 Enter 就上傳,跟打 git commit 沒有互動介面是完全不同的體驗——這也是為什麼 AI_MODELS 值得放 [vars]:一個要改就要重跑一輪互動指令,一個改完一行文字就能 deploy,常改的東西放前者,人生比較輕鬆。
OWNER_USER_ID 這個 secret 有個雞生蛋、蛋生雞的順序問題:它是用來限制「只有我自己傳訊息 bot 才會理」的白名單機制,但要拿到自己的 LINE userId,得先讓 bot 跑起來收到過一次訊息才查得到。所以第一次部署時它是空的,先把其他 secret 設完就 wrangler deploy,這時候的狀態是任何加這個官方帳號好友的人都能用(額度是我的、寫的是我的 Notion,不會想開著這個狀態太久)。部署完跑 wrangler tail,等畫面印出 Connected! 之後,拿手機傳一句話給 bot,log 就會印出:
userId: U開頭一串英數字
複製那串貼進 wrangler secret put OWNER_USER_ID,重新 wrangler deploy 一次,白名單才正式生效。這步驟寫在 handleEvents 裡:
console.log('userId:', event.source?.userId);
// 只服務你自己,避免任何加到好友的人都能用你的額度寫入你的 Notion
if (env.OWNER_USER_ID && event.source?.userId !== env.OWNER_USER_ID) {
continue;
}
env.OWNER_USER_ID && 這個判斷式也順手說明了它是選填:沒設定這個 secret,env.OWNER_USER_ID 是 undefined,整個條件式直接是 false,不會攔任何人;設定了才會真的比對 userId、擋掉不是自己的訊息。這個「選填 secret 沒設就形同關閉檢查」的寫法,之後講 MISTRAL_API_KEY、JINA_API_KEY 有沒有設定會走不同分支時還會再看到,是同一套思路。
還有一個容易漏掉的地方:這個專案的 .gitignore 裡有 .dev.vars。如果之後想用 wrangler dev 在本機測試、不想每次都對雲端敲 wrangler secret put,可以在專案根目錄建一個 .dev.vars 檔案填本機測試用的假值,wrangler dev 會自動讀取這個檔案當作 secret,而它從一開始就被排除在版控之外,不會不小心 commit 進去。
vars 跟 secret 的區分講完了,部署流程也走過一輪。明天回到 line-notion-bot 存筆記那條主線,講 Jina Reader 怎麼把任意網址轉成乾淨的內文,還有為什麼要把丟給 AI 的內容截斷在 6000 字。