vaultwarden + nginx 搭建局域网密码管理工具

发布时间 2023-08-16 14:51:50作者: Ainsliaea

介绍

之前一直在用 lastpass 管理个人密码,后来 lastpass 各种收费的广告,还爆出很多漏洞和密码泄露的消息,所以开始寻找开源、安全、免费的替代方案,过程中发现 bitwarden 还可以,正好工作上也有很多密码要管理,所以研究了一下部署方式。

优点:开源、支持私有部署、本地保存密码。

选型和环境

bitwarden 在 github 提供 server 部署方式,但是占用资源比较多,部署不太友好,所以更为流行的部署方式是采用另一个开源的 vaultwarden
image
vaultwarden 实现了大部分 bitwarden 原生提供的功能,所以在使用上并没有太大差别。

由于我的目标是局域网管理密码,部署的服务器无法连接互联网所以 vaultwarden 推荐的 caddy 自动 https 的方案并不太实用,或者过于麻烦,而且 caddy 用的还是不太熟练,因此我用了更流行、也更熟悉的 nginx 来配置 https。

因此本文仅供要在局域网环境部署且采用 nginx 的需求参考,其他需求还需要参考 vaultwarden 的 wiki

docker vaultwarden:server image:1.27.0
image
nginx 1.24.0
centos 7.9.2009

部署

1. 部署 nginx

网上太多教程,不再赘述

2. 部署 vaultwarden

docker pull vaultwarden/server:latest
通过 docker compose 来运行容器,比较好管理。

version: '3'

services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: always
    ports:
      - "18080:80"
      - "3012:3012"
    environment:
      DOMAIN: "https://192.168.20.88/vault/"
      SIGNUPS_ALLOWED: 'true'
      WEBSOCKET_ENABLED: 'true'
    volumes:
      - ./vw-data:/data

注意:

  • 单独路径访问的话需要指明,例如这里的 vault
  • 映射 3012 端口以保证 websocket 正常通信
  • SIGNUPS_ALLOWED 设置为 true,开启注册,注册完后可以设置为 false

配置

1. https[1]

编写 req.conf

# 定义输入用户信息选项的"特征名称"字段名,该扩展字段定义了多项用户信息。
distinguished_name = req_distinguished_name

# 生成自签名证书时要使用的证书扩展项字段名,该扩展字段定义了要加入到证书中的一系列扩展项。
x509_extensions = v3_req

# 如果设为no,那么 req 指令将直接从配置文件中读取证书字段的信息,而不提示用户输入。
prompt = no

[req_distinguished_name]
#国家代码,一般都是CN(大写)
C = CN
#省份
ST = ln
#城市
L = sy
#企业/单位名称
O = foobar
#企业部门
OU = foobar
#证书的主域名
CN = 192.168.20.88

##### 要加入到证书请求中的一系列扩展项 #####
[v3_req]
keyUsage = critical, digitalSignature, keyAgreement
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[ alt_names ]
IP.1 = 192.168.20.88

执行命令
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout server.key -out server.crt -config req.cnf -sha256

2. nginx.conf[2]

#user  nobody;
worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       80;
	    return 301 https://$host$request_uri; # 重定向到 https

        server_name  localhost;

        location / {
            root   html;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
   
    upstream vaultwarden-default {
        zone vaultwarden-default 64k;
        server 127.0.0.1:18080;
        keepalive 2;
    }
    # 支持 websocket
    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      "";
    }

    server {
        listen       443 ssl;
        server_name  192.168.20.88;

        ssl_certificate      /home/ross/foo/ssl/server.crt; 
        ssl_certificate_key  /home/ross/foo/ssl/server.key;

        ssl_session_cache    shared:SSL:10m;
        ssl_session_timeout  120m;
        ssl_prefer_server_ciphers  on;

	    ssl_session_tickets off;
        ssl_stapling_verify on;

        # 单独路径 vault 访问 vaultwarden
        location /vault/ {
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;

            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;

            proxy_pass http://vaultwarden-default;
        }      
        
 	    location /vault/notifications/hub {
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
	    
	        proxy_pass http://127.0.0.1:3012;
	    }
        
    }
}

3. 防火墙配置

firewall-cmd --permanent --add-port=80/tcp
firewall-cmd --permanent --add-port=443/tcp

巨人的肩膀


  1. https://www.cnblogs.com/echohye/p/16722833.html ↩︎

  2. https://rs.ppgg.in/deployment/proxy-examples ↩︎