趁现在自己还记忆犹新,赶紧记录下搭建Vaultwarden的过程。
安全加固措施
用MySQL替换默认SqLite数据库,并配置异地主从数据库备份 在Nginx配置location / {return 403;}屏蔽WEB访问,只保留必要配置 启用OpenVpn+SSL自签证书 服务器部署 Vaultwarden 搭建开源Vaultwarden 通过Docker容器安装
docker run -d \ --rm \ --name vaultwarden \ -p 8787:80 \ -p 3012:3012 \ -v /home/docker/vaultwarden:/data \ -e DATABASE_URL=mysql://user:password@127.0.0.1:8888/database \ -e SIGNUPS_ALLOWED=false \ -e WEBSOCKET_ENABLED=true \ -e INVITATIONS_ALLOWED=false \ -e ADMIN_TOKEN=your_admin_token \ -e DOMAIN=https://your_url.com \ vaultwarden/server:latest
80 web访问端口
3012 webscoket端口
/home/docker/vaultwarden建立目录用于容器外映射配置文件
-d 后台运行--rm 当容器停止时自动删除容器-e DATABASE_URL 配置数据源,默认SqLite(可选)-e SIGNUPS_ALLOWED 允许用户注册(首次用户注册后,删除容器,指定SIGNUPS_ALLOWED=false重新配置容器)-e WEBSOCKET_ENABLED 开启webscoket-e INVITATIONS_ALLOWED 允许邀请用户注册-e ADMIN_TOKEN 管理员令牌-e DOMAIN 配置访问域名(需要是https://xxx.com域名 ,不能配置ip地址),切换MySQL数据库 在docker配置容器命令添加:
示例配置:DATABASE_URL=mysql://[[user]:[password]@]host[:port][/database]
# 上述docker命令已包括 -e DATABASE_URL=mysql://vaultwarden_user:strong_password@11.1.0.9:8888/vaultwarden
配置私有IP自签名证书 注意:低版本的openssl执行会失败
11.1.0.1是我自签名SSL证书的的IP地址,执行命令得到:ca.crt证书、 ca.key密钥
openssl req -x509 -newkey rsa:2048 -sha256 -days 3650 -nodes \ -keyout ca.key -out ca.crt -subj "/CN=11.1.0.1" \ -addext "subjectAltName=IP:11.1.0.1"
由于是使用的自签名证书,需要导入浏览器、安卓手机才能正常访问
配置openVPN openvpn加固:
ca.crt 根证书 x.crt 签发证书 x.key 签发证书密钥 用户名+密码 openvpn导入连接 在移动端导入openvpn配置,需要将.ovpn文件和依赖的根证书ca.crt、自签证书.crt、.key一并选择进行导入
附录 安卓APP相关软件 安卓手机app软件(谷歌商店)
OpenVpn Connect (3.7.1) :开启OpenVPN连接Bitwarden (2025.06.1):密码管理软件Bitwarden Authenticator (2025.6.0) 密码管理软件-两步验证工具手机导入自签名证书 小米14的证书安装路径如下:
设置->隐私与安全->安全->更多安全设置->更多安全设置->加密与凭据->安装证书->CA证书
选择自签名IP的ca.crt证书安装到手机即可。
Nginx配置 server { listen 8443 ssl; # 监听ovpn地址 server_name 11.1.0.1; # 自签名证书 ssl_certificate /usr/local/nginx/conf/cert/vpn/11.1.0.1.crt; ssl_certificate_key /usr/local/nginx/conf/cert/vpn/11.1.0.1.key; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; # 仅允许openvpn下IP地址访问 allow 11.1.0.0/24; deny all; # 屏蔽web端访问 location /{ return 403; } # 允许 API 访问(确保客户端仍能同步) location /api/ { proxy_pass http://127.0.0.1:8787; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # 登录接口(web、pc、浏览器插件、app依赖) location /identity/ { proxy_pass http://127.0.0.1:8787; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # 允许 WebSocket(用于实时同步) location /notifications/hub { proxy_pass http://127.0.0.1:3012/notifications/hub; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } # 其他 location /notifications/hub/negotiate { proxy_pass http://127.0.0.1:8787; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; }
启用MTLS双向认证 配置双向认证后,在公网环境也可以
创建CA根证书(证书颁发机构)
# 创建CA私钥 openssl genrsa -out ca.key 2048 # 创建CA根证书(有效期10年) openssl req -new -x509 -days 3650 -key ca.key -out ca.crt # 需要填写国家、组织等信息
创建客户端证书
# 创建客户端私钥 openssl genrsa -out client.key 2048 # 创建证书签名请求(CSR) openssl req -new -key client.key -out client.csr # 需要填写与CA证书类似的信息 # 使用CA签署客户端证书(有效期1年) openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt # 将客户端证书转换为PKCS12格式(方便浏览器导入) openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12 # 需要设置导出密码
nginx配置
server { listen 9003 ssl; server_name 11.1.0.9; # 标准SSL配置 ssl_certificate /usr/local/nginx/conf/cert/11.1.0.9/ca.crt; ssl_certificate_key /usr/local/nginx/conf/cert/11.1.0.9/ca.key; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; #ssl_ciphers HIGH:!aNULL:!MD5; # 启用客户端证书验证 ssl_client_certificate /usr/local/nginx/conf/cert/CA/ca.crt; ssl_verify_client on; ssl_verify_depth 2; # 调整加密套件 ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-CHACHA20-POLY1305'; location /{ root /usr/local/nginx/html/snowyweb/dist; try_files $uri $uri/ /index.html; index index.html index.htm; } }
服务器迁移 Vaultwarden MySQL 数据库备份迁移 如果数据库不需要迁移,则请忽略当前 MySQL 数据库备份迁移 步骤
导出类似vaultwarden.sql的文件,需要包 表结构+数据
我在服务器上通过docker构建的mysql数据库,例如当前我需要导出vaultwarden数据库结构和数据:
查看docker启动中的镜像,并找到对应mysql的镜像ID
[root@manman ~]# docker ps; CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 420e8c5f5fc4 mysql "docker-entrypoint.s…" 2 years ago Up 7 weeks 33060/tcp, 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp mysql_8_0
进入docker镜像对应的命令
docker exec -it 420e8c5f5fc4 bash
导出需要备份的数据库sql文件到当前目录下
点击 ↩ 后,会要求输入密码︎
#mysqldump -u [用户名] -p [数据库名] > 导出的文件名.sql mysqldump -u root -p vaultwarden > backup_vaultwarden.sql
复制文件到宿主机目录下
#docker cp [容器名或ID]:容器内路径 宿主机路径 docker cp 420e8c5f5fc4:/backup_vaultwarden.sql ./
下载到本地
sz backup_vaultwarden.sql
Data 数据文件目录迁移 docker run -d \ --name vaultwarden \ ... -v /home/docker/vaultwarden:/data \ ## 需要迁移的文件目录在 /home/docker/ 下 ... vaultwarden/server:latest
tar -czvf vaultwarden.tar.gz vaultwarden/
需要先安装docker环境,并拉取镜像文件
docker pull vaultwarden/server:latest
本地启动镜像服务
docker run -d \ --name vaultwarden \ -p [WEB_PORT]:80 \ -p [SCOKET_PORT]:3012 \ -v [FILEPATH]:/data \ -e DATABASE_URL=mysql://[USERNAME]:[PASSWORD]@[IP:PORT]/[DBNAME] \ -e SIGNUPS_ALLOWED=false \ -e WEBSOCKET_ENABLED=true \ -e INVITATIONS_ALLOWED=false \ -e ADMIN_TOKEN=[ADMIN_TOKEN] \ -e DOMAIN=[DOMAIN] \ vaultwarden/server:latest
[WEB_PORT] WEB服务端口[SCOKET_PORT] SCOKET端口[FILEPATH] 宿主机文件目录,我的是 /home/docker/vaultwarden[USERNAME],[PASSWORD],[IP:PORT],[DBNAME] 分别对应的数据库用户名,密码,连接ip地址及端口,数据库名[ADMIN_TOKEN]管理员令牌[DOMAIN] 部署域名,我的是 https://bitwarden.wo0ow.com 配置Nginx并设置SSL证书 修改host文件,win的修改路径 C:\Windows\System32\drivers\etc\hosts
127.0.0.1 bitwarden.wo0ow.com
nginx-ssl的配置参考
server { listen 443 ssl; server_name bitwarden.wo0ow.com; ssl_certificate D:\\Env\\Nginx\\nginx-1.26.2\\conf\\cert\\cert.crt; ssl_certificate_key D:\\Env\\Nginx\\nginx-1.26.2\\conf\\cert\\cert.key; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; #ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; # 启用客户端证书验证 # ssl_client_certificate /usr/local/nginx/conf/cert/CA/ca.crt; # ssl_verify_client on; # ssl_verify_depth 2; # 强制浏览器发送证书 ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-CHACHA20-POLY1305'; #偶尔需要的时候在放开deny all,目前就通过openVPN进行访问安全性第一 #allow 222.94.93.108; #jmt-work 动态ip,可能下次又变其他ip #allow 11.1.0.0/24; #deny all; # 静态资源缓存配置 location ~* \.(js|css|png|jpg|jpeg|gif|ico|woff2|svg)$ { proxy_pass http://127.0.0.1:8787; # 指向 Vaultwarden 容器端口 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; # 缓存设置 expires 365d; # 缓存有效期 1 年 add_header Cache-Control "public, immutable"; proxy_hide_header Cache-Control; # 覆盖后端返回的缓存头 } # 屏蔽web端访问 #location /{ # return 403; #} # 允许 API 访问(确保客户端仍能同步) #location /api/ { # 只需要访问api,就使用这个配置行 location / { # 需要访问web端,打开这个注释 # 在nginx.conf配置允许国家 # if ($allowed_country = no) { # return 403; # } # 自签mtls证书校验 # if ($ssl_client_verify != SUCCESS) { # return 403; # } proxy_pass http://127.0.0.1:8787; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # 登录接口(web、pc、浏览器插件、app依赖) location /identity/ { proxy_pass http://127.0.0.1:8787; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # 允许 WebSocket(用于实时同步) location /notifications/hub { proxy_pass http://127.0.0.1:3012/notifications/hub; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } # 其他 location /notifications/hub/negotiate { proxy_pass http://127.0.0.1:8787; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # 495 是 Nginx 定义的错误代码,表示 "SSL Certificate Error" # 496 表示 "SSL Certificate Required" #error_page 495 496 =403 @empty; location @empty { return 403; } }
可以通过浏览器安装 bitwarden 插件进行连接,或者是通过bitwarden的网页管理端进行使用。