Innovate | Connect | Transform
ContactService statusUSD $

GICT knowledge base

Self-Host Your Passwords: Vaultwarden on a VPS (Free Forever)

Published

Self Hosted
photo_5856341101449514740_y

Bitwarden charges $10 per year for premium. 1Password charges $36 per year. Both are good products. Neither of them needs to be your only option.

Vaultwarden is a fully open-source implementation of the Bitwarden server API. It runs on your VPS. It works with every official Bitwarden client: browser extension, iPhone app, Android app, desktop app. You get every feature Bitwarden offers, you own the server, you pay nothing after the cost of your VPS.

You are not switching ecosystems. You are switching who hosts it. Your passwords stay in your vault, on your hardware, under your control.

What Vaultwarden Actually Is

Vaultwarden is an alternative server implementation for the Bitwarden API. It was originally called Bitwarden_RS. The original Bitwarden server is written in .NET and requires significant resources. Vaultwarden is written in Rust and does the same job using roughly 50MB of RAM at idle.

One Docker container. No database setup. No .NET runtime. It just runs.

The compatibility is the key detail. This is not a clone with similar features. This is Bitwarden from the perspective of the client apps. Every official Bitwarden client speaks the same API whether the server on the other end is Bitwarden’s cloud or your own Vaultwarden instance. The clients cannot tell the difference. Neither can you, once it is set up.

What You Get for Free

The comparison to paid Bitwarden matters here because the value proposition is not just “self-hosted.” It is “self-hosted with every feature unlocked.”

  • Unlimited password storage
  • TOTP authenticator built in (generate codes for two-factor authentication)
  • Secure password sharing via organizations and collections
  • Bitwarden Send (share sensitive text or files with expiration links)
  • Emergency access (grant a trusted contact access to your vault if you cannot)
  • Full audit log for your vault
  • Import from any password manager that exports CSV (1Password, LastPass, KeePass, Dashlane)
  • All of the above included, no paid tier required

The only thing Vaultwarden does not natively support is the official Bitwarden password health reports and data breach monitoring. You can add that separately with a service like HaveIBeenPwned if you want it.

Step 1: Docker and Compose

Vaultwarden runs as a single Docker container. If you do not have Docker installed yet:

curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER

Log out and back in for the group change to take effect. Verify Docker is working:

docker --version
docker compose version

Create the directory where Vaultwarden will store its data:

mkdir -p ~/vaultwarden
cd ~/vaultwarden

Step 2: Generate the Admin Token

The admin panel at /admin requires a secure password hash. The Argon2id hash must be generated on your VPS. There are two ways to do this.

Method A: Using argon2 CLI (recommended for servers)

Install argon2 on your VPS and generate the hash directly:

sudo apt install -y argon2
SALT=$(openssl rand -base64 16)
echo "YourSecurePassword123" | argon2 "$SALT" -id -k 65540 -t 3 -p 4

Replace YourSecurePassword123 with a strong password you will remember. The output looks like:

$argon2id$v=19$m=65540,t=3,p=4$VWlDTW5ORStMc0RCWmtiRWtaT2s1QT09$Cj+Aed03zt5eDab3Cg/9QiCSCP0qtSyrXkzJKpJ4rFM

Copy the entire encoded string. You will use it in the next step.

Method B: Using Vaultwarden container (only works with a screen or fully interactive terminal)

If you are on a local machine with a screen session or physical access:

docker run --rm -it vaultwarden/server:latest /vaultwarden hash

Enter your password when prompted. Copy the output starting with $argon2id.

Step 3: Write the Docker Compose File

Create docker-compose.yml in the ~/vaultwarden directory. The dollar signs in the hash must be doubled ($$) so Docker Compose passes them through correctly:

cat > ~/vaultwarden/docker-compose.yml << 'EOF'
services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    environment:
      ADMIN_TOKEN: "$$argon2id$$v=19$$m=65540,t=3,p=4$$YOUR_SALT$$YOUR_HASH"
      DOMAIN: "https://vault.YOUR_DOMAIN_OR_NIP_IO"
      SIGNUPS_ALLOWED: "true"
      WEB_VAULT_ENABLED: "true"
    volumes:
      - ./vw-data:/data
    ports:
      - "8080:80"
EOF

