自主託管 - 在未設置 SMTP 的情況下重設密碼

嘿!

我在 GCP CloudRun 上運行 n8n,搭配 PostgreSQL。我們有幾個為不同需求服務的實例。
在其中一個實例上,第一位用戶註冊後成為了擁有者。他是這個實例上唯一的擁有者/管理員。他忘記了密碼,無法恢復,因為我們沒有配置 SMTP。

重設密碼最簡單的方法是什麼?

直接在資料庫中將角色變更為 global:admin 是否安全,然後註冊一個新的擁有者來生成重設密碼連結?

@rgrzesk,在等待回應期間,以下是一些可能對你有幫助的資源:

建議的資源

自動匹配你的問題。

文檔:

論壇:

@moosa@gusgvd@mechanizedgrowth — 你們之前幫助解決過類似的問題,能看一下嗎?

由 n8n 社區機器人自動建議。這是一個試點 — 請在此分享反饋

@rgrzesk

這是重設使用者的一種方式。
這不會刪除任何其他資料,例如工作流程或認證資訊。只會刪除使用者。

Hi @rgrzesk

既然你已經在 GCP 生態系中,你可以使用 Cloud Shell 直接連接到你的 Cloud SQL 實例,並手動更新密碼雜湊。這樣就不需要在本地執行 n8n 或管理加密密鑰。

  1. 從 Google Cloud Console 開啟 GCP Cloud Shell
  2. 使用下列指令連接到你的 Cloud SQL 實例
gcloud sql connect [YOUR_INSTANCE_NAME] --user=postgres
  1. 產生新的 bcrypt 雜湊。 由於 n8n 使用 bcrypt,你不能只輸入純文字密碼。你可以在 Cloud Shell 中使用這個 Python 單行指令來為你所需的密碼(例如 NewPassword123!)產生雜湊:
python3 -c 'import bcrypt; print(bcrypt.hashpw(b"NewPassword123!", bcrypt.gensalt()).decode())'

複製產生的字串(它以 $2b$... 開頭)。

  1. 執行 SQL 更新。 在 PostgreSQL 提示符中,執行下列指令。注意:user 是 PostgreSQL 中的保留關鍵字,所以它必須用雙引號包裹。
UPDATE "user" 
SET "password" = '[PASTE_YOUR_HASH_HERE]' 
WHERE "email" = '[OWNER_EMAIL_ADDRESS]';
  1. 驗證並退出
SELECT email FROM "user" WHERE email = '[OWNER_EMAIL_ADDRESS]';
\q
  1. 使用新密碼登入 n8n。

@rgrzesk 歡迎!

你的 global:admin 方案行不通——設置精靈受限於 settingsuserManagement.isInstanceOwnerSetUp = true,而不是 global:owner 列是否存在,所以降級所有者會導致你沒有所有者,仍然無法訪問 /setup。(global:admin 也是企業版許可的角色。)

既然你使用 Postgres,只需覆蓋該用戶的 bcrypt 哈希值。一列,不涉及其他內容,無需重新部署:

1. 生成哈希值(n8n 使用 bcryptjs,成本係數 10):

docker run --rm node:20-alpine sh -c \
  "npm i bcryptjs --silent --prefix /tmp >/dev/null 2>&1 && \
   node -e \"console.log(require('/tmp/node_modules/bcryptjs').hashSync('YourNewPass1',10))\""

使用符合 n8n 規則的密碼(8–64 個字符,1 個數字,1 個大寫字母),否則你稍後無法在 UI 中更改它。

2. 連接並更新:

UPDATE "user"
SET password = '$2b$10$...your hash...'
WHERE email = 'owner@yourdomain.com';

容易出錯的兩點:user 是 Postgres 中的保留字,必須用雙引號包圍,哈希值必須用單引號包圍,否則 bash 會展開 $2b/$10 並寫入垃圾數據。

