<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Password-Manager – Serverküche</title><link>https://serverkueche.de/en/tags/password-manager/</link><description>Password-Manager – Neueste Beiträge von Serverküche</description><generator>Hugo</generator><language>en-US</language><managingEditor>feedback@serverkueche.de (Serverküche)</managingEditor><webMaster>feedback@serverkueche.de (Serverküche)</webMaster><copyright>2026 Serverküche</copyright><lastBuildDate>Sun, 19 Jul 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://serverkueche.de/en/tags/password-manager/index.xml" rel="self" type="application/rss+xml"/><item><title>Vaultwarden: your own password manager behind Traefik</title><link>https://serverkueche.de/en/tutorials/vaultwarden-password-manager/</link><pubDate>Sun, 19 Jul 2026 00:00:00 +0000</pubDate><author>feedback@serverkueche.de (Serverküche)</author><guid>https://serverkueche.de/en/tutorials/vaultwarden-password-manager/</guid><description>Self-host Vaultwarden: a lean, Bitwarden-compatible password manager behind Traefik with HTTPS, an admin panel and an encrypted backup.</description><content:encoded><![CDATA[<p>Passwords belong in a password manager – but do they have to live in the cloud of some
third-party provider? With <strong>Vaultwarden</strong> you host your own, encrypted and under your
control. It speaks the Bitwarden language, so you use the familiar Bitwarden apps and
browser extensions – they just point at <strong>your</strong> server.</p>
<h2 id="what-are-we-building">What are we building?</h2>
<p>By the end, <strong>Vaultwarden 1.36</strong> runs in a container behind your Traefik proxy, reachable
at <code>https://vault.YOUR_DOMAIN</code> with a valid HTTPS certificate. Vaultwarden is a lean
reimplementation of the Bitwarden server written in Rust: API-compatible, but frugal
enough to run on a small VPS. You connect the official <strong>Bitwarden clients</strong> (browser
extension, phone app, desktop) with your server, store your credentials – end-to-end
encrypted – and manage the service via a secured <strong>admin panel</strong>.</p>
<p>Your passwords thus live on your server, in your country, under your backup – and you pay
no subscription fee for features like 2FA or attachments.</p>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-sky-300 bg-sky-50 dark:border-sky-800 dark:bg-sky-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">ℹ️</span>Vaultwarden ≠ Bitwarden
  </p>
  <div class="prose-kitchen text-sm">Vaultwarden is an <strong>unofficial</strong>, community-driven project that reimplements the Bitwarden
server API. It&rsquo;s not affiliated with Bitwarden Inc. For private and small-team use it&rsquo;s
excellent; the clients (apps, extensions) are the real, official ones from Bitwarden.</div>
</div>
<h2 id="prerequisites">Prerequisites</h2>
<ul>
<li>A running <strong>Traefik reverse proxy</strong> with the shared <code>proxy</code> network and the Let&rsquo;s
Encrypt resolver <code>le</code> – exactly the setup from the tutorial
<a href="/en/tutorials/traefik-reverse-proxy/">reverse proxy with Traefik</a>. Without Traefik this
recipe doesn&rsquo;t work: Vaultwarden <strong>requires HTTPS</strong>.</li>
<li>A subdomain, e.g. <code>vault.YOUR_DOMAIN</code>, whose DNS record (A/AAAA) points to your server
IP – see <a href="/en/tutorials/connect-domain-to-server/">connecting a domain to your server</a>.</li>
<li>A working <strong>backup</strong> of your server. A password manager is the place where data loss
hurts most – if you haven&rsquo;t yet, first set up
<a href="/en/tutorials/restic-backups/">backups with Restic</a>.</li>
</ul>
<p>If you want to combine several services later, the <a href="/en/server-calculator/">server calculator</a>
helps with the right server size.</p>
<div class="not-prose my-6 overflow-hidden rounded-xl border border-paprika-200 bg-paprika-50 dark:border-paprika-800 dark:bg-paprika-900/20">
  <div class="flex items-center justify-between border-b border-paprika-200 bg-paprika-100 px-4 py-1.5 text-xs font-semibold uppercase tracking-wide text-paprika-700 dark:border-paprika-800 dark:bg-paprika-900/40 dark:text-paprika-300">
    <span>🍳 Recommendation</span>
    <span title="Links marked with * are affiliate links.">Ad</span>
  </div>
  <div class="flex flex-col gap-4 p-4 sm:flex-row sm:items-center sm:justify-between">
    <div>
      <p class="text-lg font-bold text-slate-900 dark:text-white">VPS 1000 G12</p>
      <p class="mt-1 text-sm text-slate-600 dark:text-slate-300">4 vCores · 8 GB RAM · 256 GB NVMe</p>
      <p class="mt-1 text-sm font-semibold text-paprika-700 dark:text-paprika-400">from €10.36/month</p>
      <p class="mt-2 text-sm text-slate-600 dark:text-slate-400">Vaultwarden is so frugal that even the smallest VPS is easily enough.</p>
    </div>
    <a href="https://www.netcup.com/en/server/vps/vps-1000-g12-iv-12m?ref=44083" rel="sponsored noopener" target="_blank"
   class="inline-flex shrink-0 items-center justify-center rounded-lg bg-paprika-600 px-5 py-2.5 font-semibold text-white transition-colors hover:bg-paprika-700">
  Go to netcup →
