Bitwarden Server with Nightly Backup (rclone)

Recently, I decided to move away from Lastpass and 1Password both of these services are great. However, I decided to look for an open-sourced alternative and thats when I found out about bitwarden. After some more research I found out that that the OG bitwarden server is pretty resource intensive for a single user. Hence, I decided to deploy a fork of bitwarden built on rust called bitwarden_rs.

However, I was worried as this deployment does not include any backup of bitwarden’s encrypted database. Hence, I decided to use rclone and google drive as a nightly backup solution.

Prerequisites

  • 18.04 Ubuntu Server
  • Docker and Docker-Compose Installed
  • Domain

Step 1: Set-Up

First, create the directory of where you are going to place the docker-compose.yml file and external data directory for your containers.

mkdir bw_docker # Replace bitwarden with any name you want
mkdir bw_docker/data

Docker-compose

Create a docker-compose.yml file based on the code below using your favorite text editor (e.g. nano)
The file originates from bitwarden_rs. However, i did make some minor changes below to store both bitwarden’s and caddy’s data file to the host os’s drive and added LOG_FILE environment variable for fail2ban.

bw_backup

version: "3"

services:
  bitwarden:
    image: bitwardenrs/server
    restart: always
    volumes:
      - ./data/bw:/data
    environment:
      WEBSOCKET_ENABLED: "true" # Required to use websockets
      SIGNUPS_ALLOWED: "true" # set to false to disable signups
      LOG_FILE: /data/bitwarden.log # For fail2ban

  caddy:
    image: abiosoft/caddy
    restart: always
    volumes:
      - ./Caddyfile:/etc/Caddyfile:ro
      - ./data/caddy:/root/.caddy
    ports:
      - 80:80 # needed for Let's Encrypt
      - 443:443
    environment:
      ACME_AGREE: "true" # agree to Let's Encrypt Subscriber Agreement
      DOMAIN: "bitwarden.example.org" # CHANGE THIS! Used for Auto Let's Encrypt SSL
      EMAIL: "[email protected]"  # CHANGE THIS! Optional, provided to Let's Encrypt
      
  bw_backup:
    image: bruceforce/bw_backup
    container_name: bw_backup
    restart: on-failure
    init: true
    depends_on:
      - bitwarden
    volumes:
      - ./data/bw:/data/
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
      - ./backup:/backup_folder/
    environment:
      - DB_FILE=/data/db.sqlite3
      - BACKUP_FILE=/backup_folder/db_backup/backup.sqlite3
      - CRON_TIME=0 5 * * *
      - TIMESTAMP=false
      - UID=0
      - GID=0  

Caddyfile

Similar to above, create a Caddyfile in the bw_docker folder

{$DOMAIN} {
    tls {$EMAIL}

    header / {
        # Enable HTTP Strict Transport Security (HSTS)
        Strict-Transport-Security "max-age=31536000;"
        # Enable cross-site filter (XSS) and tell browser to block detected attacks
        X-XSS-Protection "1; mode=block"
        # Disallow the site to be rendered within a frame (clickjacking protection)
        X-Frame-Options "DENY"
    }

    # The negotiation endpoint is also proxied to Rocket
    proxy /notifications/hub/negotiate bitwarden:80 {
        transparent
    }

    # Notifications redirected to the websockets server
    proxy /notifications/hub bitwarden:3012 {
        websocket
    }

    # Proxy the Root directory to Rocket
    proxy / bitwarden:80 {
        transparent
    }
}

Note

In the event, when the docker-compose is forcibly stopped and there is a change in your domain. You would need to remove all the files in the data folder.

Fail2Ban (Optional, highly recommended)

Follow the guide provide in the bitwarden_rs repo here: Fail2Ban Setup
Note: If fail2ban does not work ensure the the log path is set correctly. (e.g. “/path/to/bitwarden/log” to “~/bw_docker/data/bw/bitwarden.log”)

Step 2: rclone

Next we will be setting up rclone for the nightly backup to google drive.

Installation

curl -O https://downloads.rclone.org/rclone-current-linux-amd64.zip 
unzip rclone-current-linux-amd64.zip cd rclone-*-linux-amd64 
sudo cp rclone /usr/bin/ 

sudo chown root:root /usr/bin/rclone 
sudo chmod 755 /usr/bin/rclone

Configuration

To configure rclone run the following commands

rclone config
  • Press N to create a new remote
  • Type 12 for ‘Google Drive’ – Note that this number may change in the future
  • Follow this guide from rclone to get your client id and secret. Copy and paste these two values when requested by rclone.
  • Type 3 for drive.file (File authorization is revoked when the user deauthorizes the app)
  • Leave root_folder_id and service_account_file as blank
  • Press N for “Use auto config?”. Copy and paste the url and allow the app to access your google drive.
  • And you’re done!

Additionally, you could also create a crypt to encrypt the bitwarden backup data. However, the backup data is already encrypted by bitwarden so it’s your choice if you encrypt it again.

Cron Job

Create a file called bw_backup.sh with the following content

#!/bin/bash

find /path/to/backup/folder/ -type f -name '*.sqlite3' -mtime +7 -exec sudo rm -rf {} \; # to delete files older than 7 days
rclone sync /path/to/backup/folder crypt:/ 

Set the file as an executable by running the following command

chmod a+x bw_backup.sh

Set the cron job

  • Type crontab -e
  • Enter the job below. The job runs 30 mins after bruceforce/bw_backup.
30 5 * * * /path/to/script/bw_backup.sh

Leave a Comment

Your email address will not be published. Required fields are marked *