↓ 快轉到主要內容

我自己做了一套零成本、可自架的匿名問答系統!完全免費、採用零伺服器架構

·3238 個字·7 分鐘·
目錄

為什麼要做這個?
#

相信各位在 Instagram 或其他社群上,常常會看到那種「匿名問答箱」(例如 NGL.link 或 Marshmallow-qa 等等) :丟一條連結給粉絲,大家匿名發送問題或想說的話,你再挑幾則貼到限時動態上回答。

用起來很方便,沒錯,我自己也用過。但資料都在第三方手上,他們怎麼存、怎麼用、會不會外洩,你完全無法掌控。

於是我就想:這種東西為什麼不能自己做?

而且我要的是——

  • 完全免費(不要為了解鎖什麼特殊留言功能而付月費)
  • 不用自己架伺服器(我不是伺服器管理員的,雖然管理員聽起來很酷)
  • 資料 100% 自己掌控
  • 能一鍵把留言變成好看的圖卡,直接貼 IG 限動
  • (且包含市面上常見的匿名問答系統有的功能)

這就是這個專案的起點:一個我自己做的、開源、可自主架設的匿名問答系統。

我這個自製的開源專案的 GitHub 頁面: AiixiBear/aqa_system

前端預覽

手機版前端預覽

特色一覽
#

  • 完全無須架設自己的伺服器,而且免費——靠 Cloudflare Worker 與 Google Sheet + Apps Script 就能跑起來,並且不需要輸入信用卡資訊即可直接使用
  • Cloudflare Turnstile 驗證防機器人
  • 收集 IP、User-Agent,並透過 ipinfo.io API 解析 IP 所在地(國家 / ASN)
  • 內建篩選後台,可直接查看留言、一鍵生成留言圖卡,貼上 Instagram 限時動態超方便
  • 每一則留言都有專屬辨識碼(例如 AQA-9487),粉絲可以在限動上認出自己的留言
  • URL 加上 ?tag= 就能標記留言來源,方便分流
  • 資料自己掌控,並且本專案使用 MIT License 開源,你各位想怎麼改就怎麼改

系統怎麼運作?
#

整個架構是 Serverless(無伺服器) 的,可以拆成兩條路徑:

  1. 公開留言路徑:使用者 → 前台網頁 → Cloudflare Worker(驗證 Turnstile)→ Google Apps Script(查 IP、發流水號)→ Google Sheets
  2. 後台管理路徑:管理者 → 後台網頁 → 後台 Google Apps Script → Google Sheets → 回傳 JSON → 渲染成留言卡片 → 匯出 PNG 圖卡

有人留言時:

  1. 使用者在前台輸入內容、通過 Turnstile 人機驗證
  2. Cloudflare Worker 檢查欄位、驗證 Turnstile Token
  3. 驗證通過後轉送到 Google Apps Script
  4. Apps Script 去 ipinfo.io 查 IP 國家與 ASN,用 Lock Service 配發唯一流水號(AQA-0001 這種),最後寫入 Google Sheets
  5. 前台顯示這則留言的專屬代碼,粉絲可以複製保存

管理者則是打開後台,用關鍵字、IP、tag、代碼篩選留言,點一下就能匯出成 PNG 圖卡,貼上 IG 限動。

後台的留言卡片支援一鍵下載圖片,圖卡裡不會包含下載按鈕,看起來就是乾乾淨淨的一張留言圖。

後台留言面板

後台可以顯示留言的來源 IP / 裝置資料

怎麼讓別人來留言?
#

很簡單,跟一般匿名問答箱一樣:把前台網頁的連結傳給粉絲或朋友就行了。

你也可以在網址後面加上 ?tag= 參數,例如:

https://example.com/?tag=ig-stories

這個 tag 會一起被記錄到留言資料裡,而且只有你(資料庫持有者)看得到,適合用來辨識留言是從哪個管道來的。

送出留言後,系統會配發一組獨一無二的流水號(像是 AQA-9487)。這組號碼會:

  • 一起存進 Google Sheets
  • 顯示在後台的留言卡片上

這樣粉絲在你的 IG 限動上看到圖卡時,一眼就能認出「啊!這是我留的那則欸!」。

架設前的準備
#

