无需服务器,利用Cloudflare自建Bitworden密码管理器

无需服务器,利用Cloudflare自建Bitworden密码管理器

Bitwarden是一款非常优秀的密码管理器,尤其是它支持DuckDuckGo生成随机邮箱的功能,深得我心。但遗憾的是,其官方服务器在大陆访问体验不佳,这让我萌生了自建服务的念头。以往自建通常采用Vaultwarden项目,但这往往需要购买一台VPS并在Docker中部署,有一定的门槛和成本。而现在,warden-worker项目带来了一种全新的无服务器(Serverless)自建模式——你只需要拥有一个Cloudflare和GitHub账号,配合一个域名,即可零成本搭建一个完全属于自己的密码管理器。

前言

Bitwarden是一款非常优秀的密码管理器,尤其是它支持DuckDuckGo生成随机邮箱的功能,深得我心。但遗憾的是,其官方服务器在大陆访问体验不佳,这让我萌生了自建服务的念头。
以往自建通常采用Vaultwarden项目,但这往往需要购买一台VPS并在Docker中部署,有一定的门槛和成本。而现在,warden-worker项目带来了一种全新的无服务器(Serverless)自建模式——你只需要拥有一个CloudflareGitHub账号,配合一个域名,即可零成本搭建一个完全属于自己的密码管理器。

准备

  1. 一个Github账号
  2. 一个Cloudflare账号
  3. 一个没有被阻断的域名

设置Github项目

  1. Fork该项目到你的Github账户,进入Actions页面,启用Github Actions
  2. 点击settings - Secrets and variables - Actions,准备添加Repository secrets
  3. 打开Cloudflare 控制台,https://dash.cloudflare.com/,在地址栏复制你的用户ID
  4. 回到Github页面,点击New repository secret,Name写CLOUDFLARE_ACCOUNT_ID,Secret就写刚才复制的ID
  5. 访问https://dash.cloudflare.com/profile/api-tokens,点击创建令牌 - 编辑 Cloudflare Workers - 使用模板 - 权限处添加更多 - 第一个选项选择账户 - 第二个选项选择D1 - 第三个选项选择编辑,其余选项按照个人需求选择即可,然后点击继续以显示摘要 - 创建令牌
  6. 复制页面显示的令牌到Github页面按照上述方法再创建一个Secret,Name为CLOUDFLARE_API_TOKEN
  7. 最后去Cloudflare控制台的存储与数据库 - D1 SQL 数据库,创建一个数据库,并复制它的ID,随后回到Github页面按照上述方法再创建一个Secret,Name为D1_DATABASE_ID
  8. 附件支持(可选)
    该项目的附件功能依赖R2,虽然Cloudflare提供了慷慨的免费额度,但仍可能产生非预期的扣费,参考Cloudflare R2 pricing,因此该功能默认关闭。
    如果你想启用R2支持,需要先去Cloudflare控制台创建一个R2储存桶,记下它的名称。
    在Github仓库中添加一个Secret,NameR2_NAMESecret填刚才创建的桶名称。
  9. 至此在Github上的配置就完毕了,点击上方的Actions选项卡,选到Build工作流点Run workflow即可。

建立数据表

