Vaultwarden Self Host on VPS

How to self-host Vaultwarden on your own VPS with daily cloud backups.


Table of Contents


Overview

This Tutorial covers:

  • Setting up Vaulwarden on a Docker container using Portainer.io.
  • Reverse proxy via Nginx with SSL
  • Secure backup of the database
  • Encryption using age
  • Automatic upload to Dropbox
  • Disaster recovery procedure

Prerequisites

  • VPS running Ubuntu 24.04 (or similar)
  • Docker + Portainer already installed
  • Your domain configured via Nginx reverse proxy
  • Access to your VPS as root
  • Dropbox account for offsite backup

I'll be using "https://vault.your-domain.com" as the example domain name through the guide, make sure to replace it with your own sub and domain name each time.

Deploy the Vaultwarden container (on Portainer)

  • Go to Portainer
Image not found
Portainer Dashboard
  • Click "Stacks" in the Side menu
Image not found
Portainer Stacks
  • Click "Add Stack"
Image not found
Portainer Add Stack
  • Fill in Name and content
Image not found
Portainer Stack Name and Content
nginx
Name
1
vaultwarden
yaml
Content
1
version: "3.9"
2
3
services:
4
vaultwarden:
5
image: vaultwarden/server:latest
6
container_name: vaultwarden
7
restart: unless-stopped
8
ports:
9
- "127.0.0.1:8222:80"
10
volumes:
11
- /opt/vaultwarden/data:/data
12
environment:
13
DOMAIN: https://vault.your-domain.com
14
SIGNUPS_ALLOWED: false
15
WEBSOCKET_ENABLED: true
16
ADMIN_TOKEN: CHANGE_ME
17
LOG_LEVEL: warn

Before deploying the stack, generate the admin token in SSH:

bash
1
openssl rand -base64 48
  • replace "your-domain" in https://vault.your-domain.com with your domain. The vault. part is the sub domain name, you can change this too if you like.
  • replace CHANGE_ME with the generated token and deploy the stack
  • deploy the stack

Create DNS record

