背景 链接到标题
NetBird 自托管控制平面使用内置 Dex 作为 OIDC Provider。管理员账号在首次部署时通过 config.yaml 的 owner 字段创建,密码以 bcrypt 哈希存储。
长时间没有登录 Dashboard,密码遗忘了。Dashboard 没有提供密码重置功能,需要直接操作数据库恢复。
架构 链接到标题
NetBird 的认证数据分两处存放:
| 位置 | 文件 | 作用 |
|---|---|---|
| 配置 | config.yaml |
server 启动时读取 owner.password,同步到数据库 |
| 数据库 | Docker volume idp.db |
Dex 运行时读写的 password 表 |
Dex 的 password 表结构:
email - 登录邮箱
hash - bcrypt(password)
username - 用户名
user_id - UUID
直接改数据库?不行 链接到标题
第一个尝试是直接用 Python 更新 idp.db 的 password 表:
import sqlite3, bcrypt
conn = sqlite3.connect("idp.db")
h = bcrypt.hashpw(b"new_password", bcrypt.gensalt())
conn.execute("UPDATE password SET hash = ? WHERE email = ?",
(h.decode(), "admin@example.com"))
conn.commit()
验证 bcrypt 哈希正确,但 Dashboard 登录一直提示 Invalid credentials。更糟的是,重启容器后密码被还原。
config.yaml 优先级 链接到标题
NetBird server 启动时会读取 config.yaml 的 owner.password,与 idp.db 比对后同步写入。如果两者哈希不一致,config.yaml 的会覆盖数据库。
这意味着必须同时更新两处,且哈希值必须一致。
正确流程 链接到标题
1. 生成 bcrypt 哈希 链接到标题
python3 -c "import bcrypt; print(bcrypt.hashpw(b'your_password', bcrypt.gensalt()).decode())"
输出类似:
$2b$12$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
2. 更新 config.yaml 链接到标题
sudo sed -i 's|password: $2b$12$.*|password: $2b$12$你的新哈希|' /path/to/config.yaml
3. 更新 idp.db 链接到标题
可以直接在容器内执行,也可以从宿主机操作 volume:
# 容器内直接操作
sudo docker exec netbird-server python3 -c "
import sqlite3, bcrypt
conn = sqlite3.connect('/var/lib/netbird/idp.db')
h = bcrypt.hashpw(b'your_password', bcrypt.gensalt()).decode()
conn.execute('UPDATE password SET hash = ? WHERE email = ?',
(h, 'admin@example.com'))
conn.commit()
"
# 或从宿主机操作 Docker volume
sudo python3 -c "
import sqlite3
conn = sqlite3.connect('/var/lib/docker/volumes/netbird_netbird-management/_data/idp.db')
conn.execute('UPDATE password SET hash = ? WHERE email = ?',
('$2b$12$你的新哈希', 'admin@example.com'))
conn.commit()
"
两个操作的 bcrypt 哈希必须相同。
4. 重启容器 链接到标题
sudo docker restart netbird-server netbird-dashboard
5. 验证 链接到标题
打开 Dashboard 登录,或在终端使用设备码流程确认:
# 请求设备码
curl -s -X POST "https://your-domain/oauth2/device/code" \
-d "client_id=netbird-cli&scope=openid profile email"
# 用户访问 verification_uri 输入 user_code 完成授权
原理总结 链接到标题
config.yaml (owner.password) ──启动覆盖──▶ idp.db (password.hash)
│
Dex 认证时读取
│
用户登录验证
每次容器重启,server 都会将 config.yaml 的哈希同步到 idp.db。所以只改数据库没有用——配置文件的优先级更高。
如果需要批量修改或通过 CI/CD 管理密码,直接修改 config.yaml 然后重启容器即可,无需进数据库操作。
注意事项 链接到标题
- NetBird 自 0.32.0 起将 setup key 以哈希形式存在 store.db,但 idp.db 的 password 表仍然是 bcrypt 明文哈希
- Dex 的 local connector 不支持密码哈希算法切换,bcrypt 是唯一选项
- 如果开启了外部 OIDC 提供商(如 Google/GitHub),管理员密码不经过 idp.db,此方法不适用
- 建议首次部署后立即生成 Personal Access Token 备存,避免再次陷入密码遗忘的困境