Vaultwarden #

Introduction #

I began using password managers with my installation of LastPass in September of 2017. I became obsessed with securing my accounts following this: I would use 2FA and generated complex passwords at any chance I got. I transitioned away from an (unfortunately) common practice of using the same, or a variation of the same password across multiple services.

However, most of this was done using LastPass. As time passed, I became more discontent and disappointed in the lack of features and closed-source nature of LastPass.

Eventually, I came across Bitwarden and the Vaultwarden project (formerly known as bitwarden_rs) and went through the process of building it from binary rather than the standard practice of using Docker.

Why? Although Docker was obviously the easiest choice to deploy a Vaultwarden instance, I just liked the idea and challenge of building it from binary and launching it myself.

… also I’m still not sold on the idea of containerized applications just yet.

Installation #

Prerequisites #

This doc uses a base install of Linux Debian 10, but the process should be similar on other distributions.

Begin with installing a couple base programs using your package manager.
Debian and similar distros can use apt:

apt install git wget curl build-essential pkg-config openssl libssl-dev

Install one of the following database backends:


apt install libsqlite3-dev


apt install libmariadb-dev-compat libmariadb-dev


apt install libpq-dev pkg-config

Create a user account for Bitwarden and follow the prompts:

adduser bitwarden

Switch to the new ‘bitwarden’ user and install Rust and Cargo:

su bitwarden
curl -sSf | sh

To use Cargo, either restart your current shell or run:

source "$HOME/.cargo/env"

Building vaultwarden #

While still in the bitwarden user account, begin by cloning the repository into your home directory, then checking out the latest tag (e.g. 1.27.0):

cd ~
git clone && cd vaultwarden
git checkout tags/1.27.0

Now build using cargo, and specify which backend you are using:

  • SQLite:
cargo clean && cargo build --features sqlite --release
  • MySQL:
cargo clean && cargo build --features mysql --release
  • PostgreSQL:
cargo clean && cargo build --features postgresql --release
  • All backends:
cargo clean && cargo build --features sqlite,mysql,postgresql --release

Now you can return back to the original user:


Setting up environment #

Most of these are not necessarily required and are customizable by the user, depending on the systemd file detailed later.
Move the vaultwarden binary to /usr/bin/

mv /home/bitwarden/vaultwarden/target/release/vaultwarden /usr/bin/

Copy the template environment file in the base directory of the repo to /etc/

cp /home/bitwarden/vaultwarden/.env.template /etc/vaultwarden.env

Create a directory under /var/lib/ to store the vaultwarden data:

mkdir -p /var/lib/vaultwarden/data

Installing the web-vault #

Main page on vaultwarden’s GitHub wiki

Now from here, there’s two options. You can choose to compile the web-vault yourself (manually) or you can download an already compiled version:

  1. Go to the pre-patched releases page and download the latest build
  1. Extract the contents of the tar
tar -xvf bw_web_vX.XX.XX.tar.gz
  1. Move the extracted web-vault directory to /var/lib/vaultwarden/
mv web-vault/ /var/lib/vaultwarden/
  1. Clone the vaultwarden web-vault repository:
git clone bw_web_builds
cd bw_web_builds
  1. Use one of the following options to build the web-vault:
  • Using docker to build and extract the web-vault:
make docker-extract
  • Or using the host’s npm and node:
make full

After installing the web-vault, change the owner of the directory and its children to bitwarden:

chown -R bitwarden:bitwarden /var/lib/vaultwarden/

Pre-launch configuration #

Begin by creating and setting up a database corresponding to the backend you chose earlier:

If you have not set up MariaDB, do that first:


Then connect to mysql:


Create a new database:

CREATE DATABASE bitwarden CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Then create a new database user and grant rights:

CREATE USER 'bitwarden'@'localhost' IDENTIFIED BY 'yourpassword';
GRANT ALL ON bitwarden.* TO 'bitwarden'@'localhost';

If you are using MySQL v8.x, you need to create the user like this:

-- Use this on MySQLv8 installations
CREATE USER 'bitwarden'@'localhost' IDENTIFIED WITH mysql_native_password BY 'yourpassword';
GRANT ALL ON bitwarden.* TO 'bitwarden'@'localhost';

If you created the user already and want to change the password type:

-- Change password type from caching_sha2_password to native
ALTER USER 'bitwarden'@'localhost' IDENTIFIED WITH mysql_native_password BY 'yourpassword';

I do not use PostgreSQL, and cannot find a guide that uses PostgreSQL to quickly follow. Unfortunately, I do not have the time to learn how to use PostgreSQL meaning that I cannot fill this section currently. If you would like to help me complete this, please contact me.

Similarly, I have found little official documentation or any guides using SQLite3 as a backend for vaultwarden. If you would like to help me complete this, please contact me.

Now, navigate to the environment file we copied into /etc/ earlier with your favorite text editor, I will be using nano:

nano /etc/vaultwarden.env

There’s a lot of options, and it’s up to you personally to tune the instance to your liking, but to get it up and running, we’ll only need to change a few.

The template environment file does a great job at explaining what each option does, so I won’t go into much depth here. The following is an example of what needs to change before launching for the first time.


As recommended, change the admin token to a long, random string. You can use the following command to generate one:

openssl rand -base64 48