</a>

  </div><div class="px-4 pb-4"><p class="not-prose my-3 flex flex-wrap items-center gap-x-2 gap-y-1 rounded-lg border border-herb-500/40 bg-herb-50 px-3 py-2 text-sm text-slate-700 dark:bg-herb-900/20 dark:text-slate-200">
  <span>💶 <strong>5 € voucher</strong> for new netcup customers:</span>
  <code class="rounded bg-white px-2 py-0.5 font-mono text-sm font-semibold text-herb-800 dark:bg-slate-800 dark:text-herb-400">36nc17844976032</code>
  <span class="text-xs text-slate-500 dark:text-slate-400">(new customers only, no domains)</span>
</p></div>
</div>

<h2 id="step-by-step">Step by step</h2>
<h3 id="step-1-generate-the-admin_token">Step 1: Generate the ADMIN_TOKEN</h3>
<p>Vaultwarden has an admin panel at <code>/admin</code>. Access to it is protected by an <code>ADMIN_TOKEN</code>.
You should <strong>not</strong> store it in plaintext, but as a hash – then your panel password appears
nowhere readable in the Compose file.</p>
<p>Vaultwarden brings its own command for this. We run it briefly in a throwaway container:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker run --rm -it vaultwarden/server:1.36.0 /vaultwarden <span class="nb">hash</span> --preset owasp</span></span></code></pre></div>
</div>
<p>The command asks you twice for a password (input stays invisible) and then outputs an
<strong>Argon2id hash</strong> – a long string that starts like this:</p>
<div class="sk-code">
  <span class="sk-code-head">Ausgabe</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Generate an Argon2id PHC string using the &#39;owasp&#39; preset.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Password:
</span></span><span class="line"><span class="cl">Confirm Password:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">ADMIN_TOKEN=&#39;$argon2id$v=19$m=19456,t=2,p=1$FkxFEQ64Wy4zlQOWMI1fJ...$TxULe6MSND3By6GPVPKB1...&#39;</span></span></code></pre></div>
</div>
<p>Copy out the complete string between the quotes (including the <code>$argon2id$…</code> parts) – you
need it in a moment. The password you entered here is your <strong>admin panel password</strong>; store
it in your password manager (in the old one, for now).</p>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-herb-400 bg-herb-50 dark:border-herb-700 dark:bg-herb-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">🧑‍🍳</span>Why the detour via the hash?
  </p>
  <div class="prose-kitchen text-sm">You could also set the <code>ADMIN_TOKEN</code> as a plaintext password. The hash is safer, though:
even someone who gets hold of your <code>compose.yaml</code> can&rsquo;t compute your panel password back
from it. <code>--preset owasp</code> chooses Argon2 parameters per the current OWASP recommendation.</div>
</div>
<h3 id="step-2-create-the-composeyaml">Step 2: Create the compose.yaml</h3>
<p>Create a dedicated folder and change into it:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mkdir -p ~/vaultwarden <span class="o">&amp;&amp;</span> <span class="nb">cd</span> ~/vaultwarden</span></span></code></pre></div>
</div>
<p>Create the <code>compose.yaml</code>. Replace <code>vault.YOUR_DOMAIN</code> with your real subdomain and the
<code>ADMIN_TOKEN</code> with the hash from step 1:</p>
<div class="sk-code">
  <span class="sk-code-head">YAML</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">services</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">vaultwarden</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">vaultwarden/server:1.36.0</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">./vw-data:/data</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">environment</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">DOMAIN</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;https://vault.YOUR_DOMAIN&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">SIGNUPS_ALLOWED</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;true&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">ADMIN_TOKEN</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;$$argon2id$$v=19$$m=19456,t=2,p=1$$FkxFE...$$TxULe...&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">labels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.enable=true&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.routers.vaultwarden.rule=Host(`vault.YOUR_DOMAIN`)&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.routers.vaultwarden.entrypoints=websecure&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.routers.vaultwarden.tls.certresolver=le&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.services.vaultwarden.loadbalancer.server.port=80&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">networks</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">proxy</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">restart</span><span class="p">:</span><span class="w"> </span><span class="l">unless-stopped</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">networks</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">proxy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">external</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span></span></span></code></pre></div>
</div>
<p>The most important lines in detail:</p>
<ul>
<li><strong><code>image: vaultwarden/server:1.36.0</code></strong> – we deliberately pin the version instead of
taking <code>latest</code>. That way you update in a controlled manner (see &ldquo;Maintenance&rdquo;). For an
even smaller image there&rsquo;s also <code>:1.36.0-alpine</code>.</li>
<li><strong><code>volumes: ./vw-data:/data</code></strong> – this is where your database (<code>db.sqlite3</code>), the
encryption keys and the attachments live. <strong>This volume is mandatory.</strong> Without a volume
Vaultwarden deliberately refuses to start, so you don&rsquo;t lose your data in an ephemeral
container.</li>
<li><strong><code>DOMAIN</code></strong> – the full HTTPS URL. Vaultwarden needs it for WebAuthn/2FA and invitation
links, among other things. Must match your router rule exactly.</li>
<li><strong><code>SIGNUPS_ALLOWED: &quot;true&quot;</code></strong> – allows registration for now so you can create your first
account. We turn that off again shortly.</li>
<li><strong><code>ADMIN_TOKEN</code></strong> – your hash from step 1. <strong>Important:</strong> in a Compose file every dollar
sign must be <strong>doubled</strong> (<code>$</code> → <code>$$</code>), otherwise Compose tries to interpret it as a
variable. So <code>$argon2id$…</code> becomes <code>$$argon2id$$…</code>.</li>
<li><strong><code>loadbalancer.server.port=80</code></strong> – Vaultwarden listens on <strong>port 80</strong> in the container.
This line tells Traefik explicitly where to forward internally, instead of guessing the
target port from the image – the same pattern as with every app behind Traefik.</li>
<li><strong>No <code>ports:</code></strong> – as with every app behind Traefik, Vaultwarden is only reachable via the
proxy, never directly from outside.</li>
</ul>
<h3 id="step-3-start-it-and-the-first-call">Step 3: Start it and the first call</h3>
<p>Start the container:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker compose up -d</span></span></code></pre></div>
</div>
<p>On the first start, Vaultwarden creates the data directory and initializes the database.
Take a look at the log:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker compose logs -f vaultwarden</span></span></code></pre></div>
</div>
<p>At the end you should see this line – it confirms the service is running:</p>
<div class="sk-code">
  <span class="sk-code-head">Ausgabe</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">[INFO] Rocket has launched from http://0.0.0.0:80</span></span></code></pre></div>
</div>
<p>With <code>Ctrl+C</code> you leave the log view again (the container keeps running). Now open
<code>https://vault.YOUR_DOMAIN</code> in the browser. On the first access Traefik fetches the Let&rsquo;s
Encrypt certificate – that can take a few seconds. After that the Bitwarden web interface
appears.</p>
<p>Click <strong>Create account</strong> and create your first account – with your email address and a
name:</p>
<p><figure class="my-6"><img src="/en/tutorials/vaultwarden-password-manager/vaultwarden-konto-erstellen_hu_442c987fd222aaf3.webp" srcset="/en/tutorials/vaultwarden-password-manager/vaultwarden-konto-erstellen_hu_171ec18b0766c4f0.webp 480w, /en/tutorials/vaultwarden-password-manager/vaultwarden-konto-erstellen_hu_442c987fd222aaf3.webp 768w, /en/tutorials/vaultwarden-password-manager/vaultwarden-konto-erstellen_hu_fe725a264430f1c1.webp 1200w, /en/tutorials/vaultwarden-password-manager/vaultwarden-konto-erstellen_hu_19943411b9fb06d0.webp 1920w" sizes="(min-width: 768px) 768px, 100vw"
    width="768" height="432"
    data-full="/en/tutorials/vaultwarden-password-manager/vaultwarden-konto-erstellen_hu_da55256e86e78bf2.webp"
    alt="The Vaultwarden web interface shows the form to create a new account with email address and name" title="Create account – Vaultwarden uses the official Bitwarden web interface"
    loading="lazy" decoding="async" class="rounded-lg"><figcaption class="mt-2 text-sm text-center text-slate-500 italic">Create account – Vaultwarden uses the official Bitwarden web interface</figcaption></figure></p>
