Skip to content
Author Nejat Hakan
eMail nejat.hakan@outlook.de
PayPal Me https://paypal.me/nejathakan


Password Manager Vaultwarden

Introduction

Welcome to this comprehensive guide on self-hosting Vaultwarden, a lightweight, open-source password manager compatible with the official Bitwarden clients. Bitwarden itself is a highly respected password management solution, offering features like secure password storage, generation, and sharing. Vaultwarden provides an alternative server implementation written in Rust, making it significantly less resource-intensive than the official server (which requires Microsoft SQL Server and ASP.NET Core). This makes Vaultwarden an ideal choice for individuals, families, or small organizations looking to host their own password management solution on modest hardware, like a Raspberry Pi or a small Virtual Private Server (VPS).

Self-hosting your password manager offers several compelling advantages:

  1. Data Sovereignty: You retain complete control over your sensitive password data. It resides on hardware you manage, not on third-party servers. This eliminates reliance on the security practices and privacy policies of external companies.
  2. Enhanced Privacy: By hosting it yourself, you minimize the metadata footprint associated with cloud services. Your usage patterns, login times, and IP addresses are not logged by an external provider.
  3. Cost-Effectiveness: While official Bitwarden offers free tiers, premium features require a subscription. Vaultwarden enables access to many of these premium features (like organization support, TOTP authenticator key storage, file attachments) without any subscription fees, aside from your hosting costs (which can be minimal).
  4. Customization and Flexibility: You have greater control over the server configuration, backup strategies, and update schedules. You can tailor the environment precisely to your needs.
  5. Learning Opportunity: Setting up and managing Vaultwarden provides invaluable hands-on experience with technologies like Docker, reverse proxies, HTTPS/SSL certificates, data persistence, and server administration – skills highly relevant in modern computing.

However, self-hosting also comes with responsibilities:

  • Security: You are solely responsible for securing the server, keeping the operating system and Vaultwarden software updated, managing firewalls, and implementing HTTPS.
  • Backups: You must implement a robust backup and recovery strategy to prevent data loss.
  • Maintenance: Regular updates and monitoring are required to ensure smooth operation and security.

This guide will walk you through the process, starting with the basics and progressing to more advanced configurations. We assume you have a target server environment (like a Linux VPS or a home server) and basic familiarity with the command line. Each theoretical section is followed by a practical workshop to solidify your understanding. Let's begin securing your digital life with your own Vaultwarden instance!


1. Getting Started with Docker and Vaultwarden

This initial section focuses on the foundational steps: understanding the containerization technology we'll use (Docker) and deploying a basic Vaultwarden instance. This provides a quick win and familiarizes you with the core components.

Understanding Docker Basics

Before deploying Vaultwarden, it's essential to grasp the basics of Docker, the containerization platform we'll be using. Docker simplifies the process of packaging, distributing, and running applications by using containers.

Think of a container as a lightweight, standalone, executable package of software that includes everything needed to run an application: code, runtime, system tools, system libraries, and settings. Unlike traditional Virtual Machines (VMs) which virtualize the entire hardware stack including the operating system, containers virtualize the operating system level. They run directly on the host machine's kernel but are isolated from each other and the host system.

Key Docker concepts:

  • Docker Engine: The core component that runs on your host machine. It builds and runs containers.
  • Image: A read-only template containing the application and its dependencies. Images are used to create containers. You can think of an image as a blueprint or a class in object-oriented programming. Vaultwarden provides an official Docker image.
  • Container: A runnable instance of an image. You can create, start, stop, move, or delete containers. It's the actual running application. Think of a container as an object or instance created from a class.
  • Dockerfile: A text file containing instructions on how to build a Docker image. It specifies the base image, commands to run, files to copy, ports to expose, etc. While you don't need to write a Dockerfile to run Vaultwarden (we'll use a pre-built image), understanding its purpose is helpful.
  • Docker Hub/Registries: A cloud-based repository (like Docker Hub) where Docker images are stored and shared. This is where we will pull the official Vaultwarden image from.

Why Docker for Vaultwarden?

  • Simplicity: Docker encapsulates Vaultwarden and all its dependencies. You don't need to manually install Rust, web servers, or specific libraries on your host system.
  • Consistency: The Vaultwarden container will run identically regardless of the underlying host OS environment (as long as Docker is installed), reducing compatibility issues.
  • Isolation: Vaultwarden runs in its own isolated environment, preventing conflicts with other applications running on the same server.
  • Ease of Updates: Updating Vaultwarden often involves simply pulling the latest image and recreating the container.

Understanding these fundamentals will make the deployment process much clearer.

Workshop Docker Installation and Hello World

Goal: Install Docker Engine on your Linux server and verify the installation by running a simple test container.

Prerequisites:

  • A Linux server (e.g., Ubuntu 20.04/22.04 or Debian 10/11).
  • Access to the server via SSH or direct console.
  • Root or sudo privileges.

Steps:

  1. Update Package Index: Ensure your server's package list is up-to-date. Open your terminal and run:

    sudo apt update
    
    Explanation: sudo executes the command with administrative privileges. apt update refreshes the list of available packages from the repositories defined in your system's sources lists.

  2. Install Prerequisite Packages: Docker requires a few packages to allow apt to use repositories over HTTPS:

    sudo apt install -y apt-transport-https ca-certificates curl software-properties-common gnupg
    
    Explanation:

    • apt install -y: Installs packages; the -y flag automatically confirms any prompts.
    • apt-transport-https: Allows apt to retrieve packages over HTTPS.
    • ca-certificates: Allows the system to check security certificates.
    • curl: A tool to transfer data from or to a server (used to download the GPG key).
    • software-properties-common: Adds helper scripts for managing software sources.
    • gnupg: GNU Privacy Guard, used for securely signing software packages.
  3. Add Docker's Official GPG Key: Download and add Docker's official GPG key to ensure the authenticity of the Docker packages:

    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
    
    Explanation:

    • curl -fsSL ...: Downloads the key. -f fails silently, -s is silent mode, -S shows errors, -L follows redirects.
    • |: Pipes the downloaded key to the next command.
    • sudo gpg --dearmor -o ...: Decrypts and converts the key (--dearmor) and saves it (-o) to the specified location for apt to use.
  4. Set Up the Stable Repository: Add the official Docker repository to your system's sources. Replace $(lsb_release -cs) with your distribution's codename if needed (e.g., focal for Ubuntu 20.04, jammy for Ubuntu 22.04, bullseye for Debian 11).

    echo \
      "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
      $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    
    Explanation:

    • echo "...": Creates the repository definition string.
    • $(dpkg --print-architecture): Automatically determines your system's architecture (e.g., amd64, arm64).
    • signed-by=...: Tells apt where to find the GPG key for verifying packages from this repo.
    • $(lsb_release -cs): Automatically determines your Ubuntu/Debian version codename.
    • stable: Specifies that we want the stable release channel of Docker.
    • | sudo tee ...: Writes the string to the specified file (/etc/apt/sources.list.d/docker.list) with sudo privileges. > /dev/null discards the standard output of tee.
  5. Install Docker Engine: Update the package index again (to include the new Docker repo) and install Docker Engine, Containerd, and Docker Compose:

    sudo apt update
    sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
    
    Explanation: Installs the Docker Community Edition (docker-ce), the command-line interface (docker-ce-cli), the containerd runtime (containerd.io), and the Docker Compose plugin (docker-compose-plugin).

  6. Verify Docker Installation: Run the hello-world image to confirm Docker is installed and working correctly:

    sudo docker run hello-world
    
    Explanation: docker run hello-world tells Docker Engine to:

    • Check if the hello-world image is available locally.
    • If not, pull it from Docker Hub.
    • Create and run a new container based on that image.
    • The hello-world container simply prints a confirmation message and exits.

    You should see output similar to:

    Unable to find image 'hello-world:latest' locally
    latest: Pulling from library/hello-world
    [...]
    Status: Downloaded newer image for hello-world:latest
    
    Hello from Docker!
    This message shows that your installation appears to be working correctly.
    [...]
    

  7. (Optional but Recommended) Add User to Docker Group: To run Docker commands without sudo every time, add your user to the docker group. Note: This has security implications, as users in this group effectively have root-equivalent privileges.

    sudo usermod -aG docker $USER
    
    Explanation: usermod -aG docker $USER adds (-a) your current user ($USER) to the supplementary group (-G) named docker.

    • Important: You need to log out and log back in (or run newgrp docker) for this change to take effect. After logging back in, test with docker run hello-world (without sudo).

Outcome: You have successfully installed Docker Engine and verified its operation. You are now ready to deploy containerized applications like Vaultwarden.

Deploying Vaultwarden with Docker Run

The simplest way to get Vaultwarden running is using the docker run command. This command pulls the official vaultwarden/server image from Docker Hub and starts a container from it.

Here's a breakdown of a basic docker run command for Vaultwarden:

docker run -d --name vaultwarden -p 8080:80 -v vw-data:/data/ vaultwarden/server:latest

Let's dissect this command:

  • docker run: The fundamental command to create and start a new container.
  • -d or --detach: Runs the container in the background (detached mode) and prints the container ID. Without this, your terminal would be attached to the container's log output.
  • --name vaultwarden: Assigns a specific, human-readable name (vaultwarden) to the container. This makes it easier to manage (e.g., docker stop vaultwarden). If you don't specify a name, Docker assigns a random one.
  • -p 8080:80: This maps ports between the host machine and the container. The format is HOST_PORT:CONTAINER_PORT.
    • 80: Inside the container, the Vaultwarden web server listens on port 80 by default.
    • 8080: This is the port on your host machine that will forward traffic to the container's port 80. So, you'll access Vaultwarden via http://<your_server_ip>:8080. You can change 8080 to another available port on your host if needed (e.g., -p 8000:80). Avoid using port 80 directly on the host at this stage, as it's often reserved or might be used by a reverse proxy later.
  • -v vw-data:/data/: This is crucial for data persistence. It mounts a Docker volume named vw-data to the /data directory inside the container.
    • /data: This is the directory inside the container where Vaultwarden stores all its persistent data (database, attachments, configuration, keys).
    • vw-data: This is the name of the Docker named volume on your host system. Docker manages this volume. When the container is stopped, removed, or updated, the data in the vw-data volume persists. If you omit this -v flag, all your Vaultwarden data (users, passwords, settings) will be lost when the container is removed. We will cover volumes in more detail in the intermediate section, but it's good practice to include it from the start.
  • vaultwarden/server:latest: This specifies the image to use.
    • vaultwarden/server: The name of the official Vaultwarden image on Docker Hub.
    • :latest: The tag specifying which version of the image to use. latest pulls the most recently pushed stable version. While convenient for starting, it's generally recommended to pin to a specific version tag (e.g., vaultwarden/server:1.30.1) in production for more predictable updates.

