// 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:
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:
- vaultwardenImportant: The
ADMIN_TOKENvariable 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:
# 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_tokenGenerate a strong admin token:
openssl rand -base64 483. Nginx configuration
Create the ./nginx-templates directory and inside it the file vaultwarden.conf.template:
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
docker compose up -d5. 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:
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:
docker compose restart vaultwardenCaveat: Ports
25and587are often blocked by cloud providers. If mail is not sent — try2525or8025.
6. Managing signups
By default signups are disabled (SIGNUPS_ALLOWED=false). Enable only when you need to add a new user:
# 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 vaultwardenIf signups don’t enable via
.env— check the value of"signups_allowed"insideconfig.json: it takes precedence.
7. What to back up?
| File | Importance | Description |
|---|---|---|
db.sqlite3 | Critical | The main DB with all encrypted passwords |
rsa_key.pem | Critical | Encryption keys |
config.json | Important | Server configuration (SMTP, etc.) |
attachments/ | Important | Files attached to notes |
Never copy db.sqlite3 directly while the server is running — use the built-in command:
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
The collaboration left an extremely positive impression, primarily because of the professionalism and the approach to resolving issues as they arose.
The experience of working together left an extremely positive impression, above all because of the professionalism and the approach to solving the issues that arose.
Jitsi Meet: a personal Zoom — setup in Docker and on a VPS
2025-11-11 · ★ 5/5
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 …
n8n installation on your VPS server. Configuration of n8n, Docker, AI, Telegram
2025-09-24 · ★ 5/5
Thank you for the fast and excellent work. Everything was done promptly and just as needed!
Thank you for the quick and good work. Everything was done promptly and as needed!
n8n installation on your VPS server. Configuration of n8n, Docker, AI, Telegram
2025-09-06 · ★ 5/5
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 …
n8n installation on your VPS server. Configuration of n8n, Docker, AI, Telegram.
2025-08-25 · ★ 5/5
Mikhail completed the setup of another VPS. He quickly and professionally bypassed certain hosting providers' restrictions.
Mikhail completed the setup of another VPS. Quickly, professionally bypassing certain limitations of hosting providers.
n8n installation on your VPS server. n8n, Docker, AI, Telegram setup
2025-08-12 · ★ 5/5
Great job, thank you! Mikhail is a true professional — I recommend him!
Excellent work, thank you! Mikhail is a professional in his field, I recommend him!
N8n installation on your VPS server. Setup of n8n, Docker, AI, Telegram
2025-07-03 · ★ 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)
Или оставьте заявку здесь:
// Related