在Debian12上用docker部署Vaultwarden

5月29日更新

  1. 完善了compose文件配置的一部分解释,新增了用默认sqlite数据库的配置模板点击前往↩︎
  2. 使用apt install fail2ban安装的fail2ban的设置事宜点击前往↩︎

大致步骤:

  1. 在合适的位置创建文件夹保存docker-compose.yml文件和数据库数据
  2. 配置docker-compose.yml文件,配置好后运行 docker compose up -d运行服务
  3. 配置反向代理
  4. 配置fail2ban 防止密码管理器帐号被暴力破解

前期准备

  • 一个vps服务器
  • 一个域名,已经dns解析到服务器的ip地址(下文用example.com替代,自行替换成你自己的)

开始部署

设定数据保存位置

我喜欢在/home文件夹存放docker容器的数据,因此创建并进入/home/docker_apps/vaultwarden文件夹:

cd /home
mkdir docker_apps docker_apps/vaultwarden

进入刚刚创建的文件夹,创建docker-compose.yml文件并编辑

cd docker_apps/vaultwarden
vim docker-compose.yml

键入i进入编辑模式(左下角显示--insert--)

编辑配置docker-compose.yml文件

按照官方wiki进行配置,或者查看汉化版

我的docker-compose.yml文件(使用了postgresql数据库):

services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    volumes:
      - ./vw-data/:/persistent/ 
      - ./vw-attachments/:/attachments/
      
     # - ./vw-database/:/database/
     #启用默认的数据库时启用,并注释掉下文的‘- DATABASE_URL=’,这里启用了postgresql就不启用了
      
      - /icon_cache/ #这样子后每次更新会清除图标,可以可避免保留过时的图标
      - ./logs/:/fail2banlogs/ 
      #log日志文件,启用fail2ban时需要
    restart: unless-stopped
    depends_on: 
     - db
    ports:
      - "127.0.0.1:8888:80"
    environment:
      - DOMAIN=https://example.com #输入你自己的域名
      
    # - SIGNUPS_DOMAINS_WHITELIST=gmail.com,outlook.com,hotmail.com,qq.com
      #启用后"SIGNUPS_ALLOWED"将失效,始终可使用下面设置的邮箱域名后缀注册
      #如果不启用邮件服务,可设置一个其他人不知道的域名后缀来达到禁止其他人注册
      #不过密码管理器这种东西很少有人会去一个不明网站注册一个然后拿来用吧

      - WEB_VAULT_ENABLED=true #启用网页页面

      - SIGNUPS_ALLOWED=false  
      #启用后禁止注册,只能登录管理员页面去邀请用户,启用SIGNUPS_ALLOWED后失效
      - SIGNUPS_VERIFY=true    
      #启用注册验证,即往注册帐号的邮箱发送验证
      - ADMIN_TOKEN=${VAULTWARDEN_ADMIN_TOKEN} 
      #启用管理员界面,https://域名/admin 登录,这些在配置文件中设置的都可以在上面再配置 

        # 数据映射
      - DATA_FOLDER=/persistent 
    # - DATABASE_URL=/database/vaultwarden.sqlite3  
    #使用默认数据库时启用,使用其他数据库时将此条注释掉

      - DATABASE_URL=postgres://${DB_USER}:${DB_SECRET}@db/${DB_NAME}?sslmode=disable 
      #使用默认数据库时,将此条注释掉

      - ATTACHMENTS_FOLDER=/attachments
      - ICON_CACHE_FOLDER=/icon_cache
      - ROCKET_WORKERS=20 

        #(可选)启用bitwarden的push,访问https://bitwarden.com/host/ 输入邮箱注册,地区选的美国
        #在网页端登录过,然后下次再登录需要你重复输入密码时会多出一个用其他设备登录
        #点击那个按钮可用在手机"设置-待处理的登录请求批准登录"
        #设置完这个后,会给你手机推送一个消息,iOS亲测可用,其他系统自测
      - PUSH_ENABLED=true
      - PUSH_INSTALLATION_ID=       #将注册的id复制至此
      - PUSH_INSTALLATION_KEY=      #将注册的key复制至此

        #通知邮件的配置
        #我这里使用的是自建邮箱,gmail的设置可用去官方wiki查看
      - SMTP_HOST=
      - SMTP_PORT=587
      - SMTP_SECURITY=starttls
      - SMTP_FROM=${SMTP_FROM}
      - SMTP_USERNAME=${SMTP_USER}
      - SMTP_PASSWORD=${SMTP_PASSWD}
  
      - SHOW_PASSWORD_HINT=false   #密码提示
        
      - LOG_FILE=/fail2banlogs/vaultwarden.log      #日志文件,配合fail2ban使用
      - LOG_LEVEL=info
      - EXTENDED_LOGGING=true
        # - ENABLE_WEBSOCKET=false # 禁用websocket,建议别禁
        
  
  #使用你喜欢的数据库,postgres的话可用设置16或者17,我这个比较早以前弄得是15,最好固定版本
  db:
    image: postgres:15  
    container_name: postgres_vaultwarden
    environment:
        - POSTGRES_DB=${DB_NAME}
        - POSTGRES_USER=${DB_USER}

        - POSTGRES_PASSWORD=${DB_SECRET} 
        #特殊字符要特别设置转义字符,懒得折腾可用仅使用大小写的字母和数字
    volumes:
        - ./db:/var/lib/postgresql/data
    restart: unless-stopped