When you execute this command, Docker will:

  1. Check if the vaultwarden/server:latest image exists locally.
  2. If not, download (pull) it from Docker Hub.
  3. Create a Docker named volume called vw-data if it doesn't already exist.
  4. Create a new container named vaultwarden.
  5. Configure port mapping (host 8080 -> container 80).
  6. Mount the vw-data volume to /data inside the container.
  7. Start the container in the background.

This basic deployment gets Vaultwarden running, but it lacks HTTPS encryption, which is essential for security. We will address this in the intermediate section.

Workshop Basic Vaultwarden Deployment

Goal:
Deploy a functional Vaultwarden instance using the docker run command and access its web interface.

Prerequisites:

  • Docker installed and running (from the previous workshop).
  • Access to the server's terminal.
  • Port 8080 (or your chosen host port) must be open on your server's firewall if accessing remotely.

Steps:

  1. Pull the Latest Vaultwarden Image (Optional but Recommended): While docker run will pull the image if it's not present, pulling it explicitly first can be good practice.

    docker pull vaultwarden/server:latest
    
    Explanation: This command downloads the latest tagged image for vaultwarden/server from Docker Hub to your local machine.

  2. Run the Vaultwarden Container: Execute the docker run command discussed previously. We'll use port 8080 on the host.

    docker run -d --name vaultwarden -p 8080:80 -v vw-data:/data/ vaultwarden/server:latest
    
    Explanation: As detailed in the theory section, this starts Vaultwarden in detached mode, names it vaultwarden, maps host port 8080 to container port 80, uses a named volume vw-data for persistence, and uses the latest server image.

  3. Verify the Container is Running: Check the status of your Docker containers.

    docker ps
    
    Explanation: docker ps lists all currently running containers. You should see an entry for vaultwarden, showing it's Up and listing the port mapping (0.0.0.0:8080->80/tcp).

    • If you don't see it, use docker ps -a to list all containers (including stopped ones) and docker logs vaultwarden to check for errors.
  4. Check Container Logs (Optional): To see the startup messages from Vaultwarden:

    docker logs vaultwarden
    
    Explanation: This command fetches and displays the standard output and standard error streams from the vaultwarden container. You should see messages indicating the Rocket web server has started.

  5. Access the Vaultwarden Web UI: Open a web browser on your computer (or any device that can reach your server). Navigate to: http://<your_server_ip>:8080 Replace <your_server_ip> with the actual IP address of the server where you ran the Docker command.

    • If you are running this on your local machine, you might use http://localhost:8080 or http://127.0.0.1:8080.
    • If you are using a cloud VPS, use its public IP address.
    • Firewall Note: If you cannot connect, ensure that port 8080 (or the host port you chose) is allowed through any firewalls running on the server (e.g., ufw, firewalld) or provided by your cloud provider. For ufw: sudo ufw allow 8080/tcp.

Outcome: You should see the Vaultwarden web vault interface load in your browser, presenting you with options to log in or create an account. You have successfully deployed a basic Vaultwarden instance! The next step is to create your account.

Initial Vaultwarden Setup and Account Creation

Once you have accessed the Vaultwarden web UI via http://<your_server_ip>:8080, the first and most crucial step is to create your primary account. This account will serve as your entry point to managing your passwords.

Key Considerations:

  • Master Password: This is the single most important piece of information.
    • Complexity: Choose a very strong, unique master password. It should ideally be long (15+ characters), complex (mix of upper/lower case letters, numbers, symbols), and not reused anywhere else. Consider using a passphrase (a sequence of random words) for memorability and strength.
    • Security: Vaultwarden (like Bitwarden) uses your master password to encrypt and decrypt your vault data locally on your client device. The server never stores your master password directly, only a heavily salted and hashed version used for authentication. If you forget your master password, there is no recovery mechanism provided by Vaultwarden. Your encrypted data will be inaccessible. Store your master password securely (e.g., written down in multiple secure physical locations).
    • Password Hint: You can optionally provide a hint. Make sure the hint doesn't give away the password itself.
  • Email Address: This email address is used for account identification and potential communication features (like email verification if enabled, though not by default in the basic setup).
  • First User Significance: By default, Vaultwarden allows anyone who can access the web UI to create an account (SIGNUPS_ALLOWED=true). The first user created doesn't automatically gain special administrative privileges within the Vaultwarden application itself (though there is a separate admin panel we'll cover later). It's recommended to disable open signups after you've created your necessary accounts, which we will cover in the advanced section.

The Creation Process:

  1. Navigate: Go to http://<your_server_ip>:8080.
  2. Click "Create Account": Locate and click the "Create Account" button or link on the main page.
  3. Fill in the Form:
    • Enter your desired Email Address.
    • Enter a Master Password. Pay close attention to the strength indicator.
    • Confirm your Master Password.
    • Optionally, enter a Master Password Hint.
  4. Submit: Click the "Create Account" or "Submit" button.

Upon successful creation, you will typically be automatically logged into your new, empty vault. You can now start adding login credentials, secure notes, cards, and identities.

Workshop First Login and Basic Usage

Goal: Create your first Vaultwarden account, log in, and add a sample password entry.

Prerequisites:

  • Vaultwarden container running and accessible via the web browser (from the previous workshop).