In your domain DNS panel add: (I'm using easyhost.be)


TypeNameValue
Avault[your-vps-ip]
Image not found
EasyHost A Record

Add Vaultwarden to Nginx

We will NOT edit the existing file (safer). We will create a new one.

Create Config

bash
1
sudo nano /etc/nginx/sites-available/vault.your-domain

Add:

nginx
1
server {
2
server_name https://vault.your-domain.com;
3
4
location / {
5
proxy_pass http://127.0.0.1:8222;
6
proxy_http_version 1.1;
7
8
proxy_set_header Upgrade $http_upgrade;
9
proxy_set_header Connection "upgrade";
10
proxy_set_header Host $host;
11
12
proxy_set_header X-Real-IP $remote_addr;
13
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
14
proxy_set_header X-Forwarded-Proto $scheme;
15
}
16
}

Save (press ctrl + o, then enter, then ctrl + x)


Enable it:

bash
1
sudo ln -s /etc/nginx/sites-available/vault.your-domain /etc/nginx/sites-enabled/

Get HTTPS Certificate

Run:

bash
1
sudo certbot --nginx -d vault.your-domain.com

Choose redirect to HTTPS when asked.
This will automatically add SSL config like the main site should have.

Reload Nginx and Test

bash
1
sudo systemctl reload nginx

Access the admin panel

Open in your browser
https://vault.your-domain.com/admin

Image not found
Vaultwarden Admin Token
  • Vaultwarden will ask for the ADMIN_TOKEN you generated earlier with:
bash
1
openssl rand -base64 48
  • paste that token and you'll be logged into the admin interface

Create new User

  1. In the admin panel go to Invite User
    Image not found
    Vaultwarden Admin Users
    Image not found
    Vaultwarden Admin Invite User
  2. Enter the email for that user.
  3. Go back to https://vault.your-domain.com and click Create Account
    Image not found
    Vaultwarden Create Account
  4. Enable Two-step login for extra security.
    Image not found
    Vaultwarden Two-step Login
Attention

For the Master Password, write this down on a paper and keep it safe.
You cannot and should not store this password in Vaultwarden.
Because your Vaulwarden master password is NOT recoverable.
Not by you, not by the server, not even by Bitwarden devs.
If you lose it, your vault is permanently encrypted garbage.

Find Container Volume

  1. Go to Portainer, go into Vaultwarden container and scroll down to Volumes
    Image not found
    Portainer Vaultwarden Volumes
  2. run this command:
bash
1
ls /opt/vaultwarden/data

It should give you this or similar as result:

bash
1
config.json db.sqlite3-shm icon_cache tmp
2
db.sqlite3 db.sqlite3-wal rsa_key.pem

Test manual backup

We'll create a backup folder:

bash
1
mkdir -p /root/backups/vaultwarden

Now copy the database:

bash
1
cp -r /opt/vaultwarden/data /root/backups/vaultwarden/backup-$(date +%F)

Confirm with:

bash
1
ls /root/backups/vaultwarden

You should see:

bash
1
backup-yyyy-mm-dd

Obviously yyyy-mm-dd will be the current year, month and day.

Make Automatic daily backups

Create a backup script:

bash
1
nano /root/backup-vaultwarden.sh

Add this as it's content:

bash
1
#!/bin/bash
2
3
BACKUP_DIR="/root/backups/vaultwarden"
4
DATA_DIR="/opt/vaultwarden/data"
5
DATE=$(date +%F)
6
7
mkdir -p $BACKUP_DIR
8
9
# Stop container
10
docker stop vaultwarden
11
12
# Copy database
13
cp -r $DATA_DIR $BACKUP_DIR/backup-$DATE
14
15
# Start again
16
docker start vaultwarden
17
18
# Delete backups older than 14 days
19
find $BACKUP_DIR -type f -mtime +14 -delete

save (press ctrl + 0, then enter, then ctrl + x) Make the file executable:

bash
1
chmod +x /root/backup-vaultwarden.sh

Schedule nightly backups

Open cron:

bash
1
crontab -e

Choose 1 if asked.

Add this line at the bottom:

bash
1
0 4 * * * /root/backup-vaultwarden.sh >> /root/backup.log 2>&1

This means:

Every day at 04:00 will a backup be taken.

Install the Encryption tool

on the VPS (SSH):

bash
1
apt install age -y

Create your Peronal Backup key

This key is the only thing that can decrypt your vault backups.

Run:

bash
1
age-keygen -o /riit/vaultwarden-backup.key

You should sees something like:

bash
1
Public key: age1m9v...abcxyz

Two important things were created:

FilePurpose
`/root/vaulwarden-backup.key`SECRET - keep forever
public key (printed)used to encrypt
Attention

Download vaultwarden-backup.key to your PC using FileZilla or winSCP and save it on a USB drive and write it down as well on that same paper you wrote the Vaultwarden master password on. If you lose this file, your backups are unrecoverable.

Modify the backup script to encrypt

Open the script:

bash
1
nano /root/backup-vaultwarden.sh

Update the script:

bash
1
#!/bin/bash
2
3
BACKUP_DIR="/root/backups/vaultwarden"
4
DATA_DIR="/opt/vaultwarden/data"
5
DATE=$(date +%F)
6
TMP_DIR="/tmp/vaultwarden-backup"
7
8
mkdir -p $BACKUP_DIR
9
rm -rf $TMP_DIR
10
mkdir -p $TMP_DIR
11
12
# Stop container
13
docker stop vaultwarden
14
15
# Copy database
16
cp -r $DATA_DIR $BACKUP_DIR/backup-$DATE
17
cp -r $DATA_DIR $TMP_DIR/data
18
19
# Start container again immediately
20
docker start vaultwarden
21
22
# Create archive
23
tar -czf $TMP_DIR/backup-$DATE.tar.gz -C $TMP_DIR data
24
25
# Encrypt archive
26
age -r $(grep '^# public key:' /root/vaultwarden-backup.key | cut -d' ' -f4) \
27
-o $BACKUP_DIR/backup-$DATE.tar.gz.age \
28
$TMP_DIR/backup-$DATE.tar.gz
29
30
# Remove unencrypted files
31
rm -rf $TMP_DIR
32
rm -f $BACKUP_DIR/*.tar.gz
33
34
# Delete backups older than 14 days
35
find $BACKUP_DIR -type f -mtime +14 -delete

save (press ctrl + 0, then enter, then ctrl + x) Make executable again just in case:

bash
1
chmod +x /root/backup-vaultwarden.sh

Test Encrypt backup

Run manually once:

bash
1
/root/backup-vaultwarden.sh

Then check:

bash
1
ls /root/backups/vaultwarden

You should see

bash
1
backup-yyyy-mm-dd.tar.gz.age

Obviously yyyy-mm-dd will be the current year, month and day.

Restore backups

It's important to understand this process, you should only execute these steps when needed.

  • Download Age on your pc (not the VPS)
  • Look for age-vx.x.x-windows-amd64.zip if you're using windows
  • Extract this zip file and copy age.exe and age-keygen.exe to another folder on your pc. e.g.: Documents/age. You should then place the vaultwarden-backup.key from step 14 in that same folder Documents/age. If you hadn't downloaded that file yet, now it's the time to do so.
  • Then download as well the encrypted backup file (the most recent one) using FileZilla or winSCP and place it in that same folder.
  • Now you should have a total of 4 files in Documents/age.
  • Type cmd in the path bar on the top and press enter
    Image not found
    Documents/age cmd
  • Run this command:
bash
1
age -d -i vaultwarden-backup.key backup-2026-02-15.tar.gz.age > backup.tar.gz
  • You'll see this file in Documents/age:
    Image not found
    Documents/age backup.tar
  • Windows can extract tar.gz file directly. or run:
bash
1
tar -xzf backup.tar.gz
  • You should now see a data folder and that is exactly what goes back into a new Vaulwarden server.
    Image not found
    Documents/age data folder

Install rclone on the VPS

Now to make automatic backups instead of having to do it manually, we can install rclone on the VPS:

bash
1
apt install rclone -y

Install rclone on your pc

  • Go to rclone authorize and extract the downloaded zip file.
  • go into this extracted folder, type cmd in the path bar on the top and press enter.
    Image not found
    rclone cmd
  • Run the follow command:
bash
1
rclone authorize "dropbox"
  • This will open your browser automatically, login to dropbox and allow access.
  • At the end it should print a long JSON token, copy that entire JSON string. Don't close this window yet just incase you need to copy it again in the next step.

Connect the VPS to Dropbox

Of course you can also use OneDrive, GoogleDrive or any online cloud service supporting rclone. Start setup:

bash
1
rclone config

You'll see a menu, follow exactly:

bash
1
n) New remove
2
name> dropbox
3
Storage> dropbox
4
client_id> (press enter)
5
client_secret> (press enter)
6
Edit advanced config> n
7
Use auto config> n
  • paste the JSON token from your PC when prompted.

Test Dropbox connection

  • Run this command:
bash
1
rclone lsd dropbox:

You should see your Dropbox folders (if any).

  • Now create a folder for backups:
bash
1
rsclone mkdir dropbox:vaultwarden-backups

Modify the backup script to auto upload

open the script again:

bash
1
nano /rook/backup-vaultwarden.sh

Update the script:

bash
1
nano /root/backup-vaultwarden.sh

Update the script:

bash
1
#!/bin/bash
2
3
BACKUP_DIR="/root/backups/vaultwarden"
4
DATA_DIR="/opt/vaultwarden/data"
5
DATE=$(date +%F)
6
TMP_DIR="/tmp/vaultwarden-backup"
7
8
mkdir -p $BACKUP_DIR
9
rm -rf $TMP_DIR
10
mkdir -p $TMP_DIR
11
12
# Stop container
13
docker stop vaultwarden
14
15
# Copy database
16
cp -r $DATA_DIR $TMP_DIR/data
17
18
# Start container again immediately
19
docker start vaultwarden
20
21
# Create archive
22
tar -czf $TMP_DIR/backup-$DATE.tar.gz -C $TMP_DIR data
23
24
# Encrypt archive
25
age -r $(grep '^# public key:' /root/vaultwarden-backup.key | cut -d' ' -f4) \
26
-o $BACKUP_DIR/backup-$DATE.tar.gz.age \
27
$TMP_DIR/backup-$DATE.tar.gz
28
29
# Remove unencrypted files
30
rm -rf $TMP_DIR
31
rm -f $BACKUP_DIR/*.tar.gz
32
33
# Delete backups older than 14 days
34
find $BACKUP_DIR -type f -mtime +14 -delete
35
36
# Auto upload to dropbox
37
rclone copy $BACKUP_DIR dropbox:vaultwarden-backups --progress

save (press ctrl + 0, then enter, then ctrl + x) Make executable again just in case:

Final Test

Run following command:

bash
1
/root/backup-vaultwarden.sh
  • Now check Dropbox website and you should see a backup-yyyy-mm-dd.tar.gz.age file the vaultwarden-backups folder.

Conclusion

Now at the end of this tutorial if you have followed everything you should have a fully setup Vaultwarden container and a script running once daily that

  • stops vaultwarden briefly
  • backups database
  • encrypt backup
  • uploads to dropbox
  • removes unencrypted backup files
  • keeps 30 days history (on vps, dropbox is unaffected).