打开刚才创建的数据库,点Explore Data,然后在Query窗口中分别粘贴并运行以下sql建表语句,一次只执行一条:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
CREATE TABLE IF NOT EXISTS users (
id TEXT PRIMARY KEY NOT NULL,
name TEXT,
avatar_color TEXT,
email TEXT NOT NULL UNIQUE,
email_verified BOOLEAN NOT NULL DEFAULT 0,
master_password_hash TEXT NOT NULL,
master_password_hint TEXT,
password_salt TEXT, -- Salt for server-side PBKDF2 hashing (NULL for legacy users pending migration)
key TEXT NOT NULL, -- The encrypted symmetric key
private_key TEXT NOT NULL, -- encrypted asymmetric private_key
public_key TEXT NOT NULL, -- asymmetric public_key
kdf_type INTEGER NOT NULL DEFAULT 0, -- 0 for PBKDF2, 1 for Argon2id
kdf_iterations INTEGER NOT NULL DEFAULT 600000,
kdf_memory INTEGER, -- Argon2 memory parameter in MB (15-1024), NULL for PBKDF2
kdf_parallelism INTEGER, -- Argon2 parallelism parameter (1-16), NULL for PBKDF2
security_stamp TEXT,
totp_recover TEXT, -- Recovery code for 2FA
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
CREATE TABLE IF NOT EXISTS ciphers (
id TEXT PRIMARY KEY NOT NULL,
user_id TEXT,
organization_id TEXT,
type INTEGER NOT NULL,
data TEXT NOT NULL, -- JSON blob of all encrypted fields (name, notes, login, etc.)
favorite BOOLEAN NOT NULL DEFAULT 0,
folder_id TEXT,
deleted_at TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (folder_id) REFERENCES folders(id) ON DELETE SET NULL
);
1
2
3
4
5
6
7
8
CREATE TABLE IF NOT EXISTS folders (
id TEXT PRIMARY KEY NOT NULL,
user_id TEXT NOT NULL,
name TEXT NOT NULL, -- Encrypted folder name
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
1
2
3
4
5
6
7
8
9
10
11
12
CREATE TABLE IF NOT EXISTS attachments (
id TEXT PRIMARY KEY NOT NULL,
cipher_id TEXT NOT NULL,
file_name TEXT NOT NULL,
file_size INTEGER NOT NULL,
akey TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
organization_id TEXT,
FOREIGN KEY (cipher_id) REFERENCES ciphers(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_attachments_cipher ON attachments(cipher_id);
1
2
3
4
5
6
7
8
9
10
11
12
13
CREATE TABLE IF NOT EXISTS attachments_pending (
id TEXT PRIMARY KEY NOT NULL,
cipher_id TEXT NOT NULL,
file_name TEXT NOT NULL,
file_size INTEGER NOT NULL,
akey TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
organization_id TEXT,
FOREIGN KEY (cipher_id) REFERENCES ciphers(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_attachments_pending_cipher ON attachments_pending(cipher_id);
CREATE INDEX IF NOT EXISTS idx_attachments_pending_created_at ON attachments_pending(created_at);
1
2
3
4
5
6
7
8
9
10
CREATE TABLE IF NOT EXISTS twofactor (
uuid TEXT PRIMARY KEY NOT NULL,
user_uuid TEXT NOT NULL,
atype INTEGER NOT NULL,
enabled INTEGER NOT NULL DEFAULT 1,
data TEXT NOT NULL, -- JSON data specific to the 2FA type (e.g., TOTP secret)
last_used INTEGER NOT NULL DEFAULT 0, -- Unix timestamp or TOTP time step
FOREIGN KEY (user_uuid) REFERENCES users(id) ON DELETE CASCADE,
UNIQUE(user_uuid, atype)
);

PS:定义在sql/schema.sql

配置环境变量与自定义域名

当Github的Action执行完毕后,你就能在CF的Workers中找到刚才创建的warden-worker了,进入这个Worker的设置页面,在变量和机密栏添加以下三个密钥:

名称 说明
ALLOWED_EMAILS 允许注册的完整邮箱,用,分隔(例:your-name@example.com
JWT_SECRET 随机长字符串
JWT_REFRESH_SECRET 随机长字符串

可选环境变量

  • IMPORT_BATCH_SIZE:用于控制导入密码库时,每次批操作的数据条数,默认为30,设为0代表一次批操作导入所有数据(不推荐);如果你需要导入的库特别大,可以适当调大这个值。
  • TRASH_AUTO_DELETE_DAYS: 配置回收站中的项目多少天后会被清理,默认为30,设为0代表永不清理。
  • DISABLE_USER_REGISTRATION: 用于控制是否表明服务器不支持注册,默认为true,设为false可以让客户端显示注册按钮;该选项不影响实际注册功能。
  • AUTHENTICATOR_DISABLE_TIME_DRIFT: 控制是否允许TOTP的时间±1偏移,默认为true。
  • ATTACHMENT_MAX_BYTES: 单个附件的大小限制,单位字节,默认不限制,填104857600则代表100MB。
  • ATTACHMENT_TOTAL_LIMIT_KB: 单个用户的总附件大小限制,单位KB,默认不限制,填1048576代表1GB。
  • ATTACHMENT_TTL_SECS: 附件的上传下载链接的有效时间,默认五分钟。

然后在域和路由中添加一个路由,区域选择你的域名,路由写你分给这个Worker的子域名 + /*(如bitwarden.example.com/*)。

最后别忘记去给这个子域名添加一条DNS记录。
如果你想优选IP,那就不开小黄云,把它CNAME到一个优选过的域名。
要是不想优选,那就打开小黄云,目标随便填。

建议去域名配置页的 安全性 - 安全规则 里给 /identity/*/api/accounts/* 添加速率限制规则。

创建账户并导入数据

如果已有Bitwarden库,在电脑上把它导出为JSON即可。
注意: 创建账户时用的密码必须记住,没有任何方式能找回。

可选:配置数据库同步S3

如果没什么特殊需求,可以试试 backblaze,虽然额度非常少但用来备份也够了,胜在完全免费不绑卡。
此处略过注册账户和创建桶的操作。

请确保你之前添加的 CLOUDFLARE_API_TOKEN 至少有D1的读取权限。

回到你fork的github仓库,继续添加以下secrets:

Secret Required Description
S3_ACCESS_KEY_ID yes S3 access key ID
S3_SECRET_ACCESS_KEY yes S3 secret access key
S3_BUCKET yes 桶名称
S3_REGION yes S3 区域,有就正常填,不知道就直接填auto
S3_ENDPOINT no 用AWS就不用填,其他填https://your-s3-domain.com的形式,带协议不带路径
BACKUP_ENCRYPTION_KEY no 额外加密密钥,不填就不加密,填了就一定要记住

然后在Actions页面中选到Backup D1 Database to S3,手动触发一次,等待它运行完成,然后检查你的S3中是否有备份文件。成功后,每天都会自动备份一次,每个备份默认保存30天。

文章部分内容引用:https://linux.do/t/topic/1232950

无需服务器,利用Cloudflare自建Bitworden密码管理器

https://imjipa.top/warden-worker/

作者

jipa233

发布于

2026-02-16

更新于

2026-02-16

许可协议


评论

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×