Bitwarden is an open-source password manager alternative to 1Password and LastPass, providing zero-knowledge vault encryption with self-hosting control.
Software architect Kyle Spearrin created Bitwarden in 2016 to challenge commercial password managers that kept credentials inside proprietary, closed-source ecosystems. The project expanded from a personal vault into a complete credential platform supporting both managed cloud sync and self-hosted backend infrastructure. For developers and DevOps engineers, that origin guarantees verifiable cryptography alongside complete custody over secrets.
1Password centers its experience on polished consumer applications and built-in developer integrations like an SSH agent. Bitwarden matches those core needs with cross-platform desktop clients, browser extensions, mobile apps, and a scriptable command-line interface. Both platforms provide zero-knowledge encryption, shared organization vaults, and passkey support. Migrating between them requires only a vault export, though 1Password retains an edge in interface responsiveness and desktop biometric prompts.
The financial calculation diverges quickly as team size increases. 1Password requires mandatory cloud subscriptions costing roughly eight dollars monthly per user for business accounts, turning every contractor into ongoing overhead. Bitwarden provides a free tier with unlimited passwords across unlimited devices, while business plans run at four dollars per user monthly for Teams and six dollars for Enterprise with single sign-on. Furthermore, self-hosting the official Docker backend on internal servers carries zero software licensing fees for standard organization vaults, removing seat penalties as engineering teams expand.
bw CLI lets developers unlock vaults and inject credentials directly into shell scripts without manual copy-pasting.Is Bitwarden free for commercial use? Yes. Organizations can self-host the open-source server or run free accounts without fees, though enterprise capabilities like SAML single sign-on require a paid license.
Bitwarden vs 1Password — which should an engineering team choose? Choose 1Password for turnkey desktop biometric integration and polished SSH agents; choose Bitwarden for self-hosted server custody, open-source auditing, and lower per-seat expenses.
Can I self-host Bitwarden on my own server? Yes. Bitwarden provides official Docker Compose scripts to deploy the API, identity service, and database on Linux, macOS, or Windows servers.
Bitwarden is the right choice for engineering teams seeking auditable cryptography, self-hosted deployment flexibility, and predictable infrastructure spending, provided your operators can support a multi-container database stack. Active development with commits pushed through September 2026 and code distributed under the GPL-3.0 ensure dependable credential storage without proprietary lock-in.
These packages install the Bitwarden desktop client, not the server. Each package is matched to Bitwarden through the registry's own link to its source code or website.
brew install --cask bitwardenwinget install --id Bitwarden.Bitwarden -eflatpak install flathub com.bitwarden.desktopWe started this exact setup from scratch in a clean Linux machine on Nov 2, 2026 and checked it through Bitwarden's own API: every check passed. Recipes are re-checked regularly and removed if they stop working.
mkdir -p bitwarden && cd bitwarden
curl -fsSL https://open-source.store/tools/bitwarden/compose.yml -o compose.ymlcat > .env <<EOF
BASE_URL=http://localhost:8080
BW_INSTALLATION_ID=11111111-2222-3333-4444-555555555555
BW_INSTALLATION_KEY=$(openssl rand -hex 12)
POSTGRES_PASSWORD=$(openssl rand -hex 12)
EOFBASE_URL — Public HTTPS URL of the vault, e.g. https://vault.example.com; browsers require HTTPS to unlock the web vault.BW_INSTALLATION_ID — Installation ID in GUID format obtained from https://bitwarden.com/host.BW_INSTALLATION_KEY — Installation Key string obtained from https://bitwarden.com/host. Generated above; keep it secret.POSTGRES_PASSWORD — Password for the bundled PostgreSQL database. Generated above; keep it secret.docker compose up -dservices:
bitwarden:
image: ghcr.io/bitwarden/lite:2026.10.1
ports:
- "8080:8080"
environment:
BW_DOMAIN: localhost
BW_DB_PROVIDER: postgresql
BW_DB_SERVER: db
BW_DB_PORT: 5432
BW_DB_DATABASE: bitwarden_vault
BW_DB_USERNAME: bitwarden
BW_DB_PASSWORD: ${POSTGRES_PASSWORD}
BW_INSTALLATION_ID: ${BW_INSTALLATION_ID}
BW_INSTALLATION_KEY: ${BW_INSTALLATION_KEY}
BW_ENABLE_SSL: "false"
BW_PORT_HTTP: 8080
BACKUP_DB: "0"
globalSettings__baseServiceUri__vault: ${BASE_URL}
tmpfs:
- /tmp:rw,noexec,nosuid,nodev,size=768m
volumes:
- bitwarden-data:/etc/bitwarden
- bitwarden-logs:/var/log/bitwarden
depends_on:
db:
condition: service_healthy
restart: always
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8080/alive"]
interval: 5s
timeout: 5s
retries: 5
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: bitwarden_vault
POSTGRES_USER: bitwarden
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- bitwarden-db-data:/var/lib/postgresql/data
restart: always
healthcheck:
test: ["CMD-SHELL", "pg_isready -U bitwarden -d bitwarden_vault"]
interval: 5s
timeout: 5s
retries: 5
volumes:
bitwarden-data:
bitwarden-logs:
bitwarden-db-data:
Free IDE for Java, Kotlin, Go, TypeScript and Python. Built on IntelliJ Community, fully open source, 300+ plugins.
Show that Bitwarden is listed as an open-source alternative. Paste into your README:
Ubuntu 24.04 · Apple container, Docker 29.1.3, Compose 2.40.3+ds1-0ubuntu1~24.04.1. Images pulled in 621 s: ghcr.io/bitwarden/lite:2026.10.1, postgres:16-alpine.
Based on the upstream setup. Official Bitwarden Lite compose with bundled PostgreSQL database, SSL disabled for reverse proxying, and backup service disabled.
db-1 | 2026-11-02T01:23:01.673854677Z The files belonging to this database system will be owned by user "postgres". db-1 | 2026-11-02T01:23:01.673870510Z This user must also own the server process. db-1 | 2026-11-02T01:23:01.673872177Z db-1 | 2026-11-02T01:23:01.673897343Z The database cluster will be initialized with locale "en_US.utf8". db-1 | 2026-11-02T01:23:01.673899260Z The default database encoding has accordingly been set to "UTF8". db-1 | 2026-11-02T01:23:01.673900218Z The default text search configuration will be set to "english". db-1 | 2026-11-02T01:23:01.673901093Z db-1 | 2026-11-02T01:23:01.673901802Z Data page checksums are disabled. db-1 | 2026-11-02T01:23:01.673902593Z db-1 | 2026-11-02T01:23:01.673903302Z fixing permissions on existing directory /var/lib/postgresql/data ... ok db-1 | 2026-11-02T01:23:01.676232843Z creating subdirectories ... ok db-1 | 2026-11-02T01:23:01.676240552Z selecting dynamic shared memory implementation ... posix db-1 | 2026-11-02T01:23:01.684741177Z selecting default max_connections ... 100 db-1 | 2026-11-02T01:23:01.695632593Z selecting default shared_buffers ... 128MB db-1 | 2026-11-02T01:23:01.711862135Z selecting default time zone ... UTC db-1 | 2026-11-02T01:23:01.712221885Z creating configuration files ... ok db-1 | 2026-11-02T01:23:01.777217719Z running bootstrap script ... ok db-1 | 2026-11-02T01:23:01.858494052Z sh: locale: not found db-1 | 2026-11-02T01:23:01.858596052Z 2026-11-02 01:23:01.858 UTC [34] WARNING: no usable system locales were found db-1 | 2026-11-02T01:23:02.036106760Z performing post-bootstrap initialization ... ok db-1 | 2026-11-02T01:23:02.095061219Z syncing data to disk ... ok db-1 | 2026-11-02T01:23:02.095076677Z db-1 | 2026-11-02T01:23:02.095078219Z db-1 | 2026-11-02T01:23:02.095079344Z Success. You can now start the database server using: db-1 | 2026-11-02T01:23:02.095080427Z db-1 | 2026-11-02T01:23:02.095081344Z pg_ctl -D /var/lib/postgresql/data -l logfile start db-1 | 2026-11-02T01:23:02.095082302Z db-1 | 2026-11-02T01:23:02.095118135Z initdb: warning: enabling "trust" authentication for local connections db-1 | 2026-11-02T01:23:02.095125219Z initdb: hint: You can change this by editing pg_hba.conf or using the option -A, or --auth-local and --auth-host, the next time you run initdb. db-1 | 2026-11-02T01:23:02.117393219Z waiting for server to start....2026-11-02 01:23:02.117 UTC [40] LOG: starting PostgreSQL 16.15 on aarch64-unknown-linux-musl, compiled by gcc (Alpine 15.2.0) 15.2.0, 64-bit db-1 | 2026-11-02T01:23:02.118074469Z 2026-11-02 01:23:02.118 UTC [40] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" db-1 | 2026-11-02T01:23:02.120121302Z 2026-11-02 01:23:02.120 UTC [43] LOG: database system was shut down at 2026-11-02 01:23:02 UTC db-1 | 2026-11-02T01:23:02.122140260Z 2026-11-02 01:23:02.122 UTC [40] LOG: database system is ready to accept connections db-1 | 2026-11-02T01:23:02.211153594Z done db-1 | 2026-11-02T01:23:02.211432802Z server started db-1 | 2026-11-02T01:23:02.242508469Z CREATE DATABASE db-1 | 2026-11-02T01:23:02.243986135Z db-1 | 2026-11-02T01:23:02.243999052Z db-1 | 2026-11-02T01:23:02.244000594Z /usr/local/bin/docker-entrypoint.sh: ignoring /docker-entrypoint-initdb.d/* db-1 | 2026-11-02T01:23:02.244002260Z db-1 | 2026-11-02T01:23:02.244003177Z 2026-11-02 01:23:02.243 UTC [40] LOG: received fast shutdown request db-1 | 2026-11-02T01:23:02.244237760Z waiting for server to shut down....2026-11-02 01:23:02.244 UTC [40] LOG: aborting any active transactions db-1 | 2026-11-02T01:23:02.246769344Z 2026-11-02 01:23:02.246 UTC [40] LOG: background worker "logical replication launcher" (PID 46) exited with exit code 1 db-1 | 2026-11-02T01:23:02.246907469Z 2026-11-02 01:23:02.246 UTC [41] LOG: shutting down db-1 | 2026-11-02T01:23:02.247564552Z 2026-11-02 01:23:02.247 UTC [41] LOG: checkpoint starting: shutdown immediate db-1 | 2026-11-02T01:23:02.267365469Z 2026-11-02 01:23:02.266 UTC [41] LOG: checkpoint complete: wrote 926 buffers (5.7%); 0 WAL file(s) added, 0 removed, 0 recycled; write=0.009 s, sync=0.009 s, total=0.021 s; sync files=301, longest=0.003 s, average=0.001 s; distance=4283 kB, estimate=4283 kB; lsn=0/1925D20, redo lsn=0/1925D20 db-1 | 2026-11-02T01:23:02.269708844Z 2026-11-02 01:23:02.269 UTC [40] LOG: database system is shut down db-1 | 2026-11-02T01:23:02.350249635Z done db-1 | 2026-11-02T01:23:02.350261969Z server stopped db-1 | 2026-11-02T01:23:02.350741844Z db-1 | 2026-11-02T01:23:02.350746844Z PostgreSQL init process complete; ready for start up. db-1 | 2026-11-02T01:23:02.350748260Z db-1 | 2026-11-02T01:23:02.365989844Z 2026-11-02 01:23:02.365 UTC [1] LOG: starting PostgreSQL 16.15 on aarch64-unknown-linux-musl, compiled by gcc (Alpine 15.2.0) 15.2.0, 64-bit db-1 | 2026-11-02T01:23:02.365998302Z 2026-11-02 01:23:02.365 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432 db-1 | 2026-11-02T01:23:02.365999927Z 2026-11-02 01:23:02.365 UTC [1] LOG: listening on IPv6 address "::", port 5432 db-1 | 2026-11-02T01:23:02.367024094Z 2026-11-02 01:23:02.366 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" db-1 | 2026-11-02T01:23:02.369080844Z 2026-11-02 01:23:02.368 UTC [56] LOG: database system was shut down at 2026-11-02 01:23:02 UTC db-1 | 2026-11-02T01:23:02.370704385Z 2026-11-02 01:23:02.370 UTC [1] LOG: database system is ready to accept connections bitwarden-1 | 2026-11-02T01:23:07.779816096Z ......+.+..+.+.....+................+.....+...+..........+......+...............+...........+...+...+...............+...+++++++++++++++++++++++++++++++++++++++++++++*....+..+.+..+...+............+...+...+.+...+++++++++++++++++++++++++++++++++++++++++++++*..+.....+...+......................+.....+............+...+.......+...+...+.........+...+..+.+...+.....+.......+............+..+.........+...............+....+......+...........+.+............+..+.+..+.......+...+...........+....+.....+...+.......+..+.........+.+..............+.......+..............+......+............+............+....+.....+..........+......+...........+.............+.....+.........+......+......+.+............+.....+......+.+...+...+..............+....+......+...+............+..............+....+..+....+......+......+.........+...........+..................+....+..+...+.+..+....+........+.......+...+...........+..........+......+..............+......+.+.........+...+..+.............+.....+...............+................+..+.............+.....+......+...+.+..+....+...+..+.+........+.+...+........+...+....+...+.....+............+.+.....+..........+.....+.+...+..+...+....................................+.......+...+..+..........+..............+......+..........+........+...............+..........+..+...+....+..+......+.......+......+..+...+......+.+.....+.......+..+...+.......+........+............+.+.................+.+.....+....+........+.........+.+...+..+.......+........+..................+..........+..+..........+...+......+.....+...+.+..+..................+..................................+......+..........................+....+.....+.+......+..+......................+.....+.+...+.........+..+.+.....+....+...+..................+.........+...+..+.........+.........+...+............+...+...+....+...............+..+..........+...+........+....+........+.......+........+.............+.....+..........+...............+............+...+...+...............+..+....+...+...........+....+......+......+......+.....+.......+...+..+...+.......+...+............+........+....+...........+.............+..+...+.........+......+.........+......................+...+..+......+........................+...+......+...............+.+......+...+...........+....+......+....................+.+........+......+...+.+.....................+.........+..+....+.....+.+..+.+......+.....+....+.........+...+.....+.........+.+............+.....+...+.........+..........+......+...+....................+.......+..+.......+...+........+..........+...+..+............+++++ bitwarden-1 | 2026-11-02T01:23:07.792208013Z ....+++++++++++++++++++++++++++++++++++++++++++++*.+.+.....+......+.+........+.......+...+.........+++++++++++++++++++++++++++++++++++++++++++++*.+............+........+...+++++ bitwarden-1 | 2026-11-02T01:23:07.804469430Z ----- bitwarden-1 | 2026-11-02T01:23:15.751087211Z 2026-11-02 01:23:15,750 INFO Included extra file "/etc/supervisor.d/admin.ini" during parsing bitwarden-1 | 2026-11-02T01:23:15.751121252Z 2026-11-02 01:23:15,750 INFO Included extra file "/etc/supervisor.d/api.ini" during parsing bitwarden-1 | 2026-11-02T01:23:15.751123294Z 2026-11-02 01:23:15,751 INFO Included extra file "/etc/supervisor.d/backup.ini" during parsing bitwarden-1 | 2026-11-02T01:23:15.751124252Z 2026-11-02 01:23:15,751 INFO Included extra file "/etc/supervisor.d/events.ini" during parsing bitwarden-1 | 2026-11-02T01:23:15.751125127Z 2026-11-02 01:23:15,751 INFO Included extra file "/etc/supervisor.d/icons.ini" during parsing bitwarden-1 | 2026-11-02T01:23:15.751125961Z 2026-11-02 01:23:15,751 INFO Included extra file "/etc/supervisor.d/identity.ini" during parsing bitwarden-1 | 2026-11-02T01:23:15.751127419Z 2026-11-02 01:23:15,751 INFO Included extra file "/etc/supervisor.d/nginx.ini" during parsing bitwarden-1 | 2026-11-02T01:23:15.751133044Z 2026-11-02 01:23:15,751 INFO Included extra file "/etc/supervisor.d/notifications.ini" during parsing bitwarden-1 | 2026-11-02T01:23:15.751134086Z 2026-11-02 01:23:15,751 INFO Included extra file "/etc/supervisor.d/scim.ini" during parsing bitwarden-1 | 2026-11-02T01:23:15.751134919Z 2026-11-02 01:23:15,751 INFO Included extra file "/etc/supervisor.d/sso.ini" during parsing bitwarden-1 | 2026-11-02T01:23:15.752877919Z 2026-11-02 01:23:15,752 INFO RPC interface 'supervisor' initialized bitwarden-1 | 2026-11-02T01:23:15.752882752Z 2026-11-02 01:23:15,752 CRIT Server 'unix_http_server' running without any HTTP authentication checking bitwarden-1 | 2026-11-02T01:23:15.752943961Z 2026-11-02 01:23:15,752 INFO supervisord started with pid 1 bitwarden-1 | 2026-11-02T01:23:16.756860544Z 2026-11-02 01:23:16,755 INFO spawned: 'identity' with pid 61 bitwarden-1 | 2026-11-02T01:23:16.756881294Z 2026-11-02 01:23:16,756 INFO spawned: 'api' with pid 62 bitwarden-1 | 2026-11-02T01:23:16.768055169Z 2026-11-02 01:23:16,767 INFO spawned: 'admin' with pid 63 bitwarden-1 | 2026-11-02T01:23:16.769538378Z 2026-11-02 01:23:16,769 INFO spawned: 'icons' with pid 64 bitwarden-1 | 2026-11-02T01:23:16.778944336Z 2026-11-02 01:23:16,778 INFO spawned: 'notifications' with pid 65 bitwarden-1 | 2026-11-02T01:23:16.779944794Z 2026-11-02 01:23:16,779 INFO spawned: 'backup' with pid 66 bitwarden-1 | 2026-11-02T01:23:16.787291169Z 2026-11-02 01:23:16,787 INFO spawned: 'nginx' with pid 67 bitwarden-1 | 2026-11-02T01:23:16.787651128Z 2026-11-02 01:23:16,787 INFO exited: backup (exit status 0; expected) bitwarden-1 | 2026-11-02T01:23:32.277798218Z 2026-11-02 01:23:32,277 INFO success: identity entered RUNNING state, process has stayed up for > than 15 seconds (startsecs) bitwarden-1 | 2026-11-02T01:23:32.278813593Z 2026-11-02 01:23:32,278 INFO success: api entered RUNNING state, process has stayed up for > than 15 seconds (startsecs) bitwarden-1 | 2026-11-02T01:23:32.278853843Z 2026-11-02 01:23:32,278 INFO success: admin entered RUNNING state, process has stayed up for > than 15 seconds (startsecs) bitwarden-1 | 2026-11-02T01:23:32.278883135Z 2026-11-02 01:23:32,278 INFO success: icons entered RUNNING state, process has stayed up for > than 15 seconds (startsecs) bitwarden-1 | 2026-11-02T01:23:32.278974510Z 2026-11-02 01:23:32,278 INFO success: notifications entered RUNNING state, process has stayed up for > than 15 seconds (startsecs) bitwarden-1 | 2026-11-02T01:23:32.278976177Z 2026-11-02 01:23:32,278 INFO success: nginx entered RUNNING state, process has stayed up for > than 15 seconds (startsecs)