Useful virtual machine for cyber security - Vaultwarden (Bitwarden)

Posted on 28 May 2025 by Mino 4 min

Useful virtual machine for cyber security - Vaultwarden (Bitwarden)

Managing your passwords through third parties isn't always the best practice, therefore I use vaultwarden, which can be deployed on my own infrastructure without subscription and need for external provider.

Prerequisites

  • Software
  • [Hardware / VM parameters]
    • CPU: 2 i* or ryzen * cores
    • RAM: 2GB+
    • Disk: 32GB+
  • Other: Trusted Certificate, please check the guide on how to achieve this here.

Vaultwarden

Since I use docker for the deployment and compose file already on Dani Garcia's vaultwarden github, feel free to use mine, which is also behind reverse proxy. Configuration for the proxy is the standard one I use from this article.

services:
  vault:
    image: vaultwarden/server:latest
    container_name: vault
    restart: always
    environment:
      SMTP_HOST: "smtphost.example.com"
      SMTP_FROM: "senfrom@example.com"
      SMTP_EXPLICIT_TLS: true
      SMTP_USERNAME: "sendfrom@example.com"
      SMTP_PASSWORD: "password"
      ORG_CREATION_USERS: "email@example.com"
      ICON_SERVICE: "https://static.example.com/icons/{}/icon.png"
    volumes:
      - /home/god/data:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
      - /etc/passwd:/etc/passwd:ro
    networks:
      internal:
    healthcheck:
      test: ["CMD", "curl", "-f", "-k", "http://vault"]
      interval: 10s
      retries: 3
      start_period: 30s
      timeout: 10s
  vault_proxy:
    image: nginx:latest
    container_name: vault_proxy
    restart: unless-stopped
    read_only: true
    volumes:
      - /home/god/proxy/conf.d:/etc/nginx/conf.d:ro
      - /home/god/proxy/ssl:/etc/nginx/ssl:ro
      - cache:/var/cache/nginx
      - run:/var/run
    ports:
      - "0.0.0.0:80:80"
      - "0.0.0.0:443:443"
    networks:
      internal:

networks:
  internal:

volumes:
  cache:
  run:

All variables for the environment can be set through admin interface, which can be accessed through /admin. To be able to login on this page, you have to set environment variable ADMIN_TOKEN to a value produced running command written below. After running this command escape all $ with $$. Feel free to remove this environment variable, it will be stored in a file under data directory in config.json file along with all other configuration done through this interface.

Link to the original documentation

sudo apt install argon2 -y
echo -n "MySecretPassword" | argon2 "$(openssl rand -base64 32)" -e -id -k 65540 -t 3 -p 4

As an example, please find my config file (which has sensitive data removed) below.

{
  "domain": "https://vault.example.com",
  "sends_allowed": true,
  "incomplete_2fa_time_limit": 3,
  "disable_icon_download": false,
  "signups_allowed": false,
  "signups_verify": false,
  "signups_verify_resend_time": 3600,
  "signups_verify_resend_limit": 6,
  "invitations_allowed": true,
  "emergency_access_allowed": true,
  "email_change_allowed": true,
  "password_iterations": 600000,
  "password_hints_allowed": false,
  "show_password_hint": false,
  "admin_token": "$argon2id$v=19$m=65540,t=3,p=4$...",
  "invitation_org_name": "Vaultwarden",
  "ip_header": "X-Real-IP",
  "icon_redirect_code": 302,
  "icon_cache_ttl": 2592000,
  "icon_cache_negttl": 259200,
  "icon_download_timeout": 10,
  "http_request_block_non_global_ips": true,
  "disable_2fa_remember": false,
  "authenticator_disable_time_drift": false,
  "require_device_email": false,
  "reload_templates": false,
  "log_timestamp_format": "%Y-%m-%d %H:%M:%S.%3f",
  "admin_session_lifetime": 20,
  "increase_note_size_limit": false,
  "_enable_yubico": false,
  "_enable_duo": false,
  "_enable_smtp": true,
  "use_sendmail": false,
  "smtp_security": "starttls",
  "smtp_port": 587,
  "smtp_from_name": "Vaultwarden",
  "smtp_timeout": 15,
  "smtp_embed_images": true,
  "smtp_accept_invalid_certs": false,
  "smtp_accept_invalid_hostnames": false,
  "_enable_email_2fa": false,
  "email_token_size": 6,
  "email_expiration_time": 600,
  "email_attempts_limit": 3,
  "email_2fa_enforce_on_verified_invite": false,
  "email_2fa_auto_fallback": false
}

One last note is regarding ICON_SERVICE, which if you want to use a custom one, feel free to use a static nginx server which has a folder structure as follows. I use this so I can add custom domains and no service will have access to the theoretical list of my stored passwords in vaultwarden

data
|-icons
| |-www.hackthissite.org
| | |-icon.png

Other useful variables and settings can be found in the template .env file with great details and explanations here.

Alternatives

  • Passbolt - more focused on team work / team sharing, but at the time I was using it, it was unable to store the passwords locally / in offline form
  • Bitwarden - if you have a subscription or you want to host original server, I did try it just to find out that I need a subscription for 2fa, which I could not afford at that time.

This post was written without the help of AI.