onareのBlog

ラズパイでVaultwardenをdocker上でホストしてパスワード管理をやってみる

はじめに

皆さん、パスワードマネージャー使ってますか?とても便利なので仕事でもプライベートでも使っている人は多いともいます。最近VaultWardenというBitwardenの API と互換のある Rust で書かれた OSS があることを知りました。Bitwarden の有料機能も基本的に使える(SSO に関しては残念ながら公式採用されていない)ようなので、docker コンテナとしてラズパイでホストしてみたいと思います。

この記事では以下のことは紹介しません。

  • ssl 化
  • ドメイン取得
  • port 開放など

最終構成

早速ですが最終的な docker compose を共有します。Vaultwarden はwikiがかなり充実しているので、一度見ておくことをおすすめします。

version: "3.8"
services:
  nginx:
    container_name: nginx
    image: nginx:latest
    volumes:
      - ./data/nginx/conf.d:/etc/nginx/conf.d
      - ./data/nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./data/letsencrypt:/etc/letsencrypt
    restart: always
    environment:
      PUID: 1000
      PGID: 1000
      TZ: Asia/Tokyo
    ports:
      - "443:443"
    depends_on:
      - vaultwarden

  mysql:
    container_name: mysql
    image: mariadb:latest
    volumes:
      - ./data/db:/var/lib/mysql
    restart: always
    ports:
      - "3306:3306"
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_DATABASE=vaultwarden
      - MYSQL_USER=vaultwarden
      - MYSQL_PASSWORD=vaultwarden
  vaultwarden:
    container_name: vaultwarden
    image: vaultwarden/server:latest
    restart: always
    environment:
      - DOMAIN=https://example.com
      - DATABASE_URL='mysql://vaultwarden:vaultwarden@mysql/vaultwarden'
      - ADMIN_TOKEN='<TOKEN>'
      - RUST_BACKTRACE=1
    volumes:
      - ./data/vaultwarden:/data
    depends_on:
      - mysql
  vaultwarden-backup:
    container_name: vaultwarden-backup
    image: ttionya/vaultwarden-backup:latest
    restart: always
    environment:
      - BACKUP_KEEP_DAYS=1
      - CRON='0 * * * *'
      - DB_TYPE=mysql
      - MYSQL_HOST=mysql
      - MYSQL_PASSWORD=vaultwarden
    volumes:
      - ./data/vaultwarden:/bitwarden/data
      - ./data/vaultwarden-rclone-data:/config
    depends_on:
      - vaultwarden

Nginx で SSL を終端して、Vaultwarden へリバースプロキシさせます。mysql の docker イメージはラズパイ用がないので、mysql と互換のある mariaDB を使います。Vaultwarden は他の DB もサポートしているので、コンテナの数を減らしたい場合は SQLite を使えます。

vaultwarden の設定詳細

  • DOMAIN

    • host する vaultwarden の domain を設定します。
  • DATABASE_URL

    • 接続する DB への URL を記述します。SQLite を使う場合は不要です。

    • mysql の場合以下のように指定をします。

      •   'mysql://<user>:<password>@mysql/vaultwarden[?ssl_mode=(disabled|required|preferred)&ssl_ca=/path/to/cart.(crt|pem)]'
        
  • ADMIN_TOKEN

    • 管理画面を有効にするために設定します。基本は OFF にしておき、必要になったら ON にすることをおすすめします。

    • token の値は何でも OK ですが、セキュアランダムな値にするのがお勧めされています。

    • 簡単な設定では 次のコマンドが紹介されています。

      •   openssl rand -base64 48
        
    • 一方でもっとセキュアな方法がお勧めされています。

      •   docker run --rm -it vaultwarden/server /vaultwarden hash --preset owasp
        
    • この方法ではパスワードが 2 回聞かれるので、適切な値を入力すると token が生成されます。

  • SMTP の設定

    • 上記 docker compose yaml では設定していませんが、vaultwarden が email を送信できるようにするために SMTP 設定を追加できます。
    • 詳細はwikiを確認してください。
    • 私は test 用で Gmail を設定しました。その場合はGoogle account でアプリパスワードを発行する必要があります。
    • 発行したアプリパスワードと gmail アドレスを以下のように設定します。
    • SMTP_HOST=smtp.gmail.comSMTP_PORT=465 SMTP_SECURITY=force_tls SMTP_USERNAME=<mail-address> SMTP_PASSWORD=<less-secure-app-password>

backup の設定詳細

  • wikiによれば、backup が必要な項目は以下の 3 つです

    • 環境変数
    • data  ディレクトリ
    • Database
  • すべて手動でやってもいいですが、vaultwarden-backupを使えば rclone を使ってクラウドにバックアップを保存できます

  • rclone の設定についてはこちらの記事を参照ください。

  • backup から復元するにはクラウドにある zip ファイルを local に配置して restore 用の docker container にマウントする必要があります。

  •   docker run --rm -it \
        -v <復元したdataを配置したいディレクトリ>:/bitwarden/data/ \
        -v <Rcloneの設定ファイルが配置されているディレクトリ>:/config/ \
        -v <バックアップファイルを配置したディレクトリ>:/bitwarden/restore/ \
        -e DB_TYPE=mysql \
        -e MYSQL_HOST=mysql \
        -e MYSQL_PASSWORD=vaultwarden \
        ttionya/vaultwarden-backup:latest restore \
        --zip-file "/bitwarden/restore/<バックアップファイル名>"
    

nginx の設定詳細

  • Proxy の設定についてはwikiにサンプルがあるので、それを使います。特に特別な設定は必要ありません。
  • websocket の設定は使っていなければ削除しても大丈夫です。

upstream vaultwarden-default {
  zone vaultwarden-default 64k;
  server http://vaultwarden:80;
  keepalive 2;
}

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      "";
}

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

    if ($host = example.com) {
        return 301 https://$host$request_uri;
    }
    return 404;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;
    server_name example.com;

    # Specify SSL Config when needed
    ssl_certificate /path/to/certificate/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /path/to/certificate/letsencrypt/live/example.com/privkey.pem;
    ssl_trusted_certificate /path/to/certificate/letsencrypt/live/example.com/fullchain.pem;

    client_max_body_size 525M;

    location / {
      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;
    }
}

関連記事