8.2.8 Vaultwarden Deployment and Configuration on a Server

The Host Bit Banner

Vaultwarden is a lightweight server-side version of the Bitwarden password manager, written in Rust. It enables you to securely store and sync your passwords on your own server and is fully compatible with official Bitwarden clients.

System Requirements

  • An ordered Virtual Server or Dedicated Server
  • CPU: from 1 core, RAM: from 1 GB (2 GB is comfortable)
  • SSD: from 5 GB
  • OS: Ubuntu 22.04 or 24.04 LTS
  • Domain name pointing to your server (A record)
  • Open ports 80 and 443 (firewall)
  • sudo or root access
  • Docker and Docker Compose installed

Security

  • Never expose Vaultwarden to the public without HTTPS;
  • It is recommended to use a separate VPS or dedicated server;
  • Set up regular backups and store them separately.

Installing Docker and Docker Compose

Before installing Vaultwarden, you need to install Docker and Docker Compose. Docker allows you to run the application in an isolated container, avoiding complex manual dependency installation and simplifying further updates.

Execute the following commands in sequence to install Docker and Docker Compose, and start the Docker service:

Install Docker
sudo apt update && sudo apt upgrade -y
sudo apt install docker.io docker-compose -y
sudo systemctl enable docker --now

docker_install

Creating the Project Structure and .env

To organize your data and configuration, create a separate folder for Vaultwarden. This folder will contain:

  • The Docker Compose file
  • The data directory (volume)
  • The .env file with environment variables

Navigate to your working directory and create the required directories:

Creating the directory
sudo mkdir -p /opt/vaultwarden/data
cd /opt/vaultwarden

Now create the .env file — here you will store settings that are easy to update without editing the Docker Compose file itself:

.env
ADMIN_TOKEN=Replace_with_a_strong_token
DOMAIN=https://your-domain.com
DATA_FOLDER=/opt/vaultwarden/data

You can generate a strong token with the command:

openssl rand -base64 48

You’ll need this token to access the Vaultwarden admin panel.

Docker Compose File for Vaultwarden

Now create the main configuration file — docker-compose.yml. It defines which container to use, what environment variables are set, how volumes are mounted, and which networks the app uses. Open an editor and create the file:

docker-compose.yml
version: '3'

services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: always
    environment:
      - ADMIN_TOKEN=${ADMIN_TOKEN}
      - DOMAIN=${DOMAIN}
      - WEBSOCKET_ENABLED=true
    volumes:
      - ${DATA_FOLDER}:/data
    networks:
      - vaultwarden-net
    expose:
      - "80"
      - "3012"

networks:
  vaultwarden-net:
    driver: bridge

Note: We are not exposing any ports externally (ports), so Vaultwarden will only be available through the internal Docker network, increasing security. External ports are proxied via Nginx.

Configuring Nginx as a Reverse Proxy for SSL (HTTPS)

To ensure the server operates securely and supports HTTPS, use Nginx as a reverse proxy. Nginx will accept external requests, automatically forward them to the Vaultwarden container over a secure connection, and handle the SSL certificate. Install Nginx and Certbot:

Installing Nginx and Certbot
sudo apt install nginx certbot python3-certbot-nginx -y

nginx_installation

Create an Nginx site configuration file:

sudo nano /etc/nginx/sites-available/vaultwarden.conf

Obtaining and Installing a Let’s Encrypt SSL Certificate

If you cannot obtain the certificate while Nginx is running, stop Nginx:

sudo systemctl stop nginx

Run Certbot to automatically configure HTTPS:

sudo certbot --nginx -d your-domain.com

certbot_ssl_activate

Follow the prompts and agree to automatic certificate renewal.

Start Nginx again (if you stopped it):

sudo systemctl start nginx

Insert and edit the following content:

/etc/nginx/sites-available/vaultwarden.conf

# ================================================================
# 1. Redirect all HTTP requests to HTTPS
# ================================================================

server {
    listen 80;
    listen [::]:80;
    server_name your-domain.com;  # Replace your-domain.com with your actual domain

    # Redirect all requests to HTTPS
    return 301 https://$host$request_uri;
}