Steps:

  1. Access Vaultwarden: Open your web browser and navigate to http://<your_server_ip>:8080 (replace <your_server_ip> accordingly).

  2. Initiate Account Creation: Click on the "Create Account" button.

  3. Enter Account Details:

    • Email Address: Enter your email address (e.g., student@example.com).
    • Master Password: Create a strong, unique master password. For this workshop, you can use something temporary like CorrectHorseBatteryStaple123!, but remember to change it to a truly secure one later if you plan to use this instance seriously. Note it down temporarily if needed for this workshop only.
    • Confirm Master Password: Re-enter the master password.
    • Master Password Hint (Optional): You can skip this for now or add a simple hint.
  4. Submit the Form: Click the "Create Account" button at the bottom of the form.

  5. Log In: You should be redirected to the login page or possibly logged in automatically. If on the login page, enter the email address and master password you just created and click "Log In".

  6. Explore the Interface: You are now inside your empty Vaultwarden web vault. Familiarize yourself briefly with the layout:

    • Folders: Left-hand pane for organizing items.
    • Item Types: Middle pane (usually shows "All Items" initially).
    • Add Item: A button (often + or "Add Item") to create new entries.
    • Settings: Usually accessible via your email address or an icon in the top-right corner.
  7. Add a Sample Login Item:

    • Click the "Add Item" button (likely a + symbol).
    • Type: Select "Login" (this is usually the default).
    • Name: Enter a descriptive name (e.g., My Test Website).
    • Username: Enter a sample username (e.g., testuser).
    • Password: Enter a sample password (e.g., SampleP@ssw0rd). You can also click the "generate password" icon (often a refresh/circular arrow symbol) to see Vaultwarden's password generator.
    • URI 1: Enter a sample URL (e.g., https://test.example.com). Adding the correct URI helps browser extensions auto-fill credentials.
    • Save: Click the "Save" button (usually at the top or bottom).
  8. View the Saved Item: Your new item (My Test Website) should now appear in the middle pane. Click on it to view its details. You can copy the username or password using the provided icons.

Outcome: You have successfully created your primary Vaultwarden account, logged into the web vault, and added your first password entry. You now have a basic, functioning, self-hosted password manager. Remember the importance of your master password and the need for further configuration (like HTTPS) for real-world use.


2. Enhancing Your Vaultwarden Instance

With the basics covered, this section focuses on making your Vaultwarden instance more robust, manageable, and secure for real-world usage. We'll tackle persistent storage properly, simplify management with Docker Compose, and crucially, enable HTTPS encryption via a reverse proxy.

Persistent Data Storage with Volumes

In the basic deployment workshop, we already used the -v vw-data:/data/ flag. Let's delve deeper into why this is absolutely essential and explore Docker volumes more formally.

The Problem with Ephemeral Containers:

By default, the filesystem inside a Docker container is ephemeral. If you stop and remove a container (docker stop vaultwarden && docker rm vaultwarden) without having configured persistent storage, any data created or modified inside that container's filesystem is permanently lost. For Vaultwarden, this means losing your entire password database, user accounts, settings, attachments – everything stored in the /data directory within the container. Recreating the container from the same image will start it fresh, without any of your previous data.

The Solution Docker Volumes:

Docker offers several ways to persist data generated by containers. The preferred mechanism for databases, configuration files, and application data is Docker Volumes.

  • What are Volumes? Volumes are directories (or files) that exist outside the container's Union File System but are mounted into the container at a specified path. They are managed by Docker itself and stored in a dedicated area on the host filesystem (e.g., /var/lib/docker/volumes/ on Linux).
  • Named Volumes: When we used -v vw-data:/data/, we created a named volume.
    • vw-data: The name you give the volume. This makes it easy to reference and manage.
    • :/data/: The path inside the container where the volume should be mounted.
    • Docker automatically creates the named volume on the host the first time a container starts using it.
  • Benefits of Named Volumes:
    • Managed by Docker: Easier to back up, migrate, and manage volumes using Docker CLI commands (e.g., docker volume ls, docker volume inspect, docker volume rm).
    • Decoupled Lifecycle: Volumes exist independently of containers. You can remove a container, update the image, start a new container, and attach the same volume to it, preserving all your data.
    • Performance: Docker volumes often provide better I/O performance compared to bind mounts (another persistence method) for write-heavy workloads.
    • Cross-Platform Compatibility: Volumes work consistently across different Docker environments (Linux, Windows, macOS).

Bind Mounts (Alternative, Use with Caution):

Another option is using bind mounts: -v /path/on/host:/data/. This directly mounts a specific directory from your host machine into the container. While useful for development (e.g., mounting source code) or providing specific configuration files, it's generally less recommended for application data like Vaultwarden's database because:

  • It tightly couples the container to the host's filesystem structure.
  • Permissions management can be more complex.
  • It bypasses Docker's volume management features.

For Vaultwarden's /data directory, always use a named volume unless you have a very specific reason not to.

Ensuring you use -v <volume_name>:/data/ (or the equivalent in Docker Compose) guarantees that your precious vault data survives container restarts, updates, and removals.

Workshop Implementing Persistent Storage

Goal: Explicitly demonstrate data persistence using a named Docker volume. We will create an item, stop and remove the container, then start a new container using the same volume and verify the item is still present.

Prerequisites:

  • A running Vaultwarden container, preferably the one created in the previous workshop (named vaultwarden) which should already be using the vw-data volume. If you didn't use -v before, your data will be lost in this workshop, highlighting the importance of volumes.
  • Access to the server's terminal.

Steps:

  1. Ensure Vaultwarden is Running with a Volume: If you followed the previous workshop, your container should already be using the vw-data volume. Verify this:

    docker inspect vaultwarden | grep -A 5 Mounts
    
    Explanation: docker inspect vaultwarden outputs detailed information about the container in JSON format. grep -A 5 Mounts searches for the line containing "Mounts" and shows that line plus the next 5 lines. Look for an entry showing "Type": "volume", "Name": "vw-data", and "Destination": "/data".

    • If you don't have a volume mounted to /data, stop and remove the container (docker stop vaultwarden && docker rm vaultwarden) and restart it using the command from the previous workshop: docker run -d --name vaultwarden -p 8080:80 -v vw-data:/data/ vaultwarden/server:latest. You will need to create a new account and item in this case.
  2. Add or Confirm a Test Item:

    • Log in to your Vaultwarden instance (http://<your_server_ip>:8080).
    • If you don't have the "My Test Website" item from the previous workshop, create a new Login item now (e.g., Name: Persistence Test, Username: tester).
    • Ensure the item is saved and visible in your vault.
  3. Stop the Vaultwarden Container:

    docker stop vaultwarden
    
    Explanation: Gracefully stops the container named vaultwarden.

  4. Remove the Vaultwarden Container:

    docker rm vaultwarden
    
    Explanation: Removes the stopped container. Crucially, this does not remove the named volume vw-data.

  5. Verify Container Removal:

    docker ps -a
    
    Explanation: Lists all containers, running and stopped. The vaultwarden container should no longer be listed.

  6. Verify Volume Existence:

    docker volume ls
    
    Explanation: Lists all Docker volumes managed by Docker. You should see vw-data (or whatever name you used) in the list. This confirms the volume and its data still exist independently of the container.

  7. Restart Vaultwarden Using the Same Volume: Run the exact same docker run command you used initially, ensuring the volume name (vw-data) is identical:

    docker run -d --name vaultwarden -p 8080:80 -v vw-data:/data/ vaultwarden/server:latest
    
    Explanation: Docker detects that a volume named vw-data already exists and mounts it to /data in the new container instance.

  8. Verify Data Persistence:

    • Wait a few seconds for the container to start. Check with docker ps.
    • Access Vaultwarden again in your browser: http://<your_server_ip>:8080.
    • Log in using the same email and master password you created earlier.
    • Check your vault items. The "My Test Website" or "Persistence Test" item you created or confirmed in Step 2 should still be there.

Outcome: You have successfully demonstrated that using a named Docker volume ensures your Vaultwarden data persists even when the container itself is stopped and removed. This is fundamental for reliable operation and allows for safe updates and restarts. If the data was not present, it means you likely didn't use the -v flag correctly in the initial run.

Using Docker Compose for Easier Management

While docker run is fine for single containers, managing applications, their configurations, volumes, and networks becomes cumbersome as complexity increases. Docker Compose is a tool designed to define and run multi-container Docker applications using a simple YAML file.

What is Docker Compose?

Docker Compose uses a docker-compose.yml file to configure your application's services, networks, and volumes. Instead of typing long docker run commands with many flags, you define the desired state in the YAML file, and Compose handles the creation and management.

Benefits of using Docker Compose for Vaultwarden:

  1. Declarative Configuration: The docker-compose.yml file clearly describes your Vaultwarden setup (image, ports, volumes, environment variables, networks). This file acts as documentation and makes the setup reproducible.
  2. Simplicity: Starting, stopping, and restarting your application becomes much simpler: docker compose up, docker compose down.
  3. Easier Configuration Management: Modifying configurations (e.g., adding environment variables, changing ports) involves editing the YAML file and recreating the services, rather than complex docker run commands.
  4. Networking: Compose automatically sets up a dedicated network for your application's services, allowing containers to easily communicate with each other using their service names. This is crucial when adding a reverse proxy in a later step.
  5. Readability: YAML is human-readable and well-structured, making it easier to understand the setup compared to long shell commands.

Basic docker-compose.yml for Vaultwarden:

Here's an example docker-compose.yml file that replicates our previous docker run command:

version: '3.8' # Specifies the Compose file format version

services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden # Explicitly sets the container name
    restart: unless-stopped # Policy for restarting the container
    volumes:
      - vw-data:/data/ # Mounts the named volume 'vw-data' to /data in the container
    ports:
      - "8080:80" # Maps host port 8080 to container port 80
    environment:
      # Environment variables can be added here later (e.g., for HTTPS, admin token)
      - WEBSOCKET_ENABLED=true # Enable websockets for real-time client sync (optional but recommended)

volumes:
  vw-data: # Declares the named volume 'vw-data'
    # driver: local (default) - You can specify volume drivers if needed

Explanation:

  • version: '3.8': Defines the version of the Compose file syntax.
  • services:: Defines the containers (services) that make up your application.
    • vaultwarden:: The name of our service.
    • image:: Specifies the Docker image to use.
    • container_name:: Sets a specific name for the container (optional, but helpful).
    • restart: unless-stopped: Defines the restart policy. unless-stopped ensures the container restarts automatically if it crashes or if the Docker daemon restarts, unless it was manually stopped. Other options include no, on-failure, always.
    • volumes:: Defines volume mounts for this service.
      • - vw-data:/data/: Mounts the named volume vw-data (defined below) to /data inside the container.
    • ports:: Defines port mappings (HOST:CONTAINER).
      • - "8080:80": Maps host port 8080 to container port 80.
    • environment:: Used to set environment variables inside the container. We added WEBSOCKET_ENABLED=true as it improves client synchronization performance and is needed for some reverse proxy setups.
  • volumes:: Top-level key to define named volumes used by the services.
    • vw-data:: Declares the named volume vw-data. Docker Compose will create it if it doesn't exist.

Using Docker Compose provides a much cleaner and more maintainable way to manage your Vaultwarden deployment.

Workshop Migrating to Docker Compose

Goal: Transition from managing Vaultwarden with docker run to using Docker Compose, ensuring data persistence.

Prerequisites:

  • Vaultwarden previously started with docker run using the named volume vw-data.
  • Docker Compose installed (usually included with Docker Desktop or installed as docker-compose-plugin in the first workshop). Verify with docker compose version.
  • Access to the server's terminal.
  • A text editor on the server (like nano or vim).

Steps:

  1. Stop and Remove the Existing Container: If your vaultwarden container started with docker run is still running, stop and remove it. Ensure it was started with -v vw-data:/data/ so your data is safe in the volume.

    docker stop vaultwarden
    docker rm vaultwarden
    
    Verify removal: docker ps -a should not show vaultwarden. Verify volume: docker volume ls should still show vw-data.

  2. Create a Directory for Compose File: It's good practice to keep your docker-compose.yml file in a dedicated directory.

    mkdir ~/vaultwarden
    cd ~/vaultwarden
    
    Explanation: Creates a directory named vaultwarden in your home directory and navigates into it.

  3. Create the docker-compose.yml File: Use a text editor to create the docker-compose.yml file.

    nano docker-compose.yml
    

  4. Paste the Compose Configuration: Copy the following YAML content and paste it into the nano editor:

    version: '3.8'
    
    services:
      vaultwarden:
        image: vaultwarden/server:latest
        container_name: vaultwarden
        restart: unless-stopped
        volumes:
          - vw-data:/data/
        ports:
          - "8080:80"
        environment:
          - WEBSOCKET_ENABLED=true # Recommended for real-time sync
    
    volumes:
      vw-data:
    
  5. Save and Close the File:

    • In nano: Press Ctrl+X, then Y to confirm saving, and Enter to save with the name docker-compose.yml.
  6. Start Vaultwarden with Docker Compose: While inside the ~/vaultwarden directory (where the docker-compose.yml file is located), run:

    docker compose up -d
    
    Explanation:

    • docker compose: Invokes the Docker Compose tool.
    • up: Builds (if necessary), creates, starts, and attaches to containers for a service.
    • -d: Detached mode - runs containers in the background.
    • Compose reads the docker-compose.yml file in the current directory. It will detect the existing vw-data volume and attach it to the new vaultwarden container.
  7. Verify the Container:

    docker ps
    
    You should see the vaultwarden container running, managed by Docker Compose. You might notice the container name is prefixed with the directory name (e.g., vaultwarden-vaultwarden-1) if you didn't specify container_name. If you did use container_name: vaultwarden as in the example, it should just be named vaultwarden.

  8. Verify Data Persistence and Access:

    • Access Vaultwarden in your browser: http://<your_server_ip>:8080.
    • Log in with your existing credentials.
    • Verify that your previously saved items (e.g., "My Test Website", "Persistence Test") are still present.
    • Test adding a new item to ensure write access is working.

Outcome: You have successfully migrated your Vaultwarden instance to be managed by Docker Compose. Future management actions like stopping (docker compose down), starting (docker compose up -d), restarting (docker compose restart vaultwarden), and updating (pulling a new image and running docker compose up -d) are now streamlined using Compose commands within the ~/vaultwarden directory. Your data remains persistent in the vw-data volume.

Setting Up HTTPS with a Reverse Proxy (e.g., Nginx Proxy Manager)

Running Vaultwarden over plain HTTP (http://...) is highly insecure. Your login credentials (including your master password) and all vault data would be transmitted unencrypted over the network, making them vulnerable to interception. Enabling HTTPS is mandatory for any real-world use.

Vaultwarden itself doesn't handle HTTPS/TLS termination directly. The standard practice is to run Vaultwarden listening only on the local Docker network (or localhost within the container) and place a reverse proxy in front of it.

What is a Reverse Proxy?

A reverse proxy is a server that sits in front of web servers (like Vaultwarden) and forwards client requests (from web browsers, apps) to those web servers. It acts as an intermediary, providing several benefits:

  1. SSL/TLS Termination: The reverse proxy handles the complexity of obtaining, managing, and renewing SSL/TLS certificates (e.g., from Let's Encrypt) and encrypting traffic between the client and the proxy (HTTPS). Communication between the proxy and the backend Vaultwarden container can then happen over plain HTTP within the secure Docker network.
  2. Load Balancing: Can distribute incoming traffic across multiple backend server instances (not typically needed for a single Vaultwarden instance).
  3. Security: Hides the internal structure and IP addresses of your backend servers. Can provide additional security layers like rate limiting or web application firewalls (WAF).
  4. Centralized Access: Allows you to host multiple web applications on the same server using the same IP address and standard ports (80 for HTTP, 443 for HTTPS), routing traffic based on domain names (e.g., vaultwarden.mydomain.com, blog.mydomain.com).

Popular Reverse Proxy Options:

  • Nginx: A powerful, high-performance web server and reverse proxy. Requires manual configuration file editing.
  • Apache: Another widely used web server with reverse proxy capabilities. Also requires manual configuration.
  • Traefik: A modern, cloud-native reverse proxy designed specifically for containers. Automatically discovers services and handles SSL via Docker labels. Can have a steeper learning curve initially.
  • Caddy: A modern web server known for its automatic HTTPS configuration. Simple to configure.
  • Nginx Proxy Manager (NPM): A user-friendly web interface built on top of Nginx. Makes setting up proxy hosts, redirection, and Let's Encrypt SSL certificates incredibly easy via a GUI. Excellent choice for beginners.

General Workflow (using Nginx Proxy Manager as example):

  1. Set up DNS: Configure a DNS A record for your desired domain (e.g., vaultwarden.yourdomain.com) pointing to the public IP address of your server.
  2. Deploy Nginx Proxy Manager: Run NPM as a Docker container (often using Docker Compose). It needs ports 80, 443, and a port for its own admin UI (e.g., 81).
  3. Modify Vaultwarden Deployment:
    • Remove the direct port mapping (ports: section) from Vaultwarden's docker-compose.yml. It no longer needs to be exposed directly to the host.
    • Ensure both Vaultwarden and NPM are on the same Docker network so NPM can reach Vaultwarden by its service name (vaultwarden).
    • Add necessary environment variables to Vaultwarden if required by the proxy setup (e.g., DOMAIN=https://vaultwarden.yourdomain.com).
  4. Configure NPM:
    • Log in to the NPM web UI.
    • Add a new Proxy Host:
      • Domain Names: vaultwarden.yourdomain.com
      • Scheme: http
      • Forward Hostname / IP: vaultwarden (the service name from your docker-compose.yml)
      • Forward Port: 80 (the port Vaultwarden listens on inside the container)
      • Enable Block Common Exploits.
      • Enable Websockets Support.
    • Go to the SSL tab:
      • Select "Request a new SSL Certificate" with Let's Encrypt.
      • Enable "Force SSL".
      • Agree to the Let's Encrypt ToS.
      • Save.
  5. Test: Access https://vaultwarden.yourdomain.com. You should be redirected to HTTPS and see the Vaultwarden login page with a valid SSL certificate (lock icon in browser).

This setup ensures secure, encrypted access to your self-hosted password manager.

Workshop Securing Vaultwarden with HTTPS via NPM

Goal: Set up Nginx Proxy Manager (NPM) and configure it to provide secure HTTPS access to your Vaultwarden instance using a custom domain name and a Let's Encrypt SSL certificate.

Prerequisites:

  • Vaultwarden running via Docker Compose (from the previous workshop).
  • A registered domain name (e.g., yourdomain.com).
  • Ability to add DNS records for your domain.
  • Your server's public IP address.
  • Ports 80 and 443 open on your server's firewall (e.g., sudo ufw allow 80/tcp, sudo ufw allow 443/tcp). Port 81 also needs to be open for the NPM admin interface. sudo ufw allow 81/tcp.
  • Docker and Docker Compose installed.

Steps:

  1. Configure DNS:

    • Go to your domain registrar or DNS provider's control panel.
    • Create an A record pointing a subdomain (e.g., vaultwarden) to your server's public IP address.
      • Type: A
      • Name/Host: vaultwarden (or your preferred subdomain)
      • Value/Points to: <your_server_public_ip>
      • TTL: Set to the lowest possible value (e.g., 1 minute or 60 seconds) initially for faster propagation, you can increase it later.
    • Wait for DNS propagation (can take minutes to hours). You can check using ping vaultwarden.yourdomain.com or an online DNS checker.
  2. Prepare Docker Network: We need both Vaultwarden and NPM to be on the same custom Docker network so they can communicate using service names.

    • Edit your Vaultwarden docker-compose.yml (~/vaultwarden/docker-compose.yml):
      nano ~/vaultwarden/docker-compose.yml
      
    • Modify it to look like this (changes highlighted):

      version: '3.8'
      
      services:
        vaultwarden:
          image: vaultwarden/server:latest
          container_name: vaultwarden
          restart: unless-stopped
          volumes:
            - vw-data:/data/
          # ports: <-- REMOVE OR COMMENT OUT THIS SECTION
          #   - "8080:80" <-- REMOVE OR COMMENT OUT
          networks: # <-- ADD
            - npm_network # <-- ADD (Name of the network)
          environment:
            - WEBSOCKET_ENABLED=true
            - DOMAIN=https://vaultwarden.yourdomain.com # <-- ADD YOUR FULL DOMAIN HERE
      
      volumes:
        vw-data:
      
      networks: # <-- ADD THIS ENTIRE BLOCK
        npm_network: # <-- ADD
          external: true # <-- ADD (Specifies we'll use a pre-existing network)
      
      Replace vaultwarden.yourdomain.com with your actual domain.

    • Save and close the file (Ctrl+X, Y, Enter).

  3. Create the Docker Network: Before starting NPM or restarting Vaultwarden, create the network we referenced:

    docker network create npm_network
    
    Explanation: Creates a Docker bridge network named npm_network.

  4. Restart Vaultwarden: Navigate back to the Vaultwarden directory and apply the changes:

    cd ~/vaultwarden
    docker compose down # Stop the old configuration
    docker compose up -d # Start with the new configuration (using the network, no exposed ports)
    

  5. Create Docker Compose File for Nginx Proxy Manager (NPM):

    • Create a separate directory for NPM:
      mkdir ~/npm
      cd ~/npm
      
    • Create the docker-compose.yml file for NPM:
      nano docker-compose.yml
      
    • Paste the following configuration:

      version: '3.8'
      services:
        npm:
          image: 'jc21/nginx-proxy-manager:latest'
          container_name: npm
          restart: unless-stopped
          ports:
            # Public HTTP Port:
            - '80:80'
            # Public HTTPS Port:
            - '443:443'
            # Admin Web Port:
            - '81:81'
          volumes:
            - npm-data:/data
            - npm-letsencrypt:/etc/letsencrypt
          networks: # <-- ADD
            - npm_network # <-- ADD (Connect NPM to the same network)
      
      volumes:
        npm-data:
        npm-letsencrypt:
      
      networks: # <-- ADD THIS ENTIRE BLOCK
        npm_network: # <-- ADD
          external: true # <-- ADD (Connect to the network created earlier)
      
    • Save and close the file.

  6. Start Nginx Proxy Manager: While inside the ~/npm directory:

    docker compose up -d
    

  7. Access NPM Admin Interface:

    • Wait a minute for NPM to initialize.
    • Open your web browser and navigate to http://<your_server_ip>:81.
    • Default Login:
      • Email: admin@example.com
      • Password: changeme
    • You will be forced to change the email and password immediately. Do this now and use a strong password.
  8. Configure Proxy Host in NPM:

    • Log in to NPM with your new credentials.
    • Navigate to Hosts -> Proxy Hosts.
    • Click Add Proxy Host.
    • Fill in the Details tab:
      • Domain Names: Enter vaultwarden.yourdomain.com (your actual domain).
      • Scheme: http
      • Forward Hostname / IP: vaultwarden (This is the service name of your Vaultwarden container as defined in its docker-compose.yml file. Docker's internal DNS resolves this because they are on the same npm_network).
      • Forward Port: 80 (The port Vaultwarden listens on inside its container).
      • Enable Block Common Exploits.
      • Enable Websockets Support.
    • Click on the SSL tab:
      • Under SSL Certificate, select Request a new SSL Certificate.
      • Enable Force SSL.
      • Enable HTTP/2 Support (optional but recommended).
      • Agree to the Let's Encrypt Terms of Service.
      • Click Save.
  9. Test HTTPS Access:

    • NPM will now attempt to obtain the SSL certificate from Let's Encrypt. This might take a minute. You should see the status change in the NPM interface.
    • Open a new browser tab and navigate to https://vaultwarden.yourdomain.com (using HTTPS).
    • You should see the Vaultwarden login page.
    • Check your browser's address bar for a padlock icon, indicating a secure connection. Click it to view the certificate details – it should be issued by Let's Encrypt for your domain.

Outcome: You have successfully secured your Vaultwarden instance with HTTPS using Nginx Proxy Manager. All traffic between your browser/clients and the server is now encrypted. You access Vaultwarden via your custom domain name over HTTPS, and direct access via IP address and port 8080 should no longer work (or be necessary). This setup is suitable for real-world use.


3. Advanced Vaultwarden Configuration and Features

Now that you have a secure, persistent, and manageable Vaultwarden instance, we can explore advanced configurations and features to further customize, secure, and maintain your setup. This includes tweaking server behavior, enabling two-factor authentication, setting up backups, and managing users or organizations.

Understanding Vaultwarden Environment Variables

One of the primary ways to configure Vaultwarden within a Docker environment is through environment variables. These are key-value pairs passed to the container upon startup, allowing you to modify various settings without altering the container image itself.

You typically define these variables within the environment: section of your docker-compose.yml file for the vaultwarden service.

Why Use Environment Variables?

  • Flexibility: Easily change settings without rebuilding the image.
  • Security: Keep sensitive information (like SMTP passwords or admin tokens) out of version-controlled docker-compose.yml files by using .env files (though we won't cover .env files in extreme detail here, know they exist for this purpose).
  • Standardization: It's the conventional way to configure Dockerized applications.

Key Vaultwarden Environment Variables:

Here are some of the most commonly used and important environment variables (refer to the official Vaultwarden Wiki for a complete, up-to-date list):

  • SIGNUPS_ALLOWED=true|false: (Default: true) Controls whether new users can register. Set to false after creating necessary accounts to prevent unwanted signups. Highly recommended to set to false for security.
  • ADMIN_TOKEN=<your_secure_random_token>: (Default: not set) Sets a password/token required to access the admin interface at /admin. Use a long, random string generated with a password manager or openssl rand -base64 48. Accessing /admin allows managing users, settings, and organizations directly. Highly recommended to set this.
  • DOMAIN=https://yourdomain.com: (Default: not set) Specifies the public URL of your Vaultwarden instance. This is often required for features like YubiKey U2F/FIDO2 authentication, email link generation, and sometimes reverse proxy setups. Set this to your full HTTPS domain.
  • WEBSOCKET_ENABLED=true|false: (Default: false, but we enabled it earlier) Enables WebSocket connections for real-time synchronization between clients and the server (e.g., changes made in the web vault reflect instantly in the browser extension). Requires reverse proxy configuration (like the Websockets Support toggle in NPM). Generally recommended (true).
  • LOG_LEVEL=info|warn|error|debug|trace: (Default: info) Controls the verbosity of Vaultwarden's logs. Useful for troubleshooting (debug or trace).
  • SMTP_HOST=<smtp.server.com>: Hostname or IP of your SMTP server for sending emails (e.g., invitations, password hints).
  • SMTP_FROM=<vaultwarden@yourdomain.com>: The "From" address for outgoing emails.
  • SMTP_PORT=587|465|25: Port for the SMTP server (e.g., 587 for TLS, 465 for SSL).
  • SMTP_SECURITY=starttls|force_tls|off: Security protocol (STARTTLS, SSL/TLS, or none).
  • SMTP_USERNAME=<your_smtp_username>: Username for SMTP authentication.
  • SMTP_PASSWORD=<your_smtp_password>: Password for SMTP authentication. (Consider using secrets management or .env files for sensitive values like this).
  • INVITATIONS_ALLOWED=true|false: (Default: true if SMTP is configured, false otherwise) Allows administrators or organization owners to invite new users via email. Requires SMTP configuration.
  • SHOW_PASSWORD_HINT=true|false: (Default: true) Whether to allow users to request their password hint via email. Requires SMTP configuration. Set to false if you don't configure SMTP or want to disable this feature.
  • PUSH_ENABLED=true|false: (Default: false) Enables push notifications to mobile clients via Bitwarden's push relay service. Requires obtaining specific keys (PUSH_INSTALLATION_ID, PUSH_INSTALLATION_KEY) from Bitwarden (requires an account at https://bitwarden.com/host).

By strategically setting these variables, you can tailor Vaultwarden's behavior precisely to your requirements, enhancing security and functionality. Remember to restart the Vaultwarden container (docker compose down && docker compose up -d) after modifying environment variables in your docker-compose.yml file.

Workshop Customizing Vaultwarden Settings

Goal: Modify your Vaultwarden configuration using environment variables to disable signups and set an admin token.

Prerequisites:

  • Vaultwarden running via Docker Compose and accessible via HTTPS (from previous workshops).
  • Access to the server's terminal and your Vaultwarden docker-compose.yml file (~/vaultwarden/docker-compose.yml).
  • A tool to generate a random string (like a password manager or the openssl command).

Steps:

  1. Generate an Admin Token: Use a secure method to generate a long, random string. Using openssl on your server is a convenient option:

    openssl rand -base64 48
    
    Explanation: openssl rand generates random bytes, -base64 encodes them into a printable string, 48 specifies the number of random bytes (resulting in a 64-character base64 string).

    • Copy the generated string. Treat this like a password. Example output (yours will be different): aVeryLong+Random/StringGeneratedByOpenSSL12345==
  2. Edit the Docker Compose File: Open your Vaultwarden docker-compose.yml file for editing:

    nano ~/vaultwarden/docker-compose.yml
    

  3. Add Environment Variables: Locate the environment: section under the vaultwarden service. Add the following variables, replacing <your_secure_random_token> with the token you just generated:

    version: '3.8'
    
    services:
      vaultwarden:
        image: vaultwarden/server:latest
        container_name: vaultwarden
        restart: unless-stopped
        volumes:
          - vw-data:/data/
        networks:
          - npm_network
        environment:
          - WEBSOCKET_ENABLED=true
          - DOMAIN=https://vaultwarden.yourdomain.com # Ensure this is correct
          # --- ADD THESE LINES ---
          - SIGNUPS_ALLOWED=false # Disable new user registrations
          - ADMIN_TOKEN=<your_secure_random_token> # Set the admin panel token
          # --- END ADDED LINES ---
    
    volumes:
      vw-data:
    
    networks:
      npm_network:
        external: true
    
    • Ensure correct indentation (usually 2 spaces under environment:).
  4. Save and Close the File:

    • In nano: Ctrl+X, Y, Enter.
  5. Apply Configuration Changes: Navigate to the directory containing the docker-compose.yml file and restart the container:

    cd ~/vaultwarden
    docker compose down
    docker compose up -d
    
    Explanation: docker compose down stops and removes the old container. docker compose up -d creates and starts a new container using the updated configuration from the docker-compose.yml file, including the new environment variables. The persistent data from the vw-data volume is automatically re-attached.

  6. Verify Signup Disabled:

    • Open an incognito/private browser window.
    • Navigate to your Vaultwarden instance: https://vaultwarden.yourdomain.com.
    • Look for the "Create Account" button or link. It should now be missing or disabled. This confirms SIGNUPS_ALLOWED=false is active.
  7. Access the Admin Panel:

    • In your browser, navigate to https://vaultwarden.yourdomain.com/admin.
    • You should be prompted to enter the admin token.
    • Paste the secure random token you generated in Step 1 into the field and click Login.
  8. Explore the Admin Panel: You should now have access to the Vaultwarden admin interface. Briefly explore the sections available (Users, Settings, Organizations). You can see your own user account listed under Users.

Outcome: You have successfully customized your Vaultwarden instance using environment variables. You've enhanced security by disabling public signups and protecting the administrative interface with a strong token. You are now familiar with the process of modifying the configuration and applying changes using Docker Compose.

Enabling Two-Factor Authentication (2FA)

Two-factor authentication (2FA) adds a critical layer of security to your Vaultwarden account. Even if your master password becomes compromised, an attacker would still need your second factor (e.g., a code from an authenticator app, a hardware key) to log in.

Vaultwarden (like Bitwarden) supports several 2FA methods for user accounts:

  1. Authenticator App (TOTP): Time-based One-Time Passwords using apps like Google Authenticator, Authy, Aegis Authenticator (Android), or Raivo OTP (iOS). This is the most common method. Users scan a QR code or enter a secret key into their app, which then generates rotating 6-digit codes.
  2. FIDO2 WebAuthn: Uses hardware security keys (like YubiKey) or platform authenticators (like Windows Hello or Touch ID) based on the FIDO2/WebAuthn standard. This offers very strong phishing resistance. Requires DOMAIN environment variable to be set correctly.
  3. YubiKey OTP: Uses the OTP generation feature of YubiKey hardware tokens via Yubico's cloud validation service. Requires obtaining API credentials from Yubico.
  4. Duo Security: Integrates with Duo's push notification and authentication service. Requires a Duo account and API credentials.
  5. Email: Sends a code via email for verification. Requires SMTP to be configured correctly in Vaultwarden's environment variables. Generally considered less secure than TOTP or FIDO2 due to potential email account compromise.

Enabling 2FA (User Perspective):

Individual users enable and manage their 2FA methods within their own account settings after logging into Vaultwarden (web vault, desktop app, or browser extension).

  1. Log in to the Vaultwarden Web Vault (https://vaultwarden.yourdomain.com).
  2. Go to Settings (usually top-right).
  3. Select Two-step Login from the left-hand menu.
  4. Choose a provider (e.g., "Authenticator App").
  5. Click "Manage" and follow the on-screen instructions (e.g., enter your master password, scan the QR code with your authenticator app, enter the generated verification code).
  6. Crucially, save the provided Recovery Code in a safe place. This code allows you to regain access if you lose your second factor device. Store it as securely as your master password.

Server-Side Configuration (Optional but Recommended):

While users enable 2FA individually, administrators can influence 2FA policies through the Admin Panel (/admin), especially within Organizations (which we'll touch on later).

You can also enforce certain server-level requirements via environment variables, for example:

  • DISABLE_2FA_REMEMBER=true: Prevents users from checking the "Remember Me" box on the 2FA prompt, forcing them to enter a 2FA code more frequently.

Recommendation: Encourage all users to enable at least one 2FA method, preferably Authenticator App (TOTP) or FIDO2 WebAuthn, for significantly enhanced account security.

Workshop Setting Up Server-Side 2FA (User Account TOTP)

Goal: Enable and configure Two-Factor Authentication using an Authenticator App (TOTP) for your own Vaultwarden user account.

Prerequisites:

  • Your Vaultwarden instance is running and accessible via HTTPS.
  • You have successfully logged into your user account in the Vaultwarden Web Vault (https://vaultwarden.yourdomain.com).
  • An authenticator app installed on your smartphone (e.g., Authy, Google Authenticator, Aegis, Raivo OTP).

Steps:

  1. Log In to Vaultwarden Web Vault: Ensure you are logged into https://vaultwarden.yourdomain.com with your user account (not the admin panel).

  2. Navigate to Account Settings: Click on your email address or profile icon in the top-right corner and select Account Settings.

  3. Navigate to Two-step Login: In the Settings menu on the left, click on Two-step Login.

  4. Select Authenticator App: Find the "Authenticator App" provider in the list. It will likely show as "Not Enabled". Click the Manage button next to it.

  5. Enter Master Password: For security, you will be prompted to re-enter your Vaultwarden Master Password. Enter it and click Continue.

  6. Scan the QR Code:

    • A screen will appear displaying a QR code and a secret key (text string).
    • Open your authenticator app on your smartphone.
    • Choose the option to add a new account (usually a + icon).
    • Select the option to scan a QR code.
    • Point your phone's camera at the QR code displayed in the Vaultwarden web vault.
    • Your authenticator app should recognize it and add a new entry, typically named after your email address and the Vaultwarden domain. It will start generating 6-digit codes that refresh every 30 seconds.
    • (Alternative) Manual Entry: If you cannot scan the QR code, you can manually enter the secret key provided below the QR code into your authenticator app.
  7. Enter Verification Code:

    • Look at the 6-digit code currently displayed in your authenticator app for the Vaultwarden entry.
    • Enter this code into the Verification Code field in the Vaultwarden web vault (below the QR code).
    • Click Enable.
  8. Save Recovery Code:

    • Upon successful enablement, Vaultwarden will display a Recovery Code. This code is critical. If you lose access to your authenticator app (e.g., lose or reset your phone), this recovery code is the ONLY way to disable 2FA and regain access to your account.
    • Copy this recovery code immediately.
    • Store it in a very safe place, separate from your authenticator device, with the same level of security as your master password (e.g., print it and store securely, save it in another password manager if applicable, write it down in multiple secure locations).
    • Check the box confirming "I have saved my recovery code" and click Close.
  9. Verify 2FA Status: Back on the Two-step Login screen, the Authenticator App should now show as "Enabled".

  10. Test 2FA:

    • Log out of your Vaultwarden web vault (Profile Icon -> Log Out).
    • Log back in using your email and master password.
    • After entering your password, you should now be prompted for the Authenticator Code.
    • Open your authenticator app, find the code for Vaultwarden, and enter it.
    • Click Continue or Login. You should successfully log in.

Outcome: You have successfully enabled TOTP-based two-factor authentication for your Vaultwarden account. Your account is now significantly more secure against unauthorized access, even if your master password were to be compromised. Remember the importance of safeguarding both your master password and your recovery code.

Backup and Restore Strategies

Self-hosting Vaultwarden means you are solely responsible for backups. Losing access to your password vault due to data corruption, hardware failure, accidental deletion, or server compromise can be catastrophic. Implementing a reliable backup strategy is not optional; it's essential.

What Needs to Be Backed Up?

The critical components of your Vaultwarden setup that require backup are:

  1. Vaultwarden Data Volume: This is the most important part. The named Docker volume (e.g., vw-data) mounted at /data inside the container holds:

    • db.sqlite3: The SQLite database containing all vault items (logins, notes, cards, identities), user accounts, organization details, settings, etc. (unless using an external database like PostgreSQL/MySQL, which would need its own backup procedure).
    • attachments directory: Stores any file attachments uploaded by users.
    • sends directory: Stores data related to Bitwarden Send items.
    • rsa_key.pem and rsa_key.pub.pem: Private and public RSA keys used for encryption and identification. Losing these keys will render your vault unusable, even if you have the database.
    • config.json: Some runtime configuration (less critical to back up directly if using environment variables, but included in the volume).
    • Icons cache (icon_cache directory).
  2. Configuration Files:

    • docker-compose.yml: Your primary configuration file defining the service, volumes, networks, ports (if any), and environment variables.
    • .env file (if used): If you store sensitive environment variables (like ADMIN_TOKEN, SMTP passwords) in a separate .env file, this needs to be backed up securely.
  3. (Optional) Reverse Proxy Configuration:

    • If using Nginx Proxy Manager, back up its Docker volumes (npm-data, npm-letsencrypt) which contain its configuration and SSL certificates.
    • If using manual Nginx/Apache/Caddy/Traefik configurations, back up those config files.

Backup Strategy Considerations:

  • Frequency: How often should you back up? Daily is recommended for a password manager, as new credentials might be added frequently. Adjust based on your usage patterns.
  • Method:
    • Volume Snapshot (If supported): Some filesystems (like ZFS) or VM hypervisors offer snapshot capabilities, which can be very efficient.
    • Direct Copy: Stop the Vaultwarden container briefly and copy the contents of the Docker volume directory. Or, copy while running, accepting a minimal risk of inconsistency if the database is being written to at that exact moment (usually acceptable for SQLite).
    • docker cp: Copy files directly from the container (less ideal for the whole data directory).
    • Database-specific tools (if using external DB).
  • Automation: Backups must be automated using tools like cron (Linux) or Task Scheduler (Windows) running a script. Manual backups are prone to being forgotten.
  • Storage Location (3-2-1 Rule):
    • Keep at least 3 copies of your data.
    • Store the copies on 2 different media types (e.g., server disk + external USB drive).
    • Keep 1 copy off-site (e.g., encrypted cloud storage, separate physical location). This protects against local disasters (fire, theft).
  • Encryption: Encrypt your backups, especially if storing them off-site or in the cloud, as they contain highly sensitive data. Tools like gpg or rclone's encryption features can be used.
  • Retention: Decide how long to keep backups (e.g., daily backups for 7 days, weekly for 4 weeks, monthly for 6 months).
  • Testing: Regularly test your restore process to ensure your backups are valid and you know how to recover from them. A backup is useless if it can't be restored.

Restoring Vaultwarden:

  1. Stop the Container: docker compose down
  2. Restore Volume Data: Locate the Docker volume directory on the host (find path with docker volume inspect vw-data) or manage via Docker. Remove any corrupted data and copy the contents from your backup into the volume directory. Ensure file permissions and ownership are correct (usually needs to be owned by UID/GID that Docker runs the container as, often discoverable via docker inspect).
  3. Restore Configuration: Ensure your docker-compose.yml (and .env file if used) are correct.
  4. Restart Container: docker compose up -d
  5. Test: Log in and verify your data is present and correct.

A robust backup plan is your safety net for self-hosting critical services like Vaultwarden.

Workshop Implementing Automated Backups

Goal: Create a simple automated backup script for the Vaultwarden data volume and schedule it using cron. This script will copy the volume data, compress it, timestamp it, and store it locally. (Note: Off-site storage is crucial but beyond the scope of this basic workshop).

Prerequisites:

  • Vaultwarden running via Docker Compose with the named volume vw-data.
  • Access to the server's terminal with sudo or root privileges (to inspect volume path and potentially set cron jobs).
  • tar and gzip utilities installed (usually default on Linux).
  • cron daemon installed and running (usually default).

Steps:

  1. Identify the Volume Path on Host: Docker manages the storage for named volumes. We need to find where the vw-data volume physically resides on the host filesystem.

    docker volume inspect vw-data
    
    Explanation: This command outputs JSON details about the volume. Look for the "Mountpoint" value. It will be a path similar to /var/lib/docker/volumes/vw-data/_data. Copy this path accurately. Let's assume it's /var/lib/docker/volumes/vw-data/_data for this workshop.

  2. Create a Backup Directory: Create a directory outside the Docker volume area to store your backups.

    sudo mkdir -p /opt/vaultwarden-backups
    sudo chown $USER:$USER /opt/vaultwarden-backups # Optional: Change ownership for easier access by your user
    
    Explanation: Creates the directory /opt/vaultwarden-backups. The -p flag ensures parent directories are created if needed. Changing ownership allows your regular user to write backups there without sudo in the script (adjust user/group if needed).

  3. Create the Backup Script:

    • Create a new file for the script:
      cd ~ # Go to home directory
      nano backup-vaultwarden.sh
      
    • Paste the following script content into nano. Carefully replace /var/lib/docker/volumes/vw-data/_data with the actual Mountpoint path you found in Step 1.

      #!/bin/bash
      
      # --- Configuration ---
      # !!! IMPORTANT: Replace with the actual Mountpoint path from 'docker volume inspect vw-data' !!!
      VAULTWARDEN_VOLUME_PATH="/var/lib/docker/volumes/vw-data/_data"
      
      # Directory where backups will be stored
      BACKUP_DIR="/opt/vaultwarden-backups"
      
      # Backup filename format (includes date and time)
      TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
      BACKUP_FILENAME="vaultwarden_backup_${TIMESTAMP}.tar.gz"
      BACKUP_FILE_PATH="${BACKUP_DIR}/${BACKUP_FILENAME}"
      
      # Number of days to keep backups (optional: cleanup old backups)
      RETENTION_DAYS=7
      
      # --- Script Logic ---
      
      echo "Starting Vaultwarden backup..."
      
      # Check if source volume path exists
      if [ ! -d "$VAULTWARDEN_VOLUME_PATH" ]; then
          echo "ERROR: Vaultwarden volume path not found at ${VAULTWARDEN_VOLUME_PATH}"
          exit 1
      fi
      
      # Check if backup directory exists
      if [ ! -d "$BACKUP_DIR" ]; then
          echo "ERROR: Backup directory not found at ${BACKUP_DIR}"
          exit 1
      fi
      
      # Create the compressed backup archive
      # Using sudo because /var/lib/docker/volumes is often root-owned
      echo "Creating backup archive at ${BACKUP_FILE_PATH}..."
      sudo tar -czf "${BACKUP_FILE_PATH}" -C "${VAULTWARDEN_VOLUME_PATH}" .
      # Explanation:
      # tar: Tape Archiver utility
      # -c: Create an archive
      # -z: Compress using gzip
      # -f: Specify the filename of the archive (${BACKUP_FILE_PATH})
      # -C: Change directory to ${VAULTWARDEN_VOLUME_PATH} before adding files. This prevents including the full path in the archive.
      # .: Add all files and directories from the current directory (which is now ${VAULTWARDEN_VOLUME_PATH})
      
      # Check if tar command was successful
      if [ $? -eq 0 ]; then
          echo "Backup created successfully: ${BACKUP_FILE_PATH}"
      else
          echo "ERROR: Backup creation failed."
          # Optional: Remove partial backup file if it exists
          [ -f "${BACKUP_FILE_PATH}" ] && sudo rm "${BACKUP_FILE_PATH}"
          exit 1
      fi
      
      # Optional: Cleanup old backups
      if [ "$RETENTION_DAYS" -gt 0 ]; then
          echo "Cleaning up backups older than ${RETENTION_DAYS} days in ${BACKUP_DIR}..."
          # Use sudo because the backup files might be owned by root depending on how tar was run
          sudo find "${BACKUP_DIR}" -name 'vaultwarden_backup_*.tar.gz' -mtime +"${RETENTION_DAYS}" -exec echo "Deleting old backup: {}" \; -exec sudo rm {} \;
          # Explanation:
          # find: Search for files
          # ${BACKUP_DIR}: Directory to search in
          # -name '...': Match files with this pattern
          # -mtime +N: Find files modified more than N days ago
          # -exec ... \;: Execute a command (echo, rm) on each found file
      fi
      
      echo "Vaultwarden backup finished."
      exit 0
      
    • Save and close the file (Ctrl+X, Y, Enter).

  4. Make the Script Executable:

    chmod +x backup-vaultwarden.sh
    

  5. Perform an Initial Manual Backup: Run the script manually to test it. You might be prompted for your sudo password.

    ./backup-vaultwarden.sh
    

    • Check the output for success messages.
    • Verify that a .tar.gz file has been created in /opt/vaultwarden-backups:
      ls -lh /opt/vaultwarden-backups
      
  6. Schedule Automated Backups with Cron:

    • Edit the crontab for the root user (necessary because the script uses sudo to access the Docker volume path and potentially delete old backups):
      sudo crontab -e
      
    • You might be asked to choose an editor (select nano if unsure).
    • Add the following line to the end of the file. This example schedules the backup to run daily at 2:30 AM. Adjust the path /home/your_user/backup-vaultwarden.sh to the actual full path where you saved your script.

      # Example: Run Vaultwarden backup daily at 2:30 AM
      30 2 * * * /home/your_user/backup-vaultwarden.sh >> /var/log/vaultwarden_backup.log 2>&1
      
      Explanation:

      • 30 2 * * *: Cron schedule (Minute=30, Hour=2, DayOfMonth=, Month=, DayOfWeek=*) -> Run at 2:30 AM every day.
      • /home/your_user/backup-vaultwarden.sh: Full path to your backup script. Replace your_user with your actual username.
      • >> /var/log/vaultwarden_backup.log: Appends the standard output of the script to a log file.
      • 2>&1: Redirects standard error (stderr) to the same place as standard output (stdout), so errors are also logged.
        • Save and close the crontab file (Ctrl+X, Y, Enter in nano).
  7. Verify Cron Job (Optional): List the cron jobs for root to ensure yours is listed:

    sudo crontab -l
    

Outcome: You have created a script that backs up your critical Vaultwarden data volume, compresses it, timestamps it, and optionally cleans up old backups. You have scheduled this script to run automatically using cron. Regularly check the log file (/var/log/vaultwarden_backup.log) for successful completion or errors. Remember this only creates local backups; implementing an off-site copy (e.g., using rclone to sync the backup directory to cloud storage) is the critical next step for a complete strategy.

User Administration and Organization Management

While Vaultwarden can be used individually, it also supports multi-user environments and secure sharing through Organizations. Administration tasks are primarily handled through the web-based Admin Panel.

Accessing the Admin Panel:

  • Navigate to https://vaultwarden.yourdomain.com/admin.
  • Enter the ADMIN_TOKEN you configured via environment variables.

Key Admin Panel Features:

  • Dashboard: Overview statistics (users, organizations, etc.).
  • Users:
    • View all registered users.
    • Manually invite new users (requires SMTP configuration and INVITATIONS_ALLOWED=true).
    • Force password resets (sends email if SMTP configured).
    • Edit user details (name).
    • Delete users (permanently removes the user and their personal vault).
    • Disable/Enable users.
  • Organizations:
    • View existing organizations.
    • Manually create new organizations.
    • Delete organizations (permanently removes the organization, its collections, and shared items - does not delete member user accounts).
  • Settings:
    • Configure general server settings (many overlap with environment variables; environment variables usually take precedence). You can disable signups, enable invitations, configure SMTP, etc., directly here if not set via environment variables.
    • Manage settings for Duo, YubiKey validation servers if used.
  • Diagnostics: View log files and other diagnostic information.

Organizations:

Organizations are the core feature for securely sharing credentials and notes among multiple users (e.g., family members, small teams).

  • Structure: An Organization contains Members (users) and Collections.
  • Collections: Think of Collections as folders within an Organization. Items (logins, notes) belonging to the Organization are placed into one or more Collections.
  • Permissions: Access control is managed by assigning users specific roles within the Organization (e.g., Owner, Admin, User, Manager) and granting them permissions to specific Collections (e.g., Read Only, Hide Passwords, Can Edit).
  • Creation: Organizations can be created by users (if allowed by server settings) or by the Admin via the Admin Panel.
  • Management: Once created, Organization Owners/Admins manage members, collections, and permissions through the regular Vaultwarden web vault interface (not the /admin panel). Users invited to an Organization will see it appear in their vault.

Use Cases:

  • Families: Share streaming service logins, Wi-Fi passwords, shared online shopping accounts.
  • Small Teams: Share access to development servers, internal tools, group email accounts.

Managing users and organizations allows Vaultwarden to scale beyond individual use, providing a collaborative password management solution under your control.

Workshop Creating Organizations and Managing Users

Goal: Use the Admin Panel to invite a new user (simulated if SMTP isn't configured) and then create an Organization through the regular web vault to share an item.

Prerequisites:

  • Vaultwarden running, accessible via HTTPS, with ADMIN_TOKEN set.
  • You can access the Admin Panel (https://vaultwarden.yourdomain.com/admin).
  • You are logged into your primary user account in the regular web vault.
  • (Optional but helpful) SMTP configured via environment variables to test actual email invitations.

Steps:

Part 1: User Management (Admin Panel)

  1. Access Admin Panel: Navigate to https://vaultwarden.yourdomain.com/admin and log in with your ADMIN_TOKEN.

  2. Navigate to Users: Click on Users in the top navigation bar. You should see your own user account listed.

  3. Invite a New User (Simulated/Actual):

    • Click the Invite User button.
    • Enter an email address for the new user (e.g., friend@example.com). Use a real secondary email you own if SMTP is configured and you want to test the full flow. Otherwise, any fake email works for simulation.
    • Click Save.
    • If SMTP is configured: The user will receive an email invitation with a link to create their account. They will set their own master password upon registration.
    • If SMTP is NOT configured: An invitation entry is created internally, but no email is sent. The user cannot register via this method. This step primarily demonstrates the interface. Alternatively, you could temporarily set SIGNUPS_ALLOWED=true, have the user register manually, and then set it back to false. For this workshop, we'll assume the user exists or simulate the invitation.
  4. (Optional) Observe User List: The invited (or manually registered) user should now appear in the Users list in the Admin Panel. You can click on their email to see details or perform actions like Disable/Delete.

Part 2: Organization Creation and Sharing (Web Vault)

  1. Log In to Web Vault: Go to https://vaultwarden.yourdomain.com and log in with your primary user account (not the Admin Token).

  2. Create a New Organization:

    • In the main vault view, look for an option to create a new organization. This might be a + button next to "Organizations" in the left pane or under Settings. Often, it's via the + New dropdown -> Organization.
    • Enter an Organization Name (e.g., Shared Logins).
    • Enter your Billing Email (this is just informational in Vaultwarden, enter your own email).
    • Choose a plan: Select the Free plan (Vaultwarden unlocks features often tied to paid plans in official Bitwarden).
    • Click Submit.
  3. Manage the Organization:

    • You should be taken to the Organization's management view (or find it listed under "Organizations" in the left pane).
    • Select the Manage tab within the Organization view.
    • Invite User: Click Invite User. Enter the email address of the user you invited/created in Part 1 (e.g., friend@example.com). Choose a User Type (e.g., User). Select Access Control (e.g., Regular user). Click Invite.
      • (If SMTP configured, the user gets an email to accept the Org invite).
  4. Create a Collection:

    • Still in the Organization's Manage tab, select Collections.
    • Click New Collection.
    • Enter a name (e.g., Streaming Services).
    • Click Save.
  5. Assign User Access to Collection:

    • Go back to the Members section within the Organization's Manage tab.
    • Click on the invited user (friend@example.com).
    • Under Collection Access, find the "Streaming Services" collection.
    • Select the desired permission level from the dropdown (e.g., Read Only or Can Edit).
    • Click Save.
  6. Add an Item to the Organization/Collection:

    • Go back to your main Vault view.
    • Click the + Add Item button.
    • Create a sample Login item (e.g., Name: Shared Netflix, User: shared@example.com, Pass: SharedPass123!).
    • Crucially: In the Ownership section at the bottom of the item form, select your Organization (Shared Logins) instead of "My Vault".
    • Once the Organization is selected, choose the Collection (Streaming Services) where this item should reside.
    • Click Save.
  7. Verify Item in Organization:

    • In your Vault, click on the Shared Logins Organization in the left pane.
    • You should see the "Streaming Services" collection and the "Shared Netflix" item within it.
  8. (Simulated) User Access: If the invited user (friend@example.com) were to log in and accept the Organization invitation, they would see the Shared Logins Organization in their vault. Clicking on it, they would see the Streaming Services collection and the Shared Netflix item, with permissions according to what you granted in Step 9.

Outcome: You have used the Admin Panel to manage users (simulated invitation) and the regular Web Vault to create an Organization, add a Collection, manage members, and share a vault item securely within that Organization. This demonstrates the collaborative capabilities of Vaultwarden.

Troubleshooting Common Issues

Even with careful setup, you might encounter issues. Here’s a breakdown of common problems and how to diagnose them:

1. Cannot Access Web UI (Connection Refused / Timeout):

  • Container Running? Check if the Vaultwarden and Reverse Proxy (NPM) containers are running: docker ps. If not, check logs: docker logs vaultwarden or docker logs npm. If stopped, try restarting: docker compose restart vaultwarden or docker compose restart npm. If they fail to start, logs are key.
  • Port Mapping (If direct access used initially): Double-check the -p HOST:CONTAINER mapping in docker run or docker-compose.yml. Is the host port correct? Is it being used by another service (sudo ss -tulnp | grep <port>)?
  • Reverse Proxy Config:
    • Is NPM running (docker ps)? Can you access the NPM admin UI (http://<server_ip>:81)?
    • In NPM -> Proxy Hosts, double-check the configuration for your Vaultwarden domain:
      • Domain name correct?
      • Forward Hostname / IP correct? (Should be the Vaultwarden service name from its docker-compose.yml, e.g., vaultwarden).
      • Forward Port correct? (Should be the internal port Vaultwarden listens on, usually 80).
      • Scheme correct? (http for proxy-to-Vaultwarden traffic).
    • Check NPM logs: docker logs npm. Look for errors related to your domain or upstream connection failures.
  • Firewall: Are ports 80 and 443 (for NPM/HTTPS) and potentially 8080 (if testing direct basic access) allowed on the server's firewall (sudo ufw status) and any cloud provider firewall?
  • DNS: Is your domain name (vaultwarden.yourdomain.com) correctly pointing to your server's public IP address? Use ping vaultwarden.yourdomain.com or nslookup vaultwarden.yourdomain.com from an external machine. Check DNS propagation.
  • Docker Network: Are Vaultwarden and NPM on the same custom Docker network (e.g., npm_network)? Inspect containers (docker inspect vaultwarden, docker inspect npm) and check the Networks section. If not, correct your docker-compose.yml files and recreate (docker compose down && docker compose up -d).

2. HTTPS / SSL Certificate Issues (Security Warnings):

  • Certificate Not Issued: Check the NPM UI for the Proxy Host's SSL tab. Did Let's Encrypt issue the certificate successfully? If not, check NPM logs (docker logs npm) for errors from Let's Encrypt (often related to DNS not propagating, port 80 not being open/reachable from the internet, or Let's Encrypt rate limits).
  • Mixed Content Warnings: Usually occurs if the DOMAIN environment variable in Vaultwarden's docker-compose.yml is not set correctly to the https:// address or if the reverse proxy isn't forcing HTTPS properly. Ensure DOMAIN=https://vaultwarden.yourdomain.com is set and NPM has "Force SSL" enabled.
  • Expired Certificate: NPM should automatically renew Let's Encrypt certificates. If it fails, check NPM logs. Ensure the NPM container is running correctly and can reach the internet.

3. Vaultwarden Container Fails to Start:

  • Check Logs: The absolute first step: docker logs vaultwarden. Look for specific error messages.
  • Volume Permissions: Sometimes Docker has issues writing to the volume mountpoint, especially if permissions were changed manually. Errors might mention "Permission denied" or database locking issues. Ensure the directory on the host (/var/lib/docker/volumes/vw-data/_data) has appropriate ownership/permissions for the user ID the container runs as (often can be found via docker inspect vaultwarden or may require research/testing). Using Docker managed volumes usually avoids this.
  • Incorrect Environment Variables: A typo or invalid value in an environment variable in docker-compose.yml can prevent startup. Review recent changes.
  • Port Conflicts (Internal): Less common, but ensure Vaultwarden isn't configured internally (e.g., via ROCKET_PORT env var if you changed it) to use a port already in use within the container's network namespace (unlikely unless complex setup).
  • Database Corruption: If the server crashed or the container was stopped uncleanly, the db.sqlite3 file might become corrupted. Logs might indicate database errors. Restoring from backup is the safest solution.

4. Clients Cannot Sync / Websockets Not Working:

  • WEBSOCKET_ENABLED=true: Ensure this environment variable is set in Vaultwarden's docker-compose.yml.
  • Reverse Proxy Websocket Support: Ensure "Websockets Support" is enabled in the NPM Proxy Host settings for your Vaultwarden domain. Check NPM logs if issues persist.
  • Firewall/Network: Ensure no intermediate firewall or proxy is blocking WebSocket connections (which use HTTP/S initially but then upgrade the connection).

5. Admin Panel (/admin) Inaccessible:

  • Correct URL: Ensure you're using https://vaultwarden.yourdomain.com/admin.
  • ADMIN_TOKEN Set? Check if ADMIN_TOKEN is defined in your docker-compose.yml. If not set, the admin panel is disabled by default.
  • Correct Token: Are you entering the exact token value? Copy-paste carefully.
  • Restart Container: If you recently added/changed the ADMIN_TOKEN, ensure you restarted the container (docker compose down && docker compose up -d).

General Troubleshooting Steps:

  • Check Logs: docker logs <container_name> is your best friend.
  • Simplify: Temporarily remove complexity. Bypass the reverse proxy? Disable recently added environment variables?
  • Check Resources: Is the server out of memory or disk space (free -h, df -h)?
  • Update: Ensure Docker, Docker Compose, and the Vaultwarden image (docker pull vaultwarden/server:latest, then docker compose up -d) are reasonably up-to-date.
  • Consult Documentation: Review the official Vaultwarden Wiki and Nginx Proxy Manager documentation.
  • Community: Search online forums or communities for similar error messages.

Workshop Diagnosing a Failed Container

Goal: Simulate a common configuration error in docker-compose.yml that prevents the Vaultwarden container from starting correctly, and then use diagnostic tools to identify and fix the problem.

Scenario: We will intentionally misconfigure an environment variable with an invalid value, causing Vaultwarden to fail during startup.

Prerequisites:

  • Your working Vaultwarden setup managed by docker-compose (~/vaultwarden/docker-compose.yml).
  • Access to the server's terminal.

Steps:

  1. Introduce a Configuration Error:

    • Edit your Vaultwarden docker-compose.yml file:
      nano ~/vaultwarden/docker-compose.yml
      
    • Go to the environment: section. Add a line with an invalid value for a known variable. For example, let's intentionally set LOG_LEVEL to an invalid option:
      environment:
        - WEBSOCKET_ENABLED=true
        - DOMAIN=https://vaultwarden.yourdomain.com
        - SIGNUPS_ALLOWED=false
        - ADMIN_TOKEN=your_existing_token # Keep your valid token
        - LOG_LEVEL=INVALID_OPTION # <-- INTRODUCE THIS ERROR
      
    • Save and close the file (Ctrl+X, Y, Enter).
  2. Attempt to Start the Container:

    • Navigate to the Vaultwarden directory: cd ~/vaultwarden
    • Run docker compose up -d:
      docker compose up -d
      
    • You might see an immediate error, or it might seem to start but then exit quickly.
  3. Check Container Status:

    • Run docker ps. You will likely not see the vaultwarden container listed as running.
    • Run docker ps -a. You should see the vaultwarden container listed with a status like Exited (1) or similar, indicating it started but stopped due to an error. Note the Container ID or Name.
  4. Inspect the Logs:

    • This is the most critical step for diagnosis. Use the container name (vaultwarden) or its ID from docker ps -a:
      docker logs vaultwarden
      
    • Read the log output carefully from the beginning or near the end. You should find error messages indicating the problem. In this case, you'll likely see an error related to the LOG_LEVEL configuration, possibly mentioning an "unknown variant INVALID_OPTION" or similar parsing error for the logging configuration. It might look something like:
      [INFO] No .env file found.
      
      ====================================================
      
      Error: Invalid value for LOG_LEVEL: unknown variant `INVALID_OPTION`, expected one of `trace`, `debug`, `info`, `warn`, `error`, `off`
      
      ====================================================
      
    • The logs clearly point to the invalid environment variable value.
  5. Correct the Configuration:

    • Re-edit the docker-compose.yml file:
      nano ~/vaultwarden/docker-compose.yml
      
    • Find the line - LOG_LEVEL=INVALID_OPTION.
    • Either remove the line entirely (to use the default 'info') or set it to a valid value like warn:

      environment:
        - WEBSOCKET_ENABLED=true
        - DOMAIN=https://vaultwarden.yourdomain.com
        - SIGNUPS_ALLOWED=false
        - ADMIN_TOKEN=your_existing_token
        - LOG_LEVEL=warn # <-- CORRECTED or REMOVED
      

    • Save and close the file.

  6. Restart the Container:

    • Run docker compose up -d again:
      docker compose up -d
      
    • Docker Compose will notice the configuration change and recreate the container.
  7. Verify Success:

    • Check the status: docker ps. The vaultwarden container should now be listed with status Up.
    • Check the logs again (optional): docker logs vaultwarden. You should see normal startup messages without the previous error.
    • Try accessing your Vaultwarden instance (https://vaultwarden.yourdomain.com) and the admin panel (/admin) to ensure everything is working as expected.

Outcome: You have successfully simulated a container startup failure due to a configuration error, used docker ps -a and docker logs to diagnose the root cause (invalid environment variable), corrected the docker-compose.yml file, and restarted the container successfully. This demonstrates a fundamental troubleshooting workflow for Dockerized applications.


Conclusion

Congratulations! You have journeyed through setting up, securing, managing, and maintaining your own Vaultwarden password manager instance.

Starting with the Basic deployment using docker run, you learned the fundamentals of Docker and got Vaultwarden running quickly. You understood the critical importance of persistent storage using Docker volumes, ensuring your data survives container restarts and updates.

Moving to the Intermediate level, you streamlined management by migrating to Docker Compose, making your configuration declarative and easier to handle. Most importantly, you secured your instance by implementing HTTPS using Nginx Proxy Manager as a reverse proxy, encrypting all communication and making it suitable for real-world use with a custom domain.

In the Advanced section, you delved into finer control using environment variables to customize Vaultwarden's behavior, disabling signups, and securing the admin panel. You enhanced account security by enabling Two-Factor Authentication (TOTP) and learned the vital importance of implementing robust, automated backup strategies to protect your sensitive vault data. You also explored user administration and the power of Organizations for secure sharing. Finally, you gained practical experience in troubleshooting common issues by inspecting container status and logs.

Key Takeaways:

  • Self-hosting gives you control but demands responsibility. Security, updates, and backups are paramount.
  • Docker and Docker Compose significantly simplify deployment and management.
  • HTTPS via a reverse proxy is non-negotiable for security.
  • Named volumes are essential for data persistence.
  • Regular, automated, and tested backups are your safety net.
  • Environment variables offer powerful customization.
  • Two-Factor Authentication dramatically increases account security.
  • Logs (docker logs) are crucial for troubleshooting.

You now possess the knowledge and practical skills to confidently host and manage Vaultwarden. Remember that ongoing maintenance – keeping your server OS, Docker, Vaultwarden, and reverse proxy updated, monitoring logs, and verifying backups – is crucial for long-term stability and security.

Continue exploring Vaultwarden's features, refine your backup strategy (especially adding off-site storage), and enjoy the peace of mind that comes with managing your own secure password vault.