Vaultwardenを使う

Vaultwarden (旧:Bitwarden_RS) はBitwardenサーバの代替実装です。

Rustで書かれており、Bitwardenより軽量です。

APIに互換性があるためBitwardenのクライアントがそのまま利用できます。

条件

  • Docker, Docker Composeはインストール、稼働済み
  • イメージの起動はdocker-composeを使用する
  • WEBアクセスはnginxでプロキシする
  • データベースはホストで稼働中のMySQLを使用する
  • Vaultwardenの管理画面へのアクセスは特定のIPからのみとする

準備

  1. 公開用URL

    https://vaultwarden.example.jp

  2. Vaultwardenからのお知らせをメールで送る際のメールアカウント (SMTPサーバ名、ポート番号、ユーザー名、パスワードなど)

    項目
    メールアドレス(送信元) vaultwarden@example.jp
    SMTPホスト名 smtp.example.jp
    SMTPポート番号 587
    ユーザー名 vaultwarden@example.jp
    パスワード vaultwarden_smtppass
  3. MySQLデータベースにVaultwarden用のデータベースとアクセスユーザー

    項目
    データベース名 vaultwarden
    データベース文字コード utf8mb4
    ユーザー vaultwarden
    パスワード vaultwarden_dbpass
  4. vaultwarden管理画面にログインするためのトークンを生成

    $ openssl rand -base64 48
    xn8/uHwgf7Lp/9VIltS20Buj/NjZCn+7YCbXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    