<p>In the next step you set your <strong>master password</strong>. That&rsquo;s the one key that unlocks your
entire vault:</p>
<p><figure class="my-6"><img src="/en/tutorials/vaultwarden-password-manager/vaultwarden-master-passwort_hu_94b00d92f8745395.webp" srcset="/en/tutorials/vaultwarden-password-manager/vaultwarden-master-passwort_hu_817569daa8f2d151.webp 480w, /en/tutorials/vaultwarden-password-manager/vaultwarden-master-passwort_hu_94b00d92f8745395.webp 768w, /en/tutorials/vaultwarden-password-manager/vaultwarden-master-passwort_hu_eba5c53116ba25e8.webp 1200w, /en/tutorials/vaultwarden-password-manager/vaultwarden-master-passwort_hu_1fe5f1251d11ceab.webp 1920w" sizes="(min-width: 768px) 768px, 100vw"
    width="768" height="432"
    data-full="/en/tutorials/vaultwarden-password-manager/vaultwarden-master-passwort_hu_5f16260444ccea7e.webp"
    alt="The Vaultwarden page for setting a strong master password with a password field and strength indicator" title="The master password encrypts your entire vault – choose it carefully"
    loading="lazy" decoding="async" class="rounded-lg"><figcaption class="mt-2 text-sm text-center text-slate-500 italic">The master password encrypts your entire vault – choose it carefully</figcaption></figure></p>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-paprika-400 bg-paprika-50 dark:border-paprika-700 dark:bg-paprika-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">🔥</span>The master password is not recoverable
  </p>
  <div class="prose-kitchen text-sm">Your master password is <strong>never</strong> transmitted to the server; it decrypts your vault
locally. If you forget it, <strong>all</strong> passwords stored in it are lost – no one, not even you,
can recover them. Choose a long, unique passphrase and keep it in a safe place (e.g.
printed out in a safe).</div>
</div>
<h3 id="step-4-close-registration-again">Step 4: Close registration again</h3>
<p>Once your account is set up, you want to <strong>prevent strangers from registering too</strong> – your
Vaultwarden is, after all, open on the internet. Set <code>SIGNUPS_ALLOWED</code> to <code>false</code> in the
<code>compose.yaml</code>:</p>
<div class="sk-code">
  <span class="sk-code-head">YAML</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="w">    </span><span class="nt">environment</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">DOMAIN</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;https://vault.YOUR_DOMAIN&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">SIGNUPS_ALLOWED</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;false&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">ADMIN_TOKEN</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;$$argon2id$$...&#34;</span></span></span></code></pre></div>
</div>
<p>And apply the change:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker compose up -d</span></span></code></pre></div>
</div>
<p>Compose detects the changed environment variable and restarts the container. From now on
the login page rejects new registrations. Further users (e.g. for the family) you invite
specifically via the admin panel when needed – more on that shortly.</p>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-amber-400 bg-amber-50 dark:border-amber-700 dark:bg-amber-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">⚠️</span>Don&#39;t forget
  </p>
  <div class="prose-kitchen text-sm">An open <code>SIGNUPS_ALLOWED: &quot;true&quot;</code> is the most common misconfiguration with self-hosted