這個系統全部都使用免費服務,而且全都不需要輸入信用卡資訊即可直接使用:

  • Google 帳號:建立 Google Sheets 與部署 Google Apps Script
  • Cloudflare 帳號:部署 Worker 與建立 Turnstile Widget
  • IPinfo Lite API Token:查詢 IP 的國家 / 地區與 ASN(ipinfo.io/lite 註冊)
  • 靜態網頁空間:GitHub Pages、Cloudflare Pages 或任何能託管 HTML 的服務都可以

架設教學:公開留言系統
#

1. Google Sheets
#

  1. 到 Google Sheets 建立一個空白試算表
  2. 在第一列貼上表頭:
接收時間 (台北時間)	留言	來源IP	Tags	來源國家/地區	AS_Name	User-Agent	唯一辨識碼
  1. 記下試算表 URL 與 試算表名稱

Google Sheets 示範

2. 寫入用 Google Apps Script
#

  1. 打開 Google Apps Script 建立新專案
  2. 程式碼貼入專案裡的 gas/main.gs
  3. 到 ipinfo.io/lite 註冊,取得免費 API Token
  4. 在專案的 設定 → 指令碼屬性 填入:
屬性 值 說明
IPINFO_TOKEN 你的 ipinfo.io API Token 剛剛申請的
SHEET_NAME 試算表的名稱 剛剛記下的
SHEET_URL 試算表 URL 剛剛記下的
WRITE_KEY 自訂的隨機密鑰 一串夠長的亂數。Worker 與本專案共用,避免有人繞過 Worker 直灌資料
  1. 部署成網頁應用程式,記下部署後的 URL

GAS 設定示範

GAS 部署示範

關於 WRITE_KEY:這是寫入端的門禁。沒有這把鑰匙,就算知道 Apps Script 的網址也無法直接寫入留言。請自己生成一串夠長的亂數字串(例如 32 碼以上),並記好,稍後要填進 Worker。

3. Cloudflare Worker
#

  1. 註冊 Cloudflare,前往 運算 → Workers 和 Pages
  2. 建立應用程式,先部署 Hello World,記下 Worker 網址
  3. 按下編輯代碼,把專案裡的 worker/index.js 整份貼上取代
  4. 部署
  5. 去註冊一個 Cloudflare Turnstile 小工具,記下 Site Key 與 Secret Key
  6. 回到 Worker 的 設定 → 環境變數 (Runtime variables and secrets) 填入:
變數名稱 值
TURNSTILE_SECRET_KEY 你的 Turnstile Secret Key
APPS_SCRIPT_URL 剛剛寫入用 Apps Script 的 URL
APPS_SCRIPT_WRITE_KEY 剛剛在寫入用 GAS 設定的 WRITE_KEY,必須完全一致
  1. 再部署一次

Worker 示範

Worker 程式碼示範

4. 前台網頁
#

前台只有一個 HTML 檔:frontend/index.html,丟到任何靜態網頁空間都行。

打開檔案,替換這幾個變數:

名稱 值 說明
YOUR_ICON_URL_HERE 你的 Icon 預設大小 64x64
YOUR_WORKER_URL_HERE 你的 Worker URL
YOUR_TURNSTILE_SITE_KEY_HERE 你的 Turnstile Site Key

到這裡,公開留言系統與資料庫就完成了。

架設教學:留言查看面板(後台)
#

1. 後台 Google Apps Script
#

  1. 再開一個 Google Apps Script 專案
  2. 程式碼貼入 admin_panel_gas/main.gs
  3. 指令碼屬性填入:
屬性 值 說明
IPINFO_TOKEN 你的 ipinfo.io API Token 可選。若試算表的 IP 地理資料被清掉,可手動執行 repairOldData 補回來
SHEET_NAME 留言資料庫的試算表名稱
SHEET_URL 留言資料庫的試算表 URL
TIMEZONE 圖卡顯示的時區 不填預設 Asia/Taipei
READ_KEY 自訂的隨機密鑰 後台讀取留言時必須帶上,避免有人拿到後台 GAS 網址就 dump 全部留言與 IP

2. 後台網頁
#

檔案在 admin_panel/index.html,同樣丟到靜態網頁空間即可。

要替換的變數:

