目录

使用 Docker 快速搭建 Bitwarden 个人密码管理服务

首先编辑 docker-compose 文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
version: "3.0" ##docker-compose版本,一般不用动。
services:
  Bitwarden: ##服务名称
    image: vaultwarden/server:latest ##容器使用的镜像名称
    container_name: Bitwarden ##新建容器的名称
    restart: always ##重启策略,always 为始终,一般默认即可。
    network_mode: bridge ##容器采用的网络模式,host 为共享主机网络,bridge 为桥接。
    ports: 
      - "8192:80"
    environment:
      - SIGNUPS_ALLOWED=false #设置环境变量SIGNUPS_ALLOWED=true允许用户注册
      - WEB_VAULT_ENABLED=true #设置环境变量WBE_VAULT_ENABLE=true
      - [email protected] #配置邮箱
      - ADMIN_TOKEN=  #通过openssl rand -base64 48获取
      - INVITATIONS_ALLOWED=false #是否允许通过邮箱发送邀请链接进行服务的注册
      - DOMAIN=https://bitwarden.example.com/ #设置域名
      - TZ=Asia/Shanghai
    volumes: ##映射的路径,引号前为主机路径,后为容器内部路径。
      - ./data:/data

首先可以设置 SIGNUPS_ALLOWED=true 进行注册,然后再修改为 false,再次运行配置文件,这样就可以只有一个用户,防止其他人注册使用。

可以通过邮件邀请注册,也是通过 INVITATIONS_ALLOWED 是否为 true 决定的。

使用 Nginx 进行反代

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
server {
    listen                  443 ssl http2;
    server_name             bitwarden.example.com;

    # SSL
	ssl_certificate         /etc/nginx/ssl/bitwarden.example.com/fullchain.cer;
    ssl_certificate_key     /etc/nginx/ssl/bitwarden.example.com/bitwarden.example.com.key;
    ssl_trusted_certificate /etc/nginx/ssl/bitwarden.example.com/ca.cer;

    # security
    include                 nginxconfig.io/security.conf;

    # logging
    access_log              /var/log/nginx/access.log combined buffer=512k flush=1m;
    error_log               /var/log/nginx/error.log warn;

    # reverse proxy
    location / {
        proxy_pass http://127.0.0.1:8192;
        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;
    }
    
    location /notifications/hub/negotiate {
        proxy_pass http://127.0.0.1:8192;
    }

    location /admin {
        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://127.0.0.1:8192;
    }

    # additional config
    include nginxconfig.io/general.conf;
}

# HTTP redirect
server {
    listen      80;
    server_name bitwarden.example.com;

    location / {
        return 301 https://bitwarden.example.com$request_uri;
    }
}

前往管理页面

https://image.westinyou.com/blog-imgs/2023/04/02/admin_token.png
输入 admin token 的值

这个页面输入 ADMIN_TOKEN 的值,进去之后,前往 Diagnostics 查看配置时间、反代是否有问题:

https://image.westinyou.com/blog-imgs/2023/04/02/diagnostics.png
Diagnostics
这个页面基本上都是绿色的话应该就没有什么问题可以进行后面的邮件配置,如果有问题,请先修复。

配置 NTP

在 Diagnostics 中,时间同步有误,需要在服务器上配置 NTP 来保持正确的时间同步

https://image.westinyou.com/blog-imgs/2023/04/02/date&time.png
正确的date&time

  1. 安装 NTP 服务
    1
    
    sudo apt-get update && sudo apt-get install ntp
    
  2. 重启 NTP 服务
    1
    
    sudo service ntp restart
    
  3. 现在前往 Diagnostics 页面再次检查,刷新页面之后依然有误,则重启这个 container,之后应该就是正常的了。

其余配置

配置 SMTP

https://image.westinyou.com/blog-imgs/2023/04/02/smtp_qq_settings.png
使用 QQ 邮箱配置 SMTP

因为我搭建的这个服务器在国内,所以使用 QQ 邮箱比较稳定,国外优先使用 Gmail,具体的配置信息就如图所示,From Name 是发件人名字,可以自己个性化填写,Password 需要前往 QQ 邮箱获取 SMTP 的密钥而不是 QQ 密码。全部填写好了之后,先点击页面左下角的 Save 保存,然后再次点开设置,在 Test SMTP 中输入测试邮箱,如果提示下面这张图片的信息,那么表明你配置成功了。

https://image.westinyou.com/blog-imgs/2023/04/02/smtp_success.png

当然在 Secure SMTP 中可以选择 force_tls,这个时候 Port 则需要填写 465

如果选择 Gmail,那么这里的密码获取步骤:

  1. 转到您的 Google 帐户
  2. 选择安全。
  3. 在“登录 Google”下,选择两步验证
  4. 在页面底部,选择应用程序密码
  5. 输入可帮助您记住将在何处使用应用密码的名称。
  6. 选择生成
  7. 要输入应用程序密码,请按照屏幕上的说明进行操作。应用程序密码是在您的设备上生成的 16 个字符的代码。
  8. 选择完成

https://image.westinyou.com/blog-imgs/2023/08/20/smtp_gmail_setting.png
使用 Gmail 配置 SMTP

打开 Email 2FA