手順

  1. Vaultwarden用のディレクトリを作成

    sudo mkdir /opt/vaultwarden
    cd /opt/vaultwarden
    
  2. docker-compose.ymlの作成

    linux環境では、host.docker.internalが利用できないので、linuxでhost.docker.internalを使う – Qiitaより、extra_hostsで定義しておく

    version: '3'
    
    services:
      vaultwarden:
        image: vaultwarden/server:alpine
        env_file:
          - ./vaultwarden.env
        volumes:
          - ./vaultwarden:/data
        ports:
          - "127.0.0.1:10080:80"
          - "127.0.0.1:13012:3012"
        extra_hosts:
          - "host.docker.internal:host-gateway"
    
  3. 永続データ保存用ディレクトリ作成

    $ mkdir vaultwarden
    
  4. 設定ファイルのテンプレートをダウンロードしてvaultwarden.envとして保存

    $ curl -L -o vaultwarden.env https://raw.githubusercontent.com/dani-garcia/vaultwarden/main/.env.template
    
  5. vaultwarden.envを編集して、各項目を設定

    • メール
    • データベース
    • 管理画面用アクセストークン
    • WEBソケット有効化
    • クライアント側からのユーザー新規作成・招待の禁止
    @@ -17,7 +17,7 @@
     # DATABASE_URL=data/db.sqlite3
     ## When using MySQL, specify an appropriate connection URI.
     ## Details: https://docs.diesel.rs/diesel/mysql/struct.MysqlConnection.html
    -# DATABASE_URL=mysql://user:password@host[:port]/database_name
    +DATABASE_URL=mysql://vaultwarden:vaultwarden_dbpass@host.docker.internal/vaultwarden
     ## When using PostgreSQL, specify an appropriate connection URI (recommended)
     ## or keyword/value connection string.
     ## Details:
    @@ -55,7 +55,7 @@
     # WEB_VAULT_ENABLED=true
    
     ## Enables websocket notifications
    -# WEBSOCKET_ENABLED=false
    +WEBSOCKET_ENABLED=true
    
     ## Controls the WebSocket server address and port
     # WEBSOCKET_ADDRESS=0.0.0.0
    @@ -195,7 +195,7 @@
     # EMAIL_TOKEN_SIZE=6
    
     ## Controls if new users can register
    -# SIGNUPS_ALLOWED=true
    +SIGNUPS_ALLOWED=false
    
     ## Controls if new users need to verify their email address upon registration
     ## Note that setting this option to true prevents logins until the email address has been verified!
    @@ -226,14 +226,14 @@
     ## Token for the admin interface, preferably use a long random string
     ## One option is to use 'openssl rand -base64 48'
     ## If not set, the admin panel is disabled
    -# ADMIN_TOKEN=Vy2VyYTTsKPv8W5aEOWUbB/Bt3DEKePbHmI4m9VcemUMS2rEviDowNAFqYi1xjmp
    +ADMIN_TOKEN=xn8/uHwgf7Lp/9VIltS20Buj/NjZCn+7YCbXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    
     ## Enable this to bypass the admin panel security. This option is only
     ## meant to be used with the use of a separate auth layer in front
     # DISABLE_ADMIN_TOKEN=false
    
     ## Invitations org admins to invite users, even when signups are disabled
    -# INVITATIONS_ALLOWED=true
    +INVITATIONS_ALLOWED=false
     ## Name shown in the invitation emails that don't come from a specific organization
     # INVITATION_ORG_NAME=Vaultwarden
    
    @@ -272,7 +272,7 @@
     ## It's recommended to configure this value, otherwise certain functionality might not work,
     ## like attachment downloads, email links and U2F.
     ## For U2F to work, the server must use HTTPS, you can use Let's Encrypt for free certs
    -# DOMAIN=https://bw.domain.tld:8443
    +DOMAIN=https://vaultwarden.example.jp
    
     ## Allowed iframe ancestors (Know the risks!)
     ## https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors
    @@ -333,13 +333,13 @@
     ## Mail specific settings, set SMTP_HOST and SMTP_FROM to enable the mail service.
     ## To make sure the email links are pointing to the correct host, set the DOMAIN variable.
     ## Note: if SMTP_USERNAME is specified, SMTP_PASSWORD is mandatory
    -# SMTP_HOST=smtp.domain.tld
    -# SMTP_FROM=vaultwarden@domain.tld
    +SMTP_HOST=smtp.example.jp
    +SMTP_FROM=vaultwarden@example.jp
     # SMTP_FROM_NAME=Vaultwarden
     # SMTP_SECURITY=starttls # ("starttls", "force_tls", "off") Enable a secure connection. Default is "starttls" (Explicit - ports 587 or 25), "force_tls" (Implicit - port 465) or "off", no encryption (port 25)
    -# SMTP_PORT=587          # Ports 587 (submission) and 25 (smtp) are standard without encryption and with encryption via STARTTLS (Explicit TLS). Port 465 is outdated and used with Implicit TLS.
    -# SMTP_USERNAME=username
    -# SMTP_PASSWORD=password
    +SMTP_PORT=465        # Ports 587 (submission) and 25 (smtp) are standard without encryption and with encryption via STARTTLS (Explicit TLS). Port 465 is outdated and used with Implicit TLS.
    +SMTP_USERNAME=vaultwarden@example.jp
    +SMTP_PASSWORD=vaultwarden_smtppass
     # SMTP_TIMEOUT=15
    
     ## Defaults for SSL is "Plain" and "Login" and nothing for Non-SSL connections.
    
    

    その他、必要に応じてコメントアウトを外して設定

  6. NGINXにプロキシ設定を追加

    Proxy examples · dani-garcia/vaultwarden Wikiを参考にnginxにプロキシ設定を追加する certbotでLet’s EncryptのSSLを追加する

    server {
        server_name vaultwarden.example.jp;
    
        location / {
            proxy_pass http://localhost:10080;
            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;
        }
    
        access_log  /var/log/nginx/vaultwarden-access.log  main;
        error_log  /var/log/nginx/vaultwarden-error.log warn;
    
        listen 443 ssl http2; # managed by Certbot
        ssl_certificate /etc/letsencrypt/live/vaultwarden.example.jp/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/vaultwarden.example.jp/privkey.pem; # managed by Certbot
        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    
        # https://github.com/dani-garcia/vaultwarden/wiki/Proxy-examples
        client_max_body_size 128M;
    
        location /notifications/hub {
            proxy_pass http://localhost:13012;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
    
        location /notifications/hub/negotiate {
            proxy_pass http://localhost:10080;
        }
    
        # Optionally add extra authentication besides the ADMIN_TOKEN
        # If you don't want this, leave this part out
        location /admin {
            # See: https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-http-basic-authentication/
            # auth_basic "Private";
            # auth_basic_user_file /path/to/htpasswd_file;
            allow XXX.XXX.XXX.XXX;
            deny all;
    
            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://localhost:10080;
        }
    }
    
    server {
        if ($host = vaultwarden.example.jp) {
            return 301 https://$host$request_uri;
        } # managed by Certbot
    
        listen 80;
        server_name vaultwarden.example.jp;
        return 404; # managed by Certbot
    }
    
  7. 最終ファイル構成

    /opt/vaultwarden
    |--docker-compose.yml
    |--vaultwarden.env
    |--vaultwarden/
    
  8. Dockerコンテナを起動

    $ docker-compose up -d
    

確認

  1. データベース内にテーブルが作成されているか

  2. URLでアクセスできるか

    https://vaultwarden.example.jp/ image-1790_1

  3. 管理画面(/admin)へのアクセスとADMIN_TOKENを使ってログインできるか

    https://vaultwarden.example.jp/admin/ image-1790_2

    image-1790_3

  4. メールが送信できるか

    SMTP Email Settings タブを開いて、Test SMTP の欄に送り先のメールアドレスを入力して、Send test email ボタンを押下

    image-1790_4 テストメールが届いているか

    image-1790_5

ユーザ登録

設定ファイルでユーザーが新規に登録するのを禁じたので、管理画面から登録する

  1. 管理画面の上部メニューUsersを選択

  2. Invite UserにアカウントIDとなるメールアドレスを入力してInviteボタン押下して招待メールを送信

    image-1790_6

  3. 招待メールの中にあるJoin Organization Nowリンクをクリック

    image-1790_7

    Create Accountボタンを押下

    image-1790_8

  4. 表示名、マスターパスワード、マスターパスワードヒントを設定してユーザー登録を完了させる

    image-1790_9

クライアントから利用する

Bitwardenのクライアントからクライアントをダウンロード、インストール

Chromeの場合

  1. 拡張機能導入直後

    image-1790_10

  2. 左上の歯車をクリックして設定を開き、サーバURLに*VaultwardenのURLを入力し、それ以外の項目は空白のままで保存をクリック

    image-1790_11

  3. ログインから作成したユーザーのメールアドレスとマスターパスワードでログインする

その他

SQLiteからMySQLへ移行

Vaultwardenのデフォルトデータベース(設定ファイルでDATABASE_URLを設定していない場合)はSQLiteのため、MySQLを利用するときはデータを移行することで引継ぎができる

Using the MariaDB (MySQL) Backend · dani-garcia/vaultwarden Wiki · GitHub

  1. VaultwardenのDockerイメージを更新し、最新イメージで起動する (SQLiteデータベースが最新にマイグレーションされる)

  2. DATABASE_URLでMySQLを利用するように設定して、Vaultwardenを起動する (MySQLデータベース上にテーブルが作成される)

  3. 上記Wikiを参考に、SQLiteからMySQL用のINSERT分のSQLを生成する

    1. sqlite3コマンドでINSERT文だけダンプする

      cd /opt/vaultwarden/vaultwarden
      sudo sqlite3 db.sqlite3 .dump | grep "^INSERT INTO" | grep -v "__diesel_schema_migrations" > sqlitedump.sql
      echo "SET FOREIGN_KEY_CHECKS=0;" > mysqldump.sql
      cat sqlitedump.sql >> mysqldump.sql
      
    2. このままだとINSERT INTO "テーブル名" VALUES (......)の形式になっており、MySQLのインポートでSyntaxエラーになるためテーブル名を囲っているクォーテーションを取り除く

      sed -i.bak -E 's/^INSERT INTO "(\w+)" VALUES/INSERT INTO \1 VALUES /g' mysqldump.sql
      
    3. MySQLへインポートさせる

      mysql --default-character-set=utf8 vaultwarden < mysqldump.sql