變數名稱 值 說明
YOUR_DATABASE_APPS_SCRIPT_URL 後台 GAS 的 URL
YOUR_READ_KEY_HERE 剛剛後台 GAS 的 READ_KEY 必須完全一致,否則會顯示「驗證失敗」
YOUR_CARD_IMAGE_URL_HERE 留言圖卡的背景圖 程式碼中有兩處,記得都換。1:1 圖片效果最好

後台目前已內建 READ_KEY 驗證(是 API 金鑰驗證,不是帳號密碼登入)。若還想再加一層保護,可以自行使用帶有隨機路徑的 URL,或靜態託管商的存取限制功能。

到這裡,後台就架設好了。

安全性我做了哪些事?
#

這種「自己架設的匿名留言」系統最怕兩件事:有人亂灌垃圾訊息,以及後台資料外洩等等。這個專案目前有這些防護:

  • Cloudflare Turnstile:公開留言前必須通過人機驗證
  • WRITE_KEY:寫入端 GAS 只接受帶有正確金鑰的請求,繞過 Worker 直接打 Apps Script 也寫不進去
  • READ_KEY:後台 GAS 讀取留言也要金鑰,保護 IP、User-Agent 等資料
  • Lock Service:配發流水號時使用 Google Apps Script 的互斥鎖,多人同時送出也不會撞號
  • 前端字數限制與冷卻時間:基本的濫用緩衝

當然,這仍然不是「企業級防護」。如果你要拿去做更大型的公開服務,建議再自己加 rate limit、WAF 之類的機制。但以個人使用、粉絲留言這種場景來說,已經比系統直接裸奔好非常多了。

常見問題與故障排除 (FAQ)
#

Q1. 自己測試時送出留言時顯示錯誤或「驗證失敗」,該怎麼辦?
#

請依序檢查以下幾點:

  1. WRITE_KEY 是否一致:請確認 Worker 的環境變數 APPS_SCRIPT_WRITE_KEY 與寫入用 GAS 的指令碼屬性 WRITE_KEY 是否完全相同(包含大小寫與英數拼寫)。
  2. Turnstile 金鑰是否配對:檢查前台 HTML 的 Site Key 與 Worker 環境變數的 TURNSTILE_SECRET_KEY 是否來自同一組 Cloudflare Turnstile 設定。
  3. GAS 部署權限:確認寫入用 GAS 部署時,「誰有權存取」是否有設定為 「所有人 (Anyone)」。

Q2. 打開後台面板抓不到留言資料?
#

  1. READ_KEY 是否一致:請確認後台 HTML 裡的 YOUR_READ_KEY_HERE 與後台 GAS 指令碼屬性的 READ_KEY 完全一致。
  2. 網址是否填錯:請確認後台 HTML 填入的是後台 GAS 的部署 URL,而不是寫入用 GAS 的 URL。

Q3. 免費配額真的夠用嗎?會不會突然要付費?
#

對個人與一般社群粉絲互動來說完全夠用!

  • Cloudflare Worker:免費版每日提供 100,000 次請求。
  • Google Apps Script:一般 Google 帳號每日提供 20,000 次 URL Fetch 呼叫與足夠的試算表寫入額度。

詳情可參考 本專案使用的相關平台定價配額文件

並且這些免費服務完全不需要輸入信用卡資訊試用,因此不會自動產生任何費用。即使超過額度,服務也只是暫時停止回應。

結語
#

我的這個專案把「匿名問答箱系統」從第三方手裡拿回來,全部建在免費、常見、可長期使用的服務上:

  • Cloudflare Worker
  • Google Sheets / Google Apps Script
  • Cloudflare Turnstile
  • 免費靜態網頁託管

不需要伺服器、不需要資料庫、不需要月費,資料自己存、圖卡自己生、想改程式就直接改(因為本專案採用 MIT 授權)。

還是要提醒一下:上面雖然有提到,Cloudflare Worker 有每天免費 10 萬次請求、Google Apps Script 有相關上限等等,不過對個人使用真的完完全全綽綽有餘。

如果你也想要一個自己的匿名留言箱,歡迎直接拿去用、去改、去亂搞。

有問題或想法,也歡迎到 GitHub 留 issue。

本專案使用的相關平台定價配額文件
#

Google Apps Script 服務設有的每日配額 文件

Cloudflare Workers 方案定價 文件

相關文章