{"id":405,"date":"2026-09-05T21:23:09","date_gmt":"2026-09-06T00:23:09","guid":{"rendered":"https:\/\/www.linuxpro.com.br\/2026\/09\/vaultwarden-bitwarden-self-hosted\/"},"modified":"2026-10-05T14:08:28","modified_gmt":"2026-10-05T17:08:28","slug":"vaultwarden-bitwarden-self-hosted","status":"publish","type":"post","link":"https:\/\/www.linuxpro.com.br\/en\/2026\/09\/vaultwarden-bitwarden-self-hosted\/","title":{"rendered":"Vaultwarden: self-hosted Bitwarden on Linux"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" alt=\"Mascote do LinuxPro girando o volante de um cofre com o emblema do Vaultwarden, com notebook e celular sincronizando senhas e o cachorro caramelo deitado de guarda\" src=\"\/wp-content\/uploads\/2026\/10\/vaultwarden-v5.webp\" width=\"1486\" height=\"856\" \/><\/p>\n<div style=\"background:#fff8e1;border-left:4px solid #8b1a1a;padding:.8em 1em;margin:1em 0\"><strong>Update (05\/10\/2026):<\/strong> guide revised for the <a href=\"https:\/\/github.com\/dani-garcia\/vaultwarden\/releases\/tag\/1.37.3\">version 1.37.3<\/a>, from 13\/09\/2026. It added the built-in backup command, the persistent volume requirement, native SSO, the security fixes from 1.37.0, and an installation diagram.<\/div>\n<p>The <a href=\"https:\/\/github.com\/dani-garcia\/vaultwarden\">Vaultwarden<\/a> is a server <strong>compatible with official Bitwarden clients<\/strong>, written in Rust. It fits on a Raspberry Pi, uses very little memory, and delivers in self-host features that the official Bitwarden only offers on a paid plan, such as the integrated TOTP authenticator and emergency access. It is not Bitwarden Inc.: it's the community project (formerly<em>bitwarden_rs<\/em>), under AGPL-3.0 license, now at <strong>1.37.3<\/strong>.<\/p>\n<p><!-- more --><\/p>\n<p>If you already have a Linux box on the internet and don't want to send your vault to anyone's cloud, this is the short path: one container, HTTPS in front, and the official apps pointed at your domain.<\/p>\n<h2>What it is (and isn't)<\/h2>\n<p>The apps (Android, iOS, desktop, browser extension, CLI) speak the Bitwarden API, and Vaultwarden implements that API. The vault stays <strong>encrypted on the client<\/strong> (zero-knowledge): items arrive at the server already encrypted with a key derived from your master password, and the server cannot read them.<\/p>\n<ul>\n<li><strong>Useful for<\/strong> you, your family, your homelab, a small team. It runs on SQLite (default), MySQL, or PostgreSQL. In our test, the freshly started container with no users used about 10 MiB of RAM.<\/li>\n<li><strong>Not suitable for<\/strong> a company needing SOC 2, an SLA and support from Bitwarden Inc. The project <em>has no equivalent formal audit<\/em>. You are the backup, the patch and the firewall.<\/li>\n<\/ul>\n<p>Keep an eye on versions, because the official clients evolve fast: 1.37.0 is required for clients 2026.7.0 and later, and 1.37.2 for 2026.8.0 and later. 1.37.0, from July 2026, also fixed a bundle of security flaws (SSRF on the icons endpoint, cross-organization item access, unauthenticated WebSocket flooding, among others), and 1.37.3 started revoking 2FA \u201cremember this device\u201d tokens when the password or 2FA change. Since 1.35.0 (December 2025), single sign-on (SSO) via OpenID Connect is native, enabled with <code data-no-translation=\"\">SSO_ENABLED<\/code>. SCIM and Secrets Manager remain exclusive to official Bitwarden.<\/p>\n<h2>Deploy with Docker and Caddy<\/h2>\n<p>The recommended path from upstream is the container. HTTPS is required: the web vault uses the Web Crypto API, which the browser only allows in a secure context. The <a href=\"\/en\/2026\/10\/caddy-no-linux-servidor-web-com-https-automatico\/\">Caddy<\/a> obtains and renews the certificate on its own. (If Docker is still new to you, there's the <a href=\"\/en\/2017\/08\/curso-de-docker-gratis\/\">Docker course<\/a>.)<\/p>\n<figure><img loading=\"lazy\" decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/10\/vaultwarden-docker-compose-caddy.webp\" alt=\"Diagrama: clientes Bitwarden acessam por HTTPS o container do Caddy, que encaminha para o container do Vaultwarden; os dados ficam no volume vw-data, com db.sqlite3, rsa_key.pem, anexos, sends e config.json; o comando vaultwarden backup gera uma c\u00f3pia do banco, que segue com o tar para uma c\u00f3pia externa\" width=\"1200\" height=\"640\" \/><figcaption>Caddy handles TLS termination and is the only one publishing ports; Vaultwarden stays on the Compose internal network; the data volume is what needs to be backed up.<\/figcaption><\/figure>\n<p>Generate the admin panel token (Argon2) <em>before<\/em> from compose. The command asks for the password twice and prints the hash:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">docker run --rm -it vaultwarden\/server:1.37.3 \/vaultwarden hash\n<\/code><\/pre>\n<p>Paste the string <code data-no-translation=\"\">$argon2id$...<\/code> in the YAML. In Compose, each <code data-no-translation=\"\">$<\/code> becomes <code data-no-translation=\"\">$$<\/code>.<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">mkdir -p \/opt\/vaultwarden &amp;&amp; cd \/opt\/vaultwarden\n<\/code><\/pre>\n<pre data-no-translation=\"\"><code class=\"language-yaml\" data-no-translation=\"\"># \/opt\/vaultwarden\/compose.yaml\nservices:\n  vaultwarden:\n    image: vaultwarden\/server:1.37.3\n    container_name: vaultwarden\n    restart: unless-stopped\n    environment:\n      DOMAIN: \"https:\/\/vault.exemplo.com.br\"\n      SIGNUPS_ALLOWED: \"true\"\n      ADMIN_TOKEN: \"$$argon2id$$v=19$$m=65540,t=3,p=4$$COLE_O_HASH\"\n    volumes:\n      - .\/vw-data:\/data\n\n  caddy:\n    image: caddy:2\n    container_name: vw-caddy\n    restart: unless-stopped\n    ports:\n      - \"80:80\"\n      - \"443:443\"\n      - \"443:443\/udp\"\n    volumes:\n      - .\/Caddyfile:\/etc\/caddy\/Caddyfile:ro\n      - caddy_data:\/data\n      - caddy_config:\/config\n    depends_on:\n      - vaultwarden\n\nvolumes:\n  caddy_data:\n  caddy_config:\n<\/code><\/pre>\n<pre data-no-translation=\"\"><code class=\"language-text\" data-no-translation=\"\"># \/opt\/vaultwarden\/Caddyfile\nvault.exemplo.com.br {\n\tencode zstd gzip\n\treverse_proxy vaultwarden:80\n}\n<\/code><\/pre>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\"># DNS do dom\u00ednio \u2192 IP desta m\u00e1quina, depois:\ndocker compose up -d\ndocker compose logs -f\ncurl -s https:\/\/vault.exemplo.com.br\/alive<\/code><\/pre>\n<p>The <code data-no-translation=\"\">\/alive<\/code> responds with the server date and time when everything is up. Don't forget the volume <code data-no-translation=\"\">.\/vw-data:\/data<\/code>: without a persistent volume, the current Vaultwarden refuses to start and shows <em>No persistent volume!<\/em> in the log. It's a safeguard so you don't lose the vault when recreating the container.<\/p>\n<p>Anyone who already has nginx (ISPConfig, for example) can skip the Caddy service: publish Vaultwarden only on <code data-no-translation=\"\">127.0.0.1:8000<\/code> and proxy with Let's Encrypt in nginx. The WebSocket uses the same port 80 of the container; the old port 3012 is no longer needed.<\/p>\n<h2>First login and disabling registration<\/h2>\n<p>Open <code data-no-translation=\"\">https:\/\/vault.exemplo.com.br<\/code> and create <strong>your<\/strong> account. Then close the door:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-yaml\" data-no-translation=\"\">SIGNUPS_ALLOWED: \"false\"\n<\/code><\/pre>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">docker compose up -d\n<\/code><\/pre>\n<p>Subsequent invitations come from the <code data-no-translation=\"\">\/admin<\/code>, with the token you generated. Without <code data-no-translation=\"\">ADMIN_TOKEN<\/code>, the panel doesn't even exist \u2014 and that's how it should be if you don't plan to use it. If you use SSO, the 1.37.3 brought the <code data-no-translation=\"\">SSO_SIGNUPS_ALLOWED<\/code> to separately control the registration through this path.<\/p>\n<p>Enable 2FA on the vault (TOTP or FIDO2) on the first day. It is the same Bitwarden app; the only difference is the server.<\/p>\n<h2>Pointing official clients at it<\/h2>\n<p>In any Bitwarden app, on the login screen: <strong>Self-hosted<\/strong> \u2192 paste <code data-no-translation=\"\">https:\/\/vault.exemplo.com.br<\/code>. Log in with the email of the account you created. Browser extension, phone and CLI (<code data-no-translation=\"\">bw config server<\/code>) use the same URL.<\/p>\n<p>Do not report Vaultwarden bugs to Bitwarden Inc. support. The README is explicit: issues and discussions go to the project's GitHub and Matrix.<\/p>\n<h2>Backup \u2014 without one, there's no vault<\/h2>\n<p>The volume <code data-no-translation=\"\">.\/vw-data<\/code> is the vault: <code data-no-translation=\"\">db.sqlite3<\/code>, <code data-no-translation=\"\">rsa_key.pem<\/code> (signs the login tokens), attachments, Sends, and the <code data-no-translation=\"\">config.json<\/code> from the admin panel. Copying the SQLite file with the service running can generate an inconsistent copy; the binary itself has a command that makes a safe copy of the database, without stopping anything:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">docker compose exec vaultwarden \/vaultwarden backup\n# Backup to 'data\/db_20261005_170645.sqlite3' was successful<\/code><\/pre>\n<p>A daily script that generates this copy, packages the volume without the \u201clive\u201d database, and cleans up the temporary files:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">#!\/bin\/sh\n# \/usr\/local\/sbin\/vw-backup\nset -eu\ncd \/opt\/vaultwarden\ndocker compose exec -T vaultwarden \/vaultwarden backup\ntar -czf \"\/backup\/vw-$(date +%F).tar.gz\" -C vw-data \\\n  --exclude='db.sqlite3*' --exclude='icon_cache' .\nrm -f vw-data\/db_*.sqlite3<\/code><\/pre>\n<p>To restore, extract the package into an <code data-no-translation=\"\">vw-data<\/code> empty, rename the `backup-db.sqlite3`, and <code data-no-translation=\"\">db_AAAAMMDD_HHMMSS.sqlite3<\/code> to <code data-no-translation=\"\">db.sqlite3<\/code> and bring up the Compose. Keep the copy <em>off<\/em> from the machine \u2014 another disk, another VPS, a bucket via <a href=\"\/en\/2026\/09\/rclone-no-linux-sync-backup-criptografado-mount-e-serve-em-qualquer-nuvem\/\">rclone<\/a> \u2014 and test the restore at least once. The <code data-no-translation=\"\">OnCalendar=<\/code> of the <a href=\"\/en\/2026\/09\/dominando-o-systemd-comandos-essenciais\/\">systemd<\/a> handles scheduling if you don't want cron.<\/p>\n<h2>Upgrading<\/h2>\n<p>Change the image tag in <code data-no-translation=\"\">compose.yaml<\/code> to the new version, take the backup and recreate the container:<\/p>\n<pre data-no-translation=\"\"><code class=\"language-bash\" data-no-translation=\"\">\/usr\/local\/sbin\/vw-backup\ndocker compose pull\ndocker compose up -d\ndocker compose logs --tail=30 vaultwarden<\/code><\/pre>\n<p>Pinning the version (instead of <code data-no-translation=\"\">latest<\/code>) keeps the update under your control and rollback simple: just go back to the tag. Read the release notes first, particularly when they mention compatibility with a new version of the clients.<\/p>\n<h2>References<\/h2>\n<ul>\n<li><a href=\"https:\/\/github.com\/dani-garcia\/vaultwarden\">github.com\/dani-garcia\/vaultwarden<\/a> (AGPL-3.0, v1.37.3)<\/li>\n<li><a href=\"https:\/\/github.com\/dani-garcia\/vaultwarden\/wiki\">Wiki<\/a> \u2014 proxy, admin token, <a href=\"https:\/\/github.com\/dani-garcia\/vaultwarden\/wiki\/Backing-up-your-vault\">backup<\/a>, <a href=\"https:\/\/github.com\/dani-garcia\/vaultwarden\/wiki\/Enabling-SSO-support-using-OpenId-Connect\">SSO with OpenID Connect<\/a><\/li>\n<li><a href=\"https:\/\/bitwarden.com\/download\/\">Official Bitwarden clients<\/a><\/li>\n<\/ul>\n<p>A Rust binary, a volume and HTTPS. The vault stays on hardware you control \u2014 and the app in your pocket stays the same.<\/p>","protected":false},"excerpt":{"rendered":"<p>Vaultwarden is a server compatible with the official Bitwarden clients, written in Rust. Updated guide for 1.37.3: Docker Compose with Caddy, stuck registration, native SSO, backup with the built-in command, and safe update.<\/p>","protected":false},"author":0,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[33,2,120],"tags":[155,156,158,157,154],"class_list":["post-405","post","type-post","status-publish","format-standard","hentry","category-howtos","category-linux","category-servidores","tag-bitwarden","tag-docker","tag-rust","tag-senhas","tag-vaultwarden"],"_links":{"self":[{"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/posts\/405","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/comments?post=405"}],"version-history":[{"count":5,"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/posts\/405\/revisions"}],"predecessor-version":[{"id":1799,"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/posts\/405\/revisions\/1799"}],"wp:attachment":[{"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/media?parent=405"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/categories?post=405"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/tags?post=405"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}