# ================================================================
# 2. Handle HTTPS on 443 with Let's Encrypt certificate
# ================================================================

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name your-domain.com;  # Replace your-domain.com with your actual domain

    # Paths to the Let’s Encrypt certificate and key
    ssl_certificate     /etc/letsencrypt/live/your-domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;

    # Additional security optimizations (recommended)
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    
    # Recommended Diffie-Hellman parameters (optional but future-proof)
    # ssl_dhparam /etc/ssl/certs/dhparam.pem;

    # Disable server tokens (reduce information leakage)
    server_tokens off;

    # Root location — proxy to the container’s internal port (localhost:8080)
    location / {
        proxy_pass http://127.0.0.1:8080;   # If the port is mapped to localhost:8080
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Extend timeouts under high load
        proxy_read_timeout 90;
        proxy_connect_timeout 90;
    }

    # WebSocket endpoint for notifications
    location /notifications/hub {
        proxy_pass http://127.0.0.1:3012;  # If the port is mapped to localhost:3012
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # If needed: limit request body size (for large attachments)
    client_max_body_size 128M;
}

Create a symbolic link to enable the site:

sudo ln -s /etc/nginx/sites-available/vaultwarden.conf /etc/nginx/sites-enabled/

Reload Nginx:

sudo nginx -t
sudo systemctl reload nginx

If the symbolic link was not created previously, run again:

sudo ln -s /etc/nginx/sites-available/vaultwarden.conf /etc/nginx/sites-enabled/

Check Nginx syntax:

sudo nginx -t

Ensure there are no errors. If an error appears, fix it according to the message.

Restart Nginx:

sudo systemctl restart nginx

Docker → Nginx Proxy Setup

Vaultwarden should only be accessible via the Nginx proxy. To achieve this, configure port forwarding in Docker Compose so Nginx can proxy client traffic to the container. After making these changes, restart the service — your application will be accessible via HTTPS and your domain.

Update docker-compose.yml and restart Vaultwarden:

    ports:
      - "8080:80"
      - "3012:3012"

Apply the changes:

sudo docker-compose up -d

docker-compose-up

Starting Vaultwarden

Once everything is configured, start all services using Docker Compose:

sudo docker-compose up -d

You can always check the status of your services with:

docker-compose ps

docker-compose_ps

Checking Operation and Testing

  • Open https://your-domain.com in your browser
  • Register the first user
  • To access the admin panel, use: https://your-domain.com/admin?admin_token=YOUR_TOKEN

Vaultwarden_WebInterface

Supported Vaultwarden Clients

Vaultwarden is fully compatible with official Bitwarden clients. This means you can use any Bitwarden app to access your self-hosted Vaultwarden server:

Client Capabilities:

  • Synchronize passwords, cards, notes, and files across devices
  • Autofill passwords in browsers and apps
  • Use two-factor authentication (TOTP, WebAuthn)
  • Organize collections and collaborate in teams (organizations)

Official Bitwarden Clients

Platform Where to get it
Web client In your browser: https://your-domain.com (your Vaultwarden address)
Browser extension Chrome Web Store, Firefox Add-ons
Desktop client Windows/macOS/Linux
Mobile app Google Play, App Store
CLI (command line) Bitwarden CLI

How to Connect to Your Vaultwarden Server

  1. On the login screen in any official Bitwarden client, look for the “Self-hosted environment” or “Use a self-hosted server” option.

bitwarden self-hosted

  1. Enter your server address:

    https://your-domain.com # your domain where Vaultwarden is deployed
    
  2. Log in or register your account. Your data will be stored directly on your server.

Important: Some older mobile clients may, by default, only work with bitwarden.com. If you don’t see the “Self-hosted” option, update your app to the latest version!

CLI Client

For advanced users and DevOps, Bitwarden CLI is available:

bw login user@domain.com

To specify your server:

bw login user@domain.com --server https://your-domain.com

Changing the Server in the Apps

  • On desktop and mobile clients: in the settings (usually on the login screen), select “Self-hosted” and enter your Vaultwarden URL.
  • In browser extensions: open the extension settings, find the “Server” option, and enter your domain.
  • Via web: simply open https://your-domain.com in your browser.
Table of common issues and quick solutions
Issue Solution
Site does not open via HTTPS Check the certificate, domain, Nginx config, firewall
Admin panel does not work Check the ADMIN_TOKEN variable, don’t forget ?admin_token=
“Cannot write to /data” Check permissions: chown -R 1000:1000 /opt/vaultwarden/data
Mail notifications not working Configure SMTP environment variables in Docker Compose
Container won’t start Check logs: docker-compose logs vaultwarden
Certificate does not renew Run manually: sudo certbot renew