Setting up systemd service #

In order to launch vaultwarden on system startup, and have access to the other systemd tools, it’s required to have a .service file:

nano /etc/systemd/system/bitwarden.service

The official vaultwarden wiki provides a good template that this doc has been following, which requires minimal change if you have been following this doc verbatim:

Description=Bitwarden Server (Rust Edition)
# If you use a database like mariadb,mysql or postgresql, 
# you have to add them like the following and uncomment them 
# by removing the `# ` before it. This makes sure that your 
# database server is started before vaultwarden ("After") and has 
# started successfully before starting vaultwarden ("Requires").

# Only sqlite

# MariaDB
# mariadb.service
# Requires=mariadb.service

# Mysql
# mysqld.service
# Requires=mysqld.service

# PostgreSQL
# postgresql.service
# Requires=postgresql.service

# The user/group vaultwarden is run under. the working directory (see below) should allow write and read access to this user/group
# The location of the .env file for configuration
# The location of the compiled binary
# Set reasonable connection and process limits
# Isolate vaultwarden from the rest of the system
# Only allow writes to the following directory and set it to the working directory (user and password data are stored here)
# Allow vaultwarden to bind ports in the range of 0-1024


After making your changes, reload systemd:

systemctl daemon-reload

From here, you can now start, stop, and restart the service. To enable autostart, run:

systemctl enable bitwarden.service

Initial start #

Now that the service file has been configured, you can start bitwarden using systemd:

systemctl start bitwarden

Checking the status with

systemctl status bitwarden

should yield something similar to:

● bitwarden.service - Bitwarden Server (Rust Edition)
   Loaded: loaded (/etc/systemd/system/bitwarden.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2021-07-21 02:35:27 EDT; 1s ago
 Main PID: 12345 (vaultwarden)
    Tasks: 14 (limit: 9511)
   Memory: 6.1M
   CGroup: /system.slice/bitwarden.service
           └─16593 /usr/bin/vaultwarden

Jul 21 02:35:28 debian-server vaultwarden[16593]: Running migration 20200409235005
Jul 21 02:35:28 debian-server vaultwarden[16593]: Running migration 20200701214531
Jul 21 02:35:28 debian-server vaultwarden[16593]: Running migration 20200802025025
Jul 21 02:35:28 debian-server vaultwarden[16593]: Running migration 20201130224000
Jul 21 02:35:28 debian-server vaultwarden[16593]: Running migration 20201209173101
Jul 21 02:35:28 debian-server vaultwarden[16593]: Running migration 20210311190243
Jul 21 02:35:28 debian-server vaultwarden[16593]: Running migration 20210430233251
Jul 21 02:35:28 debian-server vaultwarden[16593]: Running migration 20210511205202
Jul 21 02:35:28 debian-server vaultwarden[16593]: Running migration 20210701203140
Jul 21 02:35:28 debian-server vaultwarden[16593]: [2021-07-21 02:35:28.209][start][INFO] Rocket has launched from

You should now be able to access the instance from your web browser via http://<SERVER>:8000/.

From here, you should configure the rest of your environment variables from the admin page (if you enabled it by generating an admin token during the pre-launch configuration) or by editing the .env file directly:

nano /etc/vaultwarden.env

Extras #

Setting up webserver #

The recommended method of accessing the vaultwarden instance is via reverse proxy.

You can accomplish this by either installing:

  • Apache
apt install apache2
  • Nginx
apt install nginx

I also highly recommend certbot, which allows you use Let’s Encrypt’s free SSL certificates to use HTTPS:

apt install certbot

Proxy Examples #


Enable mod_proxy_wstunnel and mod_proxy_http:

a2enmod proxy_wstunnel proxy_http
systemctl restart apache2

Then create a new virtual host file for bitwarden:

nano /etc/apache2/bitwarden.conf

And edit the following example to your liking:

<VirtualHost *:443>
    SSLEngine on
    ServerName bitwarden.$hostname.$domainname

    SSLCertificateFile ${SSLCERTIFICATE}
    SSLCertificateKeyFile ${SSLKEY}
    SSLCACertificateFile ${SSLCA}

    ErrorLog \${APACHE_LOG_DIR}/bitwarden-error.log
    CustomLog \${APACHE_LOG_DIR}/bitwarden-access.log combined

    <IfModule mod_proxy.c>
            RewriteEngine On
            RewriteCond %{HTTP:Upgrade} =websocket [NC]
            RewriteRule /notifications/hub(.*) ws://localhost:3012/$1 [P,L]
            ProxyPass / http://localhost:8000/
            ProxyPassReverse / http://localhost:8000/
            RemoteIPHeader X-Forwarded-For
server {

    server_name bitwarden.$hostname.$domainname;

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

    location /notifications/hub/negotiate {
        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:8000;

    location /notifications/hub {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Forwarded $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_pass http://localhost:3012;

    listen [::]:443 ssl;
    listen 443 ssl;
    ssl_certificate ${SSLCERTIFICATE};
    ssl_certificate_key ${SSLKEY};

server {
    if ($host = bitwarden.$hostname.$domainname) {
        return 301 https://$host$request_uri;

    server_name bitwarden.$hostname.$domainname;

    listen [::]:80;
    listen 80;
    return 404;