如果該帳戶啟用了多因素認證,還要執行 SET "mfaEnabled" = false, "mfaSecret" = NULL, "mfaRecoveryCodes" = NULL

3. 從無痕窗口登錄——n8n 從密碼哈希值衍生出部分驗證 JWT,所以舊會話失效,過期的 cookie 會被拒絕。無需重啟容器。

在此情況下避免使用 n8n user-management:reset:你無法 docker exec 進入 Cloud Run,它會清除所有用戶帳戶並將實例返回到設置精靈。之後值得在 Cloud Run 服務上添加 SMTP 環境變數,以防止整個隊伍再次發生此情況。

我們這裡在 Railway 上使用自託管。為了解決問題,我直接在 Primary 和 Worker 服務中包含變數。之後我進行了部署,問題就解決了。

image

我曾試過(在我的測試實例上)將其他用戶從 global:owner 改為 global:admin,結果成功了。進入實例後,我又看到了 /setup 畫面。所以這個技巧效果不錯。
問題是 - 這樣安全嗎?這些角色是否也被保存/使用在其他地方?

那就是我計劃要做的一個穩固且長期的解決方案 :slight_smile: 目前我只是試著快速恢復實例,而不需要額外的部署。

你說得對,我的錯 — 較新版本的 n8n 是根據是否存在 global:owner 列來決定是否顯示 /setup,而不是我引用的設定金鑰。感謝你測試。

關於安全性:有三個不同的 role 欄位,它們是分開的東西。user.role 是實例角色(你修改的那個)。project_relation.roleshared_workflow/shared_credentials.role 處理專案成員資格和資源所有權 — 而且這些是以 projectId 而非 userId 作為金鑰。所以你做的任何事都不會改變誰擁有哪個工作流程或認證。那部分沒問題。

我會改變的一件事:使用 global:member 而不是 global:admin。Admin 是 Pro/Enterprise 帳戶類型,所以在 Community 上你把使用者放在實例無法授權的角色中 — UI 往往會將未授權的角色灰顯,所以你可能無法在沒有另一個資料庫寫入的情況下改回。Member 可以讓你看到同樣的設定畫面,而不會有任何問題。

所以:快照資料庫 → 將舊擁有者設定為 global:member → 註冊一個臨時擁有者 → 設定 → 使用者 → 複製舊帳戶的密碼重設連結(不需要 SMTP 也能運作)→ 重設 → 將角色改回 → 刪除臨時使用者。不要同時保留兩個 global:owner 列。

無論如何,值得在所有 Cloud Run 服務上設定 N8N_EMAIL_MODE=smtp — 由於每個實例只有一個擁有者,這個問題遲早會出現。

@rgrzesk
從 n8n 2.17.0 開始,實例擁有者可以從環境變數佈建,這樣可以重設密碼而完全不需要觸碰資料庫。在 Cloud Run 服務上設定這些變數,使用現有擁有者的電子郵件:

N8N_INSTANCE_OWNER_MANAGED_BY_ENV=true
N8N_INSTANCE_OWNER_EMAIL=owner@yourdomain.com
N8N_INSTANCE_OWNER_FIRST_NAME=Firstname
N8N_INSTANCE_OWNER_LAST_NAME=Lastname
N8N_INSTANCE_OWNER_PASSWORD_HASH=<bcrypt hash>

n8n 會在每次啟動時重新應用這些設定到現有的擁有者帳戶,所以修訂版本會在密碼已更改的狀態下啟動。當啟用這個標誌時,該使用者在 UI 中是唯讀的,他們的 API 寫入會被拒絕,所以一旦你進入系統,設定 N8N_INSTANCE_OWNER_MANAGED_BY_ENV=false,它套用的值會保留在原位,UI 就會再次解鎖。
它只需要一個修訂版本,但無需編輯角色,資料庫中也沒有任何東西需要復原,這就是可以跨其他實例擴展的地方。