修改好后键入:wq按下回车退出

使用默认sqlitedocker-compose.yml文件

services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    volumes:
      - ./vw-data/:/persistent/
      - ./vw-attachments/:/attachments/
      - ./vw-database/:/database/
      - /icon_cache/ # 升级后会清除图标
      - ./vw-logs/:/f2blogs/ # log日志文件位置,如果使用fail2ban需要
    restart: unless-stopped
    ports:
      - "127.0.0.1:8888:80"
    environment:
        # web以及基本配置
      - DOMAIN=https://example.com
      - WEB_VAULT_ENABLED=true # 启用网页页面
      - SIGNUPS_ALLOWED=false # 启用禁止注册
      - SIGNUPS_VERIFY=true # 启用注册验证
      - ADMIN_TOKEN=${VAULTWARDEN_ADMIN_TOKEN} # 启用管理员界面 

        #数据映射
      - DATA_FOLDER=/persistent 
      - ATTACHMENTS_FOLDER=/attachments
      - DATABASE_URL=/database/vaultwarden.sqlite3
      - ICON_CACHE_FOLDER=/icon_cache
      - ROCKET_WORKERS=20 

        #启用bitwarden的push,前提是你是用bitwarden的官方客户端
        #如果使用keyguard(安卓)这种开源第三方客户端,不知道有没有推送
        #ID和key访问https://bitwarden.com/host/ 填入邮箱获得,地区随便选我选了美国
        #作用是如果你网页端登录时有用其他设备登录会有通知push到你手机
        #iOS亲测可用,其他端没有测试过
      - PUSH_ENABLED=true
      - PUSH_INSTALLATION_ID=
      - PUSH_INSTALLATION_KEY=
        #通知邮件的配置(可选)
      - SMTP_HOST=
      - SMTP_PORT=
      - SMTP_SECURITY=starttls
      - SMTP_FROM=${SMTP_FROM}
      - SMTP_USERNAME=${SMTP_USER}
      - SMTP_PASSWORD=${SMTP_PASSWD}
        #显示密码提示
      - SHOW_PASSWORD_HINT=true

        #日志文件,用于配合fail2ban
      - LOG_FILE=/f2blogs/vaultwarden.log 
      - LOG_LEVEL=info
      - EXTENDED_LOGGING=true

编辑.env环境变量

同文件夹下键入 vim .env 按 i 进入编辑模式

VAULTWARDEN_ADMIN_TOKEN=
DB_NAME=
DB_USER=
DB_SECRET=
SMTP_FROM=
SMTP_USERNAME=
SMTP_PASSWD=

如果使用默认配置则不需要在.env文件中设置数据库信息"DB_xxx"的相关变量自行删除

各个值都用小引号‘’括起来。

如果启用管理员页面.env文件里的VAULTWARDEN_ADMIN_TOKEN值要避免明文,如何设置参考官方wiki中文版页面

配置完成后在此文件夹下运行 docker compose up -d 以启动服务。 可使用命令docker ps是否正常运行

配置反向代理

需要提前安装好nginx、certbot、python3-certbot-nginx

如果没有安装,执行:

apt update
apt install nginx certbot python3-certbot-nginx

创建配置文件 vim /etc/nginx/conf.d/vaultwarden.confi进入编辑模式,wiki上有示例配置,或者查看 汉化版说明

用certbot申请ssl证书,以下二选一

  1. 停止nginx(systemctl stop nginx)后运行certbot certonly --standalone -d example.com然后再去配置文件中指定ssl证书文件位置,再运行systemctl restart nginx重启nginx
  2. 不停止nginx,将配置文件的server块改成只监听80端口,让certbot自动设置你的ssl证书位置,执行certbot --nginx -d example.com

我使用第二种,下面是示例配置:

文件路径:/etc/nginx/conf.d/vaultwarden.conf:

server {
    listen 80;
    listen [::]:80;
    server_name example.com;



    client_max_body_size 200M;
location / {
      proxy_set_header   X-Real-IP $remote_addr;
      proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header   Host $host;
      proxy_pass         http://localhost:8888/;
      proxy_http_version 1.1;
      proxy_set_header   Upgrade $http_upgrade;
      proxy_set_header   Connection "upgrade";
      proxy_set_header X-Forwarded-Proto $scheme;

      
  }
}

