// DevOps

Vaultwarden: self-hosting a password manager in 30 minutes

Published on 2026-06-02

Vaultwarden — a lightweight implementation of the Bitwarden server written in Rust. It consumes only about 30 MB of RAM (instead of gigabytes for the official server), supports all official Bitwarden clients, and provides access to most premium features. An ideal solution for personal use or a small team.

What you’ll need

  • A VPS with Ubuntu 22.04/24.04 (1 vCPU and 1 GB RAM is usually sufficient).
  • Docker and Docker Compose installed.
  • A domain with an A record pointing to your server’s IP address.
  • An SMTP service for sending system emails (invitations, login confirmations).

1. Set up docker-compose.yaml

We’ll deploy a fully isolated stack: Vaultwarden and Nginx with automatic Let’s Encrypt certificate issuance acting as a reverse proxy.

Create a working directory and the file docker-compose.yaml:

yaml
services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    environment:
      - WEBSOCKET_ENABLED=true
      - SIGNUPS_ALLOWED=${VAULTWARDEN_SIGNUPS_ALLOWED}
      - ADMIN_TOKEN=${VAULTWARDEN_ADMIN_TOKEN}
    volumes:
      - ./vaultwarden-data:/data

  nginx:
    image: ${NGINX_IMAGE}
    container_name: nginx-proxy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    environment:
      - DOMAIN=${VAULTWARDEN_DOMAIN}
    volumes:
      - ./nginx-templates:/opt/nginx-templates:ro
      - ./letsencrypt:/etc/letsencrypt
    depends_on:
      - vaultwarden

Important: The ADMIN_TOKEN variable gives access to the admin web panel at /admin. After completing the initial setup, it is recommended to remove this token from the configuration.


2. Environment variables (.env)

Next to docker-compose.yaml, create a .env file:

env
# Basic settings
VAULTWARDEN_DOMAIN=vault.yourdomain.com
NGINX_IMAGE=your-preferred-nginx-image:latest

# Vaultwarden settings
VAULTWARDEN_SIGNUPS_ALLOWED=false
VAULTWARDEN_ADMIN_TOKEN=your_secure_generated_token

Generate a strong admin token:

bash
openssl rand -base64 48

3. Nginx configuration

Create the ./nginx-templates directory and inside it the file vaultwarden.conf.template:

nginx
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;
    server_name __VAULTWARDEN_DOMAIN__;

    ssl_certificate /etc/letsencrypt/live/__VAULTWARDEN_DOMAIN__/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/__VAULTWARDEN_DOMAIN__/privkey.pem;

    client_max_body_size 128m;

    # WebSocket for live-sync (since Vaultwarden 1.29+ uses the same port 80)
    location /notifications/hub {
        proxy_pass http://vaultwarden:80;
        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;
    }

    location / {
        proxy_pass http://vaultwarden:80;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 3600;
        proxy_send_timeout 3600;
    }
}

If the Nginx image does not support variable substitution — replace __VAULTWARDEN_DOMAIN__ with your actual domain manually and rename the file to .conf.


4. Start

bash
docker compose up -d

5. SMTP setup

Vaultwarden stores SMTP settings in the data/config.json file. This file takes precedence over environment variables in .env.

Quickly write mail settings:

python
python3 -c "
import json
with open('./vaultwarden-data/config.json') as f:
    c = json.load(f)
c.update({
    'smtp_host': 'mail.your-provider.com',
    'smtp_port': 587,
    'smtp_security': 'starttls',
    'smtp_username': 'your-username',
    'smtp_password': 'your-password',
    'smtp_from': 'no-reply@yourdomain.com',
    'smtp_from_name': 'Vaultwarden',
    '_enable_smtp': True,
})
with open('./vaultwarden-data/config.json', 'w') as f:
    json.dump(c, f, indent=2)
"

After changing the configuration:

bash
docker compose restart vaultwarden

Caveat: Ports 25 and 587 are often blocked by cloud providers. If mail is not sent — try 2525 or 8025.


6. Managing signups

By default signups are disabled (SIGNUPS_ALLOWED=false). Enable only when you need to add a new user:

bash
# Open signups
sed -i 's/VAULTWARDEN_SIGNUPS_ALLOWED=false/VAULTWARDEN_SIGNUPS_ALLOWED=true/' .env
docker compose up -d --force-recreate vaultwarden

# Close after the user has created an account
sed -i 's/VAULTWARDEN_SIGNUPS_ALLOWED=true/VAULTWARDEN_SIGNUPS_ALLOWED=false/' .env
docker compose up -d --force-recreate vaultwarden

If signups don’t enable via .env — check the value of "signups_allowed" inside config.json: it takes precedence.


7. What to back up?

FileImportanceDescription
db.sqlite3CriticalThe main DB with all encrypted passwords
rsa_key.pemCriticalEncryption keys
config.jsonImportantServer configuration (SMTP, etc.)
attachments/ImportantFiles attached to notes

Never copy db.sqlite3 directly while the server is running — use the built-in command:

bash
sqlite3 ./vaultwarden-data/db.sqlite3 ".backup /backup/db.sqlite3"

Clients

All official Bitwarden clients work with your server. On first login click the gear (server settings) and set the Self-hosted URL field to https://vault.yourdomain.com.

Available for: Chrome, Firefox, Safari, iOS, Android, macOS, Windows, Linux and CLI.


Summary

Deploying Vaultwarden takes no more than half an hour with minimal resources. Main caveats: SMTP ports availability, config.json taking precedence over .env, and that starting from version 1.29 WebSocket operates on the main port 80, not a separate 3012.

// Reviews

Related reviews

I needed to get n8n, Redis, and the database working. I had hired another contractor before and everything kept breaking. I hired Mikhail, and the next day everything was working quickly, like clockwork!

There was a task to get n8n, redis and the database working. I had previously ordered from another contractor, it kept breaking all the time. Ordered from Mikhail, the next day everything started working fast, like …

christ_media

n8n installation on your VPS server. Configuration of n8n, Docker, AI, Telegram

2025-09-24 · ★ 5/5

Experienced buyer

Quick solution — I highly recommend Mikhail as a contractor! I tried to build a similar configuration myself and even followed AI advice, which ended up costing a lot of time and money (due to server downtime). So my advice: hire professionals — it's cheaper =) Thanks to Mikhail for his professionalism.

Quick fix for the problem, I recommend Mikhail as a contractor to everyone! I tried to assemble a similar configuration myself and following advice from neural networks, which resulted in a lot of wasted effort and …

ladohinpy

n8n installation on your VPS server. Configuration of n8n, Docker, AI, Telegram.

2025-08-25 · ★ 5/5

// Contact

Need help?

Get in touch with me and I'll help solve the problem

Message on Telegram

Отвечаю в течение рабочего дня (03:00–13:00 GMT)

Или оставьте заявку здесь:

Send request
Write and get a quick reply