Install a Vaultwarden Server for Bitwarden

This tutorial will demonstrate how to set up a Vaultwarden server for use with Bitwarden password manager clients. This tutorial will use a Debian 11 server and will install via Podman, using Apache as a reverse proxy. Watch the video version here.

Prerequisites: You will need a server running Debian 11 (visit linode.nots.co, digitalocean.nots.co, or vultr.nots.co if you don't have one.) You will also need a domain name to register an SSL/TLS certificate with Let's Encrypt (visit hover.nots.co if you don't have one.)

Example parameters: In this example, the server URL used for Vaultwarden/Bitwarden will be example.nerdonthestreet.com.


Part 1: Set Up the Vaultwarden Container

Step 1: Log into your server as root (or use sudo) and make sure your server is entirely up-to-date:

apt update
apt full-upgrade

Step 2: Install Podman and MariaDB:

apt install podman mariadb-server

Step 3: Create a directory for Vaultwarden's configuration and data files:

mkdir /vaultwarden-data

Step 4: Secure your MariaDB installation and create a MariaDB/MySQL database for Vaultwarden:

mysql_secure_installation
mariadb
CREATE DATABASE vaultwarden;
CREATE USER 'vaultwarden'@'localhost' IDENTIFIED BY 'Passw0rd';
GRANT ALL PRIVILEGES ON vaultwarden . * TO 'vaultwarden'@'localhost';
quit

Step 5: Fetch and start the Vaultwarden container:

podman run -d --name vaultwarden --network host -v /vaultwarden-data/:/data/:Z -e ROCKET_PORT=8080 -e DATABASE_URL='mysql://vaultwarden:Passw0rd@127.0.0.1:3306/vaultwarden' -e ADMIN_TOKEN='RANDOM_SECRET_STRING' docker://vaultwarden/server:latest

Command explanation:

  • podman : Invokes the podman container application.
  • run : Tells Podman to run a container (it will fetch the container first, if necessary.)
  • -d : Short for --detach; runs the container in the background (detached or daemon mode) and doesn't keep the terminal tied up.
  • --name vaultwarden : Sets the container's name to vaultwarden.
  • --network host : Configures the container to use the physical host's network instead of a virtual network. (This requires running podman in root mode to use.)
    • -p 8080:8080 : (Not required when using --network host!) Configures port 8080 within the container to be mapped to port 8080 on the host. (Even if you are not changing the port number, this configuration is still necessary to allow the host to communicate with the container on that port.)
  • -v /vaultwarden/:/data/:Z : Configures a "volume" to be mounted in the container. /vaultwarden/ is the directory on the host; /data/ is the directory within the container where it will be mounted (and /data/ is the default path that Vaultwarden will store its data in); :Z gives the container write permissions for the volume, and does not allow other containers to mount the volume (using a lowercase :z instead would allow other containers to mount the volume.)
  • -e ROCKET_PORT=8080 : Sets the ROCKET_PORT environment variable, which Vaultwarden will read to decide what port to serve itself on.
  • -e DATABASE_URL='mysql://vaultwarden:Passw0rd@127.0.0.1:3306/vaultwarden : Sets the DATABASE_URL environment variable, which Vaultwarden will read to determine how to connect to its database. The URL syntax is mysql://username:password@IP:port/dbname.
  • -e ADMIN_TOKEN='RANDOM_SECRET_STRING' : Sets the ADMIN_TOKEN environment variable, which Vaultwarden will use for authentication when performing administrative tasks.
  • docker://vaultwarden/server:latest : Specifies what container image for Podman to start. The docker:// prefix tells Podman to fetch an image from Docker Hub. From there, the syntax is organization/application:version.

Part 2: Set Up an Apache Reverse Proxy

Step 6: Install Apache httpd and Let's Encrypt certbot:

apt install apache2 certbot python3-certbot-apache

Step 7: Create an HTTP virtual host:

nano /etc/apache2/sites-available/vaultwarden.conf

Set the following configuration (type the middle line manually):

<VirtualHost *:80>
        ServerName example.nerdonthestreet.com
</VirtualHost>

Step 6: Enable the HTTP virtual host, then reload Apache to activate it:

a2ensite vaultwarden
systemctl reload apache2

Step 7: Use Certbot to obtain an SSL/TLS certificate and configure an HTTPS virtual host:

certbot --apache

Step 7: Configure the HTTPS virtual host to forward traffic to and from the Podman container:

nano /etc/apache2/sites-available/vaultwarden-le-ssl.conf

Add the following configuration:

RewriteEngine On
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule /notifications/hub(.*) ws://localhost:3012/$1 [P,L]
ProxyPass / http://localhost:8080/

ProxyPreserveHost On
ProxyRequests Off
RequestHeader set X-Real-IP %{REMOTE_ADDR}s

Step 8: Enable the necessary Apache modules to rewrite headers and proxy traffic to the container, then restart Apache to load the new modules and the updated virtual host configuration:

a2enmod proxy_http proxy_wstunnel headers systemctl restart apache2

Step 9: Access the configured URL in a web browser and proceed through the Bitwarden setup wizard.

Part 3: Configure the Vaultwarden Container to Start on Boot

Step 10: Confirm that the Apache service is enabled (starts on boot):

systemctl status apache2

Step 11: Create a systemd service file for the Vaultwarden container:

nano /etc/systemd/system/container-vaultwarden.service

Add the following configuration:

[Unit]
Description=Podman Container: vaultwarden
Documentation=man:podman
Wants=network.target
After=network-online.target

[Service]
Type=forking
PIDFile=%t/%N.pid
Restart=on-failure
TimeoutStopSec=70
# Commands to be executed by systemd:
Environment=PODMAN_SYSTEMD_UNIT=%n
ExecStartPre=/bin/rm -f %t/%N.pid %t/%N.ctr-id
ExecStart=/usr/bin/podman run --replace --conmon-pidfile %t/%N.pid --cidfile %t/%N.ctr-id -d --name vaultwarden --network host -v /vaultwarden-data/:/data/:Z -e ROCKET_PORT=8080 -e DATABASE_URL='mysql://vaultwarden:Passw0rd@127.0.0.1:3306/vaultwarden' -e ADMIN_TOKEN='RANDOM_SECRET_STRING' docker://vaultwarden/server:latest
# Only run if the service started successfully:
ExecStop=/usr/bin/podman stop -i -t 10 --cidfile %t/%N.ctr-id
# Run even if the service failed to start:
ExecStopPost=/usr/bin/podman rm -i -f --cidfile %t/%N.ctr-id
ExecStopPost=rm %t/%N.ctr-id

[Install]
WantedBy=multi-user.target default.target

Step 12: Reload systemd to detect the new unit file:

systemctl daemon-reload

Step 13: Stop and remove the manually-started container from Part 1:

podman stop vaultwarden podman rm vaultwarden

Step 14: Enable and start the systemd service for the container:

systemctl enable --now container-vaultwarden.service

Step 15: Reboot and confirm that the Bitwarden instance comes online automatically:

systemctl reboot

Part 4: Update the Vaultwarden Container

This part does not need to be run immediately after finishing the previous parts.

Step 1: Stop the container service:

systemctl stop container-vaultwarden

Step 2: Pull the latest version of the Vaultwarden Docker image:

podman pull docker://vaultwarden/server:latest

Step 3: Start the container service:

systemctl start container-vaultwarden

There are no pages beneath this page

Expand: Discussion Discussion (0 posts)