编辑好后,执行certbot --nginx -d example.com后如果没有报错那就是已经设置上了,这时候再查看这个配置会发现被certbot自动增加上了ssl部分,打开浏览器访问你的网页吧。

或者你可以用cf-tunnel的方式设置ssl,适合家里云这种配置起来麻烦的情况,可参考少数派的这篇文章

优点是相比家里云,没有端口号小尾巴,且配置简单

缺点是可能延迟高,但这个密码库是本地存储的,只有修改密码库时要联网,对延迟要求不高,勉强能接受

使用cf-tunnel的或者开了cloudflare小黄云的要去管理页面把客户端IP标头设置为CF-Connecting-IP否则fail2ban不会起作用

配置fail2ban

即输错密码3次后会ban掉IP一段时间

fail2ban可以直接照汉化过的wiki来。 假设你按官方的wiki设置了一对filter与jail规则vaultwarden.local(按wiki在对应的文件夹创建对应的文件),执行 fail2ban-client status vaultwarden查看状态

设置网页端的fail2ban

fail2banfilter.d文件夹创建规则,输入以下内容vim /etc/fail2ban/filter.d/vaultwarden.local

# path_f2b/filter.d/vaultwarden.local

[INCLUDES]
before = common.conf

[Definition]
failregex = ^.*?Username or password is incorrect\. Try again\. IP: <ADDR>\. Username:.*$
ignoreregex =

fail2banjail.d文件夹创建规则,输入以下内容vim /etc/fail2ban/jail.d/vaultwarden.local

# path_f2b/jail.d/vaultwarden.local

[vaultwarden]
enabled = true
port = 80,443,8081
filter = vaultwarden
banaction = %(banaction_allports)s
logpath = /path/to/vaultwarden.log  #你的log文件的绝对路径
maxretry = 3
bantime = 14400
findtime = 14400

设置网页端admin管理界面的fail2ban

fail2banfilter.d文件夹创建规则,输入以下内容vim /etc/fail2ban/filter.d/vaultwarden-admin.local

# path_f2b/filter.d/vaultwarden-admin.local

[INCLUDES]
before = common.conf

[Definition]
failregex = ^.*Invalid admin token\. IP: <ADDR>.*$
ignoreregex =

fail2banjail.d文件夹创建规则,输入以下内容vim /etc/fail2ban/jail.d/vaultwarden-admin.local

# path_f2b/jail.d/vaultwarden-admin.local

[vaultwarden-admin]
enabled = true
backend = pyinotify #由于我使用的系统是Debian以及我使用的是apt方式安装的fail2ban,按wiki说法这里得加这个
port = 80,443
filter = vaultwarden-admin
banaction = %(banaction_allports)s
logpath = /path/to/vaultwarden.log #你的log文件的绝对路径
maxretry = 3
bantime = 14400
findtime = 14400

TOTPfail2ban设置,用于vaultwarden帐号设置了二次验证的

fail2banfilter.d文件夹创建规则,输入以下内容vim /etc/fail2ban/filter.d/vaultwarden-totp.local

# path_f2b/filter.d/vaultwarden-totp.local
# Fail2Ban filter for Vaultwarden TOTP

[INCLUDES]
before = common.conf

[Definition]
failregex = ^.*\[ERROR\] Invalid TOTP code! Server time: (.*) UTC IP: <ADDR>$
ignoreregex =

fail2banjail.d文件夹创建规则,输入以下内容 vim /etc/fail2ban/jail.d/vaultwarden-totp.local

# path_f2b/jail.d/vaultwarden-totp.local

[vaultwarden-totp]
enabled = true
backend = pyinotify #由于我使用的系统是Debian以及我使用的是apt方式安装的fail2ban,按wiki说法这里得加这个
port = 80,443
filter = vaultwarden-totp
banaction = iptables-multiport[name=vaultwarden-totp, port="80,443", protocol=tcp]
logpath = /path/to/vaultwarden.log #你的log文件的绝对路径
maxretry = 3
bantime = 14400
findtime = 14400

重启fail2ban sudo systemctl restart fail2ban 即可生效

查看对应的规则ban了多少IP

#查看web登录失败封禁状况
fail2ban-client status vaultwarden 
#如果某个IP访问登录帐号页面并输错密码或者邮箱,3次会banIP(jail文件对应规则maxretry = 3)

#查看管理员页面登录失败封禁状况
fail2ban-client status vaultwarden-admin 
#如果某个IP在登录管理员页面输错密码,3次会banIP(jail文件对应规则maxretry = 3)

#查看二次验证输入错误封禁状况
fail2ban-client status vaultwarden-totp
#如果某个IP在登录vaultwarden时,输入二次验证时出错会记录,3次会banIP(jail文件对应规则maxretry = 3)

docker安装的fail2ban可去wiki自己研究

到此为止基本结束了。

参考

  1. Vaultwarden Wiki 中文版
  2. Vaultwarden Wiki(官方wiki)
  3. CloudFlare Tunnel 免费内网穿透的简明教程