Managed with AI assistance. Reviewed by a human.
🛠️ Real incident

Fixing Bitwarden "Failed to fetch" Against Self-Hosted Vaultwarden

A TLS certificate name mismatch made the Bitwarden client fail to reach a self-hosted Vaultwarden server.

Fixing Bitwarden “Failed to fetch” Against Self-Hosted Vaultwarden

Symptoms

Evidence

The service was configured with HTTPS, not plain HTTP. Its certificate covered a DNS hostname but not the raw IP address used in the extension.

Check the certificate presented by the service:

openssl s_client -connect VAULT_HOST:PORT -servername VAULT_HOST \
  </dev/null 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates -ext subjectAltName

Test the HTTPS endpoint:

curl -v https://VAULT_HOST:PORT/

If DNS is not ready yet, test a hostname against a specific address without changing DNS:

curl -v --resolve vault.example.internal:PORT:SERVER_IP \
  https://vault.example.internal:PORT/

Root cause

The extension connected to an address absent from the certificate’s Subject Alternative Name list. Chromium extensions enforce TLS validation independently of the “proceed anyway” exception available in a normal browser tab.

The vault was healthy; its HTTPS identity was misconfigured for the address used by the extension.

Correct fixes

Choose one stable hostname and use it everywhere:

  1. Make the hostname resolve through private DNS, split DNS, or the mesh VPN’s DNS feature.
  2. Issue a certificate whose SAN includes that hostname.
  3. Trust the issuing CA on every Bitwarden client.
  4. Configure the Bitwarden extension with the matching HTTPS URL.

For a private CA using mkcert:

mkcert -install
mkcert -cert-file vaultwarden.crt \
  -key-file vaultwarden.key \
  vault.example.internal SERVER_IP VPN_IP
chmod 600 vaultwarden.key

Install only the CA certificate on client devices. Never distribute the CA private key.

If using a platform that provides trusted HTTPS certificates and private DNS, prefer its supported reverse-proxy or certificate workflow.

What not to do

Verification

From every client network path:

getent hosts vault.example.internal
curl -fsS https://vault.example.internal/ >/dev/null \
  && echo "HTTPS validation succeeded"

Then set the extension’s self-hosted server URL to the same validated HTTPS origin and sign in.