Vaultwarden. Anyone who knows your domain could otherwise create an account. This step is
mandatory, not an extra.</div>
</div>
<h3 id="step-5-the-admin-panel">Step 5: The admin panel</h3>
<p>Open <code>https://vault.YOUR_DOMAIN/admin</code> and log in with the <strong>password</strong> you entered in
step 1 when generating the hash (not with the hash itself). You land in the management
interface:</p>
<p><figure class="my-6"><img src="/en/tutorials/vaultwarden-password-manager/vaultwarden-admin_hu_473707ac677392b3.webp" srcset="/en/tutorials/vaultwarden-password-manager/vaultwarden-admin_hu_9aeb46075faece5c.webp 480w, /en/tutorials/vaultwarden-password-manager/vaultwarden-admin_hu_473707ac677392b3.webp 768w, /en/tutorials/vaultwarden-password-manager/vaultwarden-admin_hu_5667882637e7d363.webp 1200w, /en/tutorials/vaultwarden-password-manager/vaultwarden-admin_hu_d5ec00afc73e4d04.webp 1920w" sizes="(min-width: 768px) 768px, 100vw"
    width="768" height="432"
    data-full="/en/tutorials/vaultwarden-password-manager/vaultwarden-admin_hu_6e7aad8d3eec6a20.webp"
    alt="The Vaultwarden admin panel with the areas General, SMTP Email and Backup Database" title="The admin panel – here you manage users, SMTP and global settings"
    loading="lazy" decoding="async" class="rounded-lg"><figcaption class="mt-2 text-sm text-center text-slate-500 italic">The admin panel – here you manage users, SMTP and global settings</figcaption></figure></p>
<p>Here you control the service centrally:</p>
<ul>
<li><strong>Users</strong> – view existing users, <strong>invite</strong> new ones (even with <code>SIGNUPS_ALLOWED=false</code>),
deactivate accounts.</li>
<li><strong>Settings → SMTP Email Settings</strong> – enter your mail server&rsquo;s credentials here so
Vaultwarden can send invitations and 2FA codes by email. Without SMTP, invitation by link
works too, but email-based 2FA doesn&rsquo;t.</li>
<li><strong>Diagnostics</strong> – shows you whether your <code>DOMAIN</code> is set correctly and whether Vaultwarden
is reachable from outside – handy for troubleshooting.</li>
</ul>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-herb-400 bg-herb-50 dark:border-herb-700 dark:bg-herb-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">🧑‍🍳</span>Settings in the panel vs. environment variables
  </p>
  <div class="prose-kitchen text-sm">What you save in the admin panel is stored in <code>vw-data/config.json</code> and <strong>overrides</strong> the
environment variables from the <code>compose.yaml</code>. Decide per setting on one way to avoid
confusion. For the basic configuration (domain, token, signups) we deliberately stick with
the Compose file – it&rsquo;s versionable and reproducible.</div>
</div>
<h3 id="step-6-connect-the-clients">Step 6: Connect the clients</h3>
<p>Now comes the real benefit. Install the <strong>official Bitwarden app</strong> or browser extension
(from the respective app or add-on store). Before you log in, you switch the server:</p>
<ol>
<li>In the app/extension, <strong>before logging in</strong>, open the settings for the <strong>self-hosted
environment</strong> (gear icon or &ldquo;Region: Self-hosted&rdquo;).</li>
<li>Enter <code>https://vault.YOUR_DOMAIN</code> as the <strong>server URL</strong> and save.</li>
<li>Now log in with your email and your master password – the app talks to your server from
now on.</li>
</ol>
<p>The nice part: it&rsquo;s the same mature clients as with commercial Bitwarden. Autofill,
password generator, secure notes, attachments and 2FA storage work the same way – only the
data lives on your server.</p>
<p><strong>Import existing passwords:</strong> if you&rsquo;re switching from another manager (or the browser&rsquo;s
password store), you don&rsquo;t have to retype everything. Export your entries there as CSV or
JSON and import them via the <strong>web interface</strong> under <code>Tools → Import data</code>. Vaultwarden
understands the export formats of the common managers (KeePass, LastPass, 1Password,
Chrome/Firefox, etc.) directly.</p>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-amber-400 bg-amber-50 dark:border-amber-700 dark:bg-amber-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">⚠️</span>Securely delete export files afterwards
  </p>
  <div class="prose-kitchen text-sm">An export CSV contains all passwords <strong>in plaintext</strong>. Delete the file immediately after a
successful import – and empty the trash. Never leave it lying in Downloads or a cloud
folder.</div>
</div>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-herb-400 bg-herb-50 dark:border-herb-700 dark:bg-herb-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">🧑‍🍳</span>Enable two-factor authentication
  </p>
  <div class="prose-kitchen text-sm">In your vault&rsquo;s account settings, enable <strong>2FA</strong> (e.g. via an authenticator app). That way,