Replace the three values in the ADMIN_TOKEN line:

  • YOUR_SALT and YOUR_HASH from the argon2 output
  • YOUR_DOMAIN_OR_NIP_IO with your actual domain or YOUR_VPS_IP.nip.io

For example, if your argon2 output is $argon2id$v=19$m=65540,t=3,p=4$VWlDTW5ORStMc0RC$CWOrkoo7oJBQ, the ADMIN_TOKEN line becomes:

ADMIN_TOKEN: "$$argon2id$$v=19$$m=65540,t=3,p=4$$VWlDTW5ORStMc0RC$$CWOrkoo7oJBQ"

Start the container:

docker compose up -d

Verify it is running with no “plain text” warning:

docker compose ps
docker logs vaultwarden --tail 10

You should see [start][INFO] Rocket has launched from http://0.0.0.0:80 with no “You are using a plain text ADMIN_TOKEN” message.

Step 4: nginx Reverse Proxy

Vaultwarden listens on port 8080 inside this setup. Set up nginx to forward traffic to it:

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

Paste this, replacing vault.YOUR_DOMAIN_OR_NIP_IO with your actual address:

server {
    listen 80;
    server_name vault.YOUR_DOMAIN_OR_NIP_IO;

    location / {
        proxy_pass http://127.0.0.1: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;
    }
}

Enable the site and reload nginx:

sudo ln -sf /etc/nginx/sites-available/vaultwarden /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Step 5: TLS with Let’s Encrypt

HTTPS is not optional. The Bitwarden browser extension requires a secure context and will refuse to connect over plain HTTP. Free TLS from Let’s Encrypt:

sudo certbot --nginx -d vault.YOUR_DOMAIN_OR_NIP_IO --non-interactive --agree-tos -m admin@YOUR_DOMAIN --redirect

Certbot handles the certificate issuance and nginx configuration update. Your Vaultwarden instance now serves over HTTPS with a valid certificate that renews itself automatically.

If you are using nip.io, the certificate will work exactly as it would for a regular domain. The DNS resolves to your VPS IP, Let’s Encrypt verifies you control that IP via HTTP, and the certificate is issued. No DNS configuration required.

Step 6: Disable Open Registration

After you create your account, you do not want strangers signing up on your server. Edit the docker-compose.yml and change:

    environment:
      SIGNUPS_ALLOWED: "false"

Then restart:

docker compose down
docker compose up -d

You can always re-enable signups temporarily if you need to invite someone.

Step 7: Connect Your Clients

Open the web vault in your browser at your domain. Create your account. Then connect every device you use:

In the Bitwarden app or browser extension, go to Settings > Self-hosted and enter your server URL:

https://vault.YOUR_DOMAIN_OR_NIP_IO

Save. The app connects to your server instead of Bitwarden’s cloud. All your passwords sync to your server from this point forward. Your master password never leaves your device. The encryption happens client-side before anything is transmitted.

The iPhone app, Android app, browser extension, and desktop app all work the same way. They all support custom server URLs. All your devices stay in sync.

The Admin Panel

Visit https://vault.YOUR_DOMAIN_OR_NIP_IO/admin and log in with the password you used to generate the Argon2 hash. Not the hash string itself, but the original password.

From the admin panel you can:

  • View all registered users and their vault activity
  • Force-delete user accounts
  • Configure SMTP settings so Vaultwarden can send invitation emails
  • Enable or disable features at the server level
  • Export a full system diagnostics report

Set up SMTP early. Without it, Vaultwarden cannot send password reset links or organization invitations. Any email provider that supports SMTP works: Gmail with an app password, SendGrid, or your own mail server.

Backups

The entire vault is stored in the ./vw-data directory mapped to /data inside the container. Back up that folder:

sudo tar -czf vaultwarden-backup-$(date +%Y%m%d).tar.gz ~/vaultwarden/vw-data

The key file inside vw-data is db.sqlite3, which contains your encrypted vault. Back this up regularly and store copies somewhere off the VPS. If the VPS fails, you restore from this backup.

Update Vaultwarden by pulling the latest image and recreating the container:

docker compose pull
docker compose up -d

Database migrations run automatically on startup. No manual steps.

Stop paying for a password manager. Deploy Vaultwarden on an InterServer VPS and own your vault. One container, no per-user fees, every device covered. Starting at $6/month with full root access and your data never leaving your server.

Related guides

Account services are unavailable until the production backend is configured.