Vaultwarden - Hardened Self-Hosted Password Server
Autor: Lynxroute
Vaultwarden - CIS Level 1 hardened self-hosted password manager on Ubuntu 24.04 LTS with SBOM.
What is Vaultwarden
Vaultwarden is a lightweight, self-hosted password manager server written in Rust. It implements the Bitwarden client API, so it works with all official Bitwarden clients on Windows, macOS, Linux, Android, iOS, and the browser extensions - your team gets the same client experience while the vault data lives entirely on your own infrastructure. Compared to running the official server stack, Vaultwarden has a much smaller footprint (single binary plus SQLite by default), starts instantly, and is the practical choice for small to medium teams that want a self-hosted vault without operating multiple containers.
Why self-host Vaultwarden
Self-hosting puts every credential, secure note, and vault item under your own control - no per-user SaaS fees, no third-party visibility into who is logging in or which vaults are syncing. Ideal for teams with data residency requirements, organisations operating under regulated frameworks (HIPAA, GDPR, ISO 27001), and MSPs that need to keep customer secrets inside their own tenant.
What this VM image adds
Security hardening:
- Argon2id admin token generated per instance - 48-character random token, hashed with OWASP-recommended Argon2id parameters at first boot, never the same on two deployments
- Vaultwarden runs as non-root - dedicated vaultwarden system user, no shell, locked home directory
- Localhost-only application binding - Vaultwarden listens on 127.0.0.1:8080, exposed externally only through the hardened nginx reverse proxy
- SQLite database owned by vaultwarden user - 0640 permissions, UMask=0027 enforced via systemd
- RSA JWT signing key generated per instance - tokens issued by your server cannot be replayed against any other deployment
- Certbot pre-installed - one command issues a Let's Encrypt certificate, no extra apt steps after deployment
- CVE scan - every image is scanned with Trivy before release
- UFW firewall - only ports 80, 443, and 22 open; internal port 8080 explicitly denied
- fail2ban - SSH brute-force protection
- AppArmor - mandatory access control
OS hardening (CIS Level 1):
- CIS Level 1 hardened - CIS Ubuntu 24.04 LTS Level 1 Benchmark via ansible-lockdown
- auditd - system call auditing for critical paths
- SSH hardening - PasswordAuthentication disabled, key-only access
- Kernel hardening - SYN cookies, ASLR, rp_filter, TCP BBR
- /tmp as tmpfs - nosuid, nodev, noexec
- Azure IMDS endpoints - egress rules pre-configured (169.254.169.254, 168.63.129.16)
Compliance artifacts (inside the VM):
- SBOM - CycloneDX 1.6 at /etc/lynxroute/sbom.json
- CIS Conformance Report - OpenSCAP HTML at /etc/lynxroute/cis-report.html
- Tailored CIS profile - /usr/share/doc/lynxroute/CIS_TAILORED_PROFILE.md
- Server credentials file - /root/vaultwarden-credentials.txt with public IP, web UI URL, and the per-instance admin token
Quick Start
- Deploy VM from Azure Marketplace (Standard_B2s or larger recommended)
- Open NSG: TCP 80 and 443 from your client networks - SSH 22 from your management IPs only
- SSH: ssh -i key.pem <username>@<PUBLIC_IP> (username set during VM creation, default: azureuser)
- Read connection details: sudo cat /root/vaultwarden-credentials.txt - contains web UI URL and the unique admin token
- Issue an HTTPS certificate (Vaultwarden web vault requires HTTPS): sudo certbot --nginx -d your.domain.com, then set DOMAIN=https://your.domain.com in /etc/vaultwarden/vaultwarden.env and restart vaultwarden
- In Bitwarden clients (desktop, mobile, browser extension): Settings - Server URL: https://your.domain.com
Vaultwarden web vault requires HTTPS - the Web Crypto API used by the client only works on a secure context. Run certbot before sharing the URL with end users.