https://image.westinyou.com/blog-imgs/2023/04/02/Enabled_Email_2FA.png

账户个性化设置

开启两步登录

https://image.westinyou.com/blog-imgs/2023/04/02/Authenticator.png
使用验证器进行验证,保障安全

我选择的是 Google Authenticator,对于我来说,这个比较方便和安全。

注意
一定要找个地方把自己的 恢复代码 记录下来,保证自己账户的安全。

登录浏览器插件、本地程序

注意
在登录的时候需要设置登录 Bitwarden 的网址,否则就是登录 Bitwarden 的官方的服务了。

https://image.westinyou.com/blog-imgs/2023/04/02/setting_url.png

个性化设置

https://image.westinyou.com/blog-imgs/2023/04/02/auto_fill.png
自动填充,匹配规则使用

https://image.westinyou.com/blog-imgs/2023/04/02/no_card.png
不显示支付卡和身份信息

https://image.westinyou.com/blog-imgs/2023/04/02/Safety.png
安全设置

数据库备份到 Dropbox

获取 refresh_token

  1. 前往 dropbox apps 注册一个 app;
  2. https://www.dropbox.com/oauth2/authorize?client_id=<your_app_key>&token_access_type=offline&response_type=code 去浏览器输入该网址,获取 app 的 access_code,网址中需要替换<your_app_key>
  3. 输入已下命令获取得到 refresh_token
    1
    2
    3
    4
    5
    
    curl https://api.dropboxapi.com/oauth2/token \
    -u '<your_app_key>:<your_app_secret>' \
    -H 'Content-Type: application/x-www-form-urlencoded' \
    --data-urlencode 'code=<your_app_access_code>' \
    --data-urlencode 'grant_type=authorization_code'
    

python 脚本运行

  1. 安装 python 脚本的环境:
    1
    
    pip install dropbox
    
  2. 创建并运行该脚本:
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    
    import shutil
    import dropbox
    import requests
    import os
    from dropbox.files import WriteMode
    from dropbox.exceptions import AuthError
    
    def refresh_dropbox_access_token(app_key, app_secret, refresh_token):
    	# Function to refresh the access token using the provided app_key, app_secret, and refresh_token.
    	url = "https://api.dropboxapi.com/oauth2/token"
    	auth = (app_key, app_secret)
    	data = {
    		"refresh_token": refresh_token,
    		"grant_type": "refresh_token"
    	}
    
    	response = requests.post(url, auth=auth, data=data)
    	response_data = response.json()
    
    	if "access_token" in response_data:
    		return response_data["access_token"]
    	else:
    		raise ValueError("Failed to refresh access token.")
    
    def upload_folder_to_dropbox(folder_path, dropbox_target_path, app_key, app_secret, refresh_token):
    	try:
    
    		dropbox_access_token = refresh_dropbox_access_token(app_key, app_secret, refresh_token)
    
    		dbx = dropbox.Dropbox(dropbox_access_token)
    
    		# 获取本地文件夹名
    		folder_name = os.path.basename(folder_path)
    
    		# 递归上传文件夹中的所有文件和子文件夹
    		for root, _, files in os.walk(folder_path):
    			for file in files:
    				local_file_path = os.path.join(root, file)
    				relative_path = os.path.relpath(local_file_path, folder_path)
    				dropbox_file_path = os.path.join(dropbox_target_path, folder_name, relative_path)
    
    				# 以二进制模式打开文件并上传到 Dropbox
    				with open(local_file_path, "rb") as f:
    					try:
    						dbx.files_upload(f.read(), dropbox_file_path, mode=dropbox.files.WriteMode.overwrite)
    					except dropbox.exceptions.ApiError as e:
    						if isinstance(e.error, dropbox.files.UploadWriteFailed) and e.error.is_conflict:
    							# Handle file name conflict by renaming the file
    							dropbox_file_path = os.path.join(dropbox_target_path, folder_name, "conflict_" + file)
    							dbx.files_upload(f.read(), dropbox_file_path)
    
    		print(f"{folder_name} 文件夹已成功上传到 Dropbox 中的 {dropbox_target_path}。")
    	except AuthError as e:
    		if e.error.is_expired_access_token():
    			# If the access token is expired, attempt to refresh it.
    			new_access_token = refresh_dropbox_access_token(app_key, app_secret, refresh_token)
    			print("Dropbox 已刷新API")
    
    			# Retry the backup with the new access token.
    			upload_folder_to_dropbox(folder_path, new_access_token, dropbox_target_path, app_key, app_secret, refresh_token)
    		else:
    			print("Dropbox授权失败,请检查您的API密钥。")
    
    
    if __name__ == "__main__":
    
    	folder_path_to_upload = "<your_folder_path>"  # 替换为要上传的文件夹路径
    	dropbox_target_path = "<your_dropbox_folder_path>"  # 替换为您希望在 Dropbox 中保存文件夹的目标路径
    	app_key = "<your_app_key>"
    	app_secret = "<your_app_secret>"
    	refresh_token = "<your_refresh_token>"
    
    	upload_folder_to_dropbox(folder_path_to_upload, dropbox_target_path, app_key, app_secret, refresh_token)
    

定时任务

1
crontab -e
1
40 0 * * * /usr/bin/python3 /<your_file_path>/backup_db.py