even with a cracked master password, your vault isn&rsquo;t immediately open. For email-based 2FA,
SMTP must be set up in the admin panel first.</div>
</div>
<h2 id="when-things-go-wrong">When things go wrong</h2>
<div class="troubleshoot not-prose">
<p><strong>The container won&rsquo;t start, the log says something like <code>Running without a persistent volume is not recommended</code>.</strong> The <code>volumes:</code> mapping is missing. Vaultwarden deliberately
refuses to start without a data directory so your passwords don&rsquo;t end up in an ephemeral
container. Add <code>./vw-data:/data</code> as in step 2 and restart.</p>
<p><strong>The web interface shows &ldquo;You need to enable HTTPS!&rdquo; or the login fails with crypto
errors.</strong> Vaultwarden uses the browser&rsquo;s Web Crypto API, which is only available in a
<strong>secure context</strong> (real HTTPS). You opened the page over <code>http://</code> or with an invalid
certificate. Make sure Traefik fetched a valid Let&rsquo;s Encrypt certificate (check the Traefik
log) and that you reach the page over <code>https://</code>. The <code>DOMAIN</code> variable must also start with
<code>https://</code>.</p>
<p><strong>The admin panel rejects your password, even though it&rsquo;s correct.</strong> Probably the dollar
signs in the <code>ADMIN_TOKEN</code> aren&rsquo;t doubled. In the <code>compose.yaml</code> every <code>$</code> must become <code>$$</code>.
Check with <code>docker compose config</code> how the token actually arrives (Compose shows the
resolved value there). Also remember: at login you enter the <strong>password</strong>, not the hash.</p>
<p><strong>The phone app can&rsquo;t find the server or reports &ldquo;Server URL invalid&rdquo;.</strong> The server URL must
be the full <code>https://</code> address without a trailing path (<code>https://vault.YOUR_DOMAIN</code>). Also
check whether the domain is reachable from outside via a browser and the certificate is
valid – apps are stricter about certificate errors than browsers.</p>
<p><strong>Despite <code>SIGNUPS_ALLOWED=false</code>, someone was able to register.</strong> The setting was probably
set in the admin panel and overrides the environment variable, or the container wasn&rsquo;t
restarted after the change. Check the value under <strong>Settings → General settings</strong> in the
panel and restart with <code>docker compose up -d</code>.</p>

</div>

<h2 id="maintenance--backups">Maintenance &amp; backups</h2>
<ul>
<li>
<p><strong>Backups are non-negotiable for a password manager.</strong> Your entire vault is in the
<code>vw-data/</code> directory (SQLite database, keys, attachments). Back it up <strong>encrypted and
off-site</strong> with <a href="/en/tutorials/restic-backups/">Restic</a> – add the folder
<code>~/vaultwarden/vw-data</code> to your backup sources. For a consistent database state, briefly
run <code>docker compose stop</code> before the backup, or use the &ldquo;Backup Database&rdquo; function in the
admin panel. A mere file copy while the container is <strong>running</strong> can catch an inconsistent
state (SQLite writes into WAL files) – with a password manager that&rsquo;s not a risk worth
taking.</p>
</li>
<li>
<p><strong>Apply updates in a controlled way.</strong> Because we pinned the version, you update
deliberately: before the switch read the
<a href="https://github.com/dani-garcia/vaultwarden/releases">release notes</a>, then raise the tag
in the <code>compose.yaml</code> (e.g. to the next <code>1.x</code>) and pull anew:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker compose pull <span class="o">&amp;&amp;</span> docker compose up -d</span></span></code></pre></div>
</div>
<p>Afterwards check the <code>Rocket has launched</code> line in the log again and test a login.</p>
</li>
<li>
<p><strong>Keep registration closed.</strong> Occasionally check that <code>SIGNUPS_ALLOWED</code> is still <code>false</code> –
always invite new users specifically via the admin panel.</p>
</li>
<li>
<p><strong>Rotate the ADMIN_TOKEN</strong> if it might be compromised: generate a new hash with the <code>hash</code>
command from step 1, replace it in the <code>compose.yaml</code>, restart.</p>
</li>
<li>
<p><strong>Never lose the master password.</strong> There is no recovery. In a team/family setup, an
emergency access can make sense – you set that up per vault in the account settings.</p>
</li>
</ul>
]]></content:encoded></item></channel></rss>