Why migrate now
In 2026, the 1Password Individual plan billed annually has gone from $35.88/yr to $47.88/yr, a 33% increase. In January 2026, Bitwarden.com had already raised its Premium plan from $10 to $19.80 per year — nearly double. Both increases coming so close together made self-hosting economically obvious for developers who already have a VPS: Vaultwarden, written in Rust and much lighter than the official Bitwarden server, runs with no software license fee, at a fixed monthly cost equal to an entry-level VPS.
The most common objection — "managing my own password manager is risky" — does not hold against Vaultwarden's architecture. Encryption is done entirely client-side, using AES-256-CBC with PBKDF2 or Argon2id key derivation: the server never sees your passwords in plaintext, even in the event of a full machine compromise.
What Vaultwarden brings to a developer
- AES-256-CBC client-side encryption — your passwords never leave your device in plaintext, regardless of the server configuration.
- Full compatibility with all official Bitwarden clients: browser extensions, iOS, Android, desktop apps and CLI, without any modifications.
- Lightweight memory footprint — written in Rust, Vaultwarden is built for self-hosting where the official, more resource-heavy Bitwarden server is not a good fit.
- Fixed cost — a 1 vCPU / 512 MB VPS is enough for personal use or a small team, with no variable SaaS subscription.
- Full data control — backup, restore, datacenter choice and retention period remain in your hands.
- Multi-profile and organization support — Vaultwarden supports organization management and vault sharing, just like Bitwarden.com.
- Decoupled updates — you choose when to update the server; official Bitwarden clients manage their own release cycle.
Prerequisites before you start
Before starting the migration, make sure you have all of the following.
Server side: a VPS with at least 1 vCPU and 512 MB of RAM, Docker and Docker Compose installed, a domain name pointing to the server IP, and a reverse proxy (Caddy or Nginx) configured for TLS termination. The Vaultwarden deployment itself is covered in the article Deploy Vaultwarden on a VPS — this guide assumes your instance is already online and accessible over HTTPS.
Local workstation: 1Password v8 or later installed (required to export in .1pux format), Bitwarden CLI (bw) installed via npm (npm install -g @bitwarden/cli) or the official binary, and Node.js ≥ 22 if installing via npm.
Step 1 — Export your 1Password vault
Open the export dialog
On macOS, open 1Password and go to File → Export. On Windows, click the ellipsis (…) at the top of the sidebar, then Export. Select the account to export — if you have multiple vaults, you can export the entire account in a single operation.
Choose the 1PUX format
In the dialog box, enter your 1Password account password to confirm the operation. Then select the 1Password Unencrypted Export (.1pux) format. This JSON-based format preserves the full structure — custom fields, secure notes, identities, application passwords — unlike CSV, which only exports Login and Password items, without custom fields.
Save the file somewhere safe
Choose an encrypted local folder (FileVault or BitLocker enabled) to store the
.1puxfile. This file contains all your secrets in structured plaintext — do not leave it in a downloads folder or send it by email. Once the migration is complete, delete it securely.
Step 2 — Import with Bitwarden CLI
Point the CLI to your Vaultwarden instance
By default,
bwpoints tobitwarden.com. Redirect it to your instance before anything else:bw config server https://vault.your-domain.comVerify the response: the CLI should print "Saved setting
config."Log in and unlock the vault
Authenticate with your Vaultwarden credentials (email + master password set during initial setup):
bw login [email protected]The CLI will prompt for your master password interactively. Once logged in, unlock the vault and export the session key:
export BW_SESSION=$(bw unlock --raw)All subsequent commands use this variable implicitly to access the decrypted vault.
Run the .1pux import
Import your 1Password export using the
1password1puxformat:bw import 1password1pux /path/to/export.1puxThe CLI replies
Imported /path/to/export.1pux; if it had to skip items, it lists them with the reason. If your 1Password account contained multiple vaults, they are all imported into a single Bitwarden vault — folders are created from each item's first tag, not from the 1Password vaults.If the import fails, verify the file has the
.1puxextension (the CLI only unzips the archive under that extension) and that you are using a recent CLI version (bw --version).Verify the import in a Bitwarden client
Open the Bitwarden browser extension or desktop app, point the server to your Vaultwarden instance, then log in. Browse your vaults and check a sample of passwords — in particular entries with custom fields, secure notes and identities, which are most likely to vary between password managers. File attachments are not imported: add them by hand. Passkeys are not included in a 1Password desktop export: create them again on each site.
Step 3 — Vaultwarden on your VPS
If your Vaultwarden instance is not yet deployed, follow the guide Deploy Vaultwarden on a VPS, which covers the full Docker configuration. In summary, three points are non-negotiable before importing anything:
HTTPS required. Bitwarden clients refuse to connect to a server without valid TLS. Caddy or Nginx with Let's Encrypt (certbot) are sufficient; verify your domain is reachable over https:// before configuring the CLI.
Correct DOMAIN variable. In your docker-compose.yml, the variable DOMAIN=https://vault.your-domain.com must match exactly the URL you declared in bw config server — no trailing slash.
Volume backup before import. The import writes to Vaultwarden's SQLite database (/data/db.sqlite3). Take a snapshot of your Docker volume before running bw import, so you can roll back if the import goes wrong.
Close sign-ups afterwards. Once your account is created, set SIGNUPS_ALLOWED=false and recreate the container: otherwise anyone who can reach the instance can open an account on it. If you enable the admin page, ADMIN_TOKEN must be an Argon2 hash generated with vaultwarden hash, not a plaintext token.
1Password vs Bitwarden.com vs Vaultwarden
Scroll the table
| Criterion | 1Password | Bitwarden.com | Vaultwarden (self-hosted) |
|---|---|---|---|
| Annual cost (individual) | $47.88/yr since 2026 | $19.80/yr since Jan. 2026 (Premium) | VPS cost only |
| Data control | 1Password servers | Bitwarden servers | Your VPS, your datacenter |
| Encryption | AES-256-GCM client-side | AES-256-CBC client-side | AES-256-CBC client-side (identical) |
| Official mobile clients | Dedicated 1Password apps | iOS, Android, desktop, extension | Official Bitwarden clients, unmodified |
| Browser extension | 1Password extension | Bitwarden extension | Bitwarden extension (same binary) |
| Updates | Automatic (SaaS) | Automatic (SaaS) | Manual (you choose the timing) |
| Server RAM required | N/A (SaaS) | N/A (SaaS) | Low (lightweight server written in Rust) |
Back up and test restoration
Once the import is complete, set up automated backups of the Vaultwarden volume before disabling your 1Password account. The guide Restic backups on a VPS covers a Docker-adapted 3-2-1 strategy: stop the container, snapshot the volume, send encrypted to remote storage, restart. Test restoration on a separate machine — not just the presence of the backup file — before considering the migration done. A password vault without a tested restore is not a backup.
Troubleshooting — common errors
Proper importer type required. on import. The format expected by the CLI is exactly 1password1pux (no spaces, lowercase). Make sure you are not using 1password alone or 1pux — neither is a recognized file format (the older 1PIF format from 1Password 7 and earlier is called 1password1pif). List available formats with bw import --formats | grep 1password.
ERR_CERT_AUTHORITY_INVALID in clients. Bitwarden clients require a TLS certificate signed by a recognized authority — a self-signed certificate is only accepted if every device trusts the authority that issued it. Verify that Let's Encrypt has issued a valid certificate for your domain and that it is not expired.
Existing Bitwarden.com account. If you import from an existing Bitwarden.com account before switching to Vaultwarden, your items remain encrypted with the cloud account key. After bw config server pointing to your instance, create a new local account: the CLI does not migrate the encryption key between instances, only plaintext data transits via import.
Import stops on an SSH entry. In some CLI versions, a single non-compliant SSH key in the 1pux file made the whole import fail (Failed to parse key, issue bitwarden/clients #20432). Since CLI version 2026.8.0 (August 2026), the faulty item is skipped and listed, and the rest is imported; create that key again by hand. Update with npm install -g @bitwarden/cli@latest if you encounter this behavior.
Leaving 1Password with confidence
Once the import is verified on the Vaultwarden side — open each item type (logins, notes, identities, cards) in a Bitwarden client and check a representative sample — you can deactivate your 1Password account. Do not wait for your subscription to expire before deleting the local .1pux file: it contains all your secrets in structured plaintext.
To go further in securing your infrastructure, the articles Initial Linux server hardening and Passbolt for a team cover the next steps: port lockdown, SSH key management and secure sharing in a team context.