Octelium documentation · Latest
Self-Hosting Vaultwarden Password Manager
Vaultwarden is a popular open source, lightweight server implementation of the Bitwarden API written in Rust that is compatible with the official Bitwarden clients, including the browser extensions, the desktop and mobile apps, and the CLI. This guide shows you how to deploy Vaultwarden via Helm on the same underlying Kubernetes cluster that is running the Octelium Cluster, and then serve it via Octelium Services.
A password manager has a special access pattern. The Bitwarden clients need to reach the server directly from anywhere, and they cannot go through the Cluster's browser-based login. On the other hand, the vault itself is end-to-end encrypted where the master password never leaves the client, while the Vaultwarden admin panel, which manages users and server settings, is the most sensitive part of the server. Therefore, in this guide Octelium provides the following:
A public anonymous Service (read more here) that operates as a web application firewall (WAF) and serves the Bitwarden clients from anywhere, while completely blocking the admin panel.
A separate Service for the admin panel which is only accessible by the members of an
adminsGroup after authenticating to the Cluster via OpenID Connect, SAML 2.0 or GitHub IdentityProviders (read more here) as well as Passkeys.OpenTelemetry-native, L7 aware visibility and auditing of every request, including the blocked ones (read more here).
If you installed the Cluster via the quick installation guide, you can simply use the command export KUBECONFIG="/etc/rancher/k3s/k3s.yaml" in your Cluster VM/VPS before running the kubectl and helm commands below.
Install Vaultwarden
Vaultwarden does not publish an official Helm chart. In this guide we use the vaultwarden Helm chart which is the chart recommended by the Vaultwarden wiki for Kubernetes deployments.
Create the Admin Token
The admin panel is protected by an admin token. Instead of storing a plaintext token, Vaultwarden can generate an Argon2id hash of a password of your choice. First, create a Kubernetes namespace for Vaultwarden and then generate the hash via a temporary pod as follows:
After entering your password twice, the command outputs the Argon2id PHC string, which starts with $argon2id$. Now store that string in a Kubernetes secret as follows:
Make sure to use single quotes around the PHC string as shown above, since it contains $ characters that your shell would otherwise try to expand.
Install the Chart
Now we create a values.yaml file for the chart (see the chart here) as follows:
The domain value must be the public URL that the Bitwarden clients use, which is the public URL of the vault Service that we create below. We disable open signups so that only the users that you invite via the admin panel can create accounts. By default, Vaultwarden uses a SQLite database that is stored, along with the attachments, in the vaultwarden-data persistent volume claim.
Now install the chart and wait for Vaultwarden to become ready as follows:
The chart creates the vaultwarden Kubernetes service in the vaultwarden Kubernetes namespace which listens over the port 80.
You can create a consistent backup of the SQLite database at any time via the command kubectl exec -n vaultwarden vaultwarden-0 -- /vaultwarden backup. The backup file is created inside the data volume, from which you can copy it out via kubectl cp. Read more about backing up Vaultwarden in the Vaultwarden wiki here.
Create the Services
Both of the following Services use the same vaultwarden Kubernetes service as their upstream.
Public Service for Bitwarden Clients
We create a public anonymous vault Service with anonymous authorization enabled (read more here). In this mode, the Service does not authenticate the requests, but it still authorizes every request according to its Policies, effectively operating as a WAF. Here we allow all requests except for the ones to the admin panel as follows:
Since DENY rules override ALLOW rules of the same priority (read more here), any request to the admin panel is denied with a 403 status code before it ever reaches Vaultwarden. The regular expression also matches paths with repeated leading slashes such as //admin, which some web servers treat exactly like /admin.
In the anonymous mode, the Service passes the downstream's Authorization request header as is (read more here). This is required since the Bitwarden clients authenticate to Vaultwarden via Bearer tokens in that header.
Admin Service
Now we create a separate vault-admin Service for the admin panel. Unlike the vault Service, this one is not anonymous and is only accessible by the members of the admins Group (read more about Groups here) as follows:
Now add your administrator Users to the admins Group. Here is an example:
You can now apply the creation of the Group, both Services and the Users via the octeliumctl apply command (read more here) as follows:
Now members of the admins Group can visit the admin panel from their browsers at the URL https://vault-admin.<DOMAIN>/admin via the clientless BeyondCorp mode (read more here), or at the URL http://vault-admin/admin via the client-based mode once connected to the Cluster via the octelium connect command (read more here). Vaultwarden then asks for the password that you used to generate the admin token.
The Diagnostics page of the admin panel shows a No Match warning for the domain configuration since you are visiting it from a different hostname than the configured domain value. You can safely ignore that warning since the Bitwarden clients only use the vault Service.
Inviting Users
Since open signups are disabled, go to the Users page of the admin panel and invite a user via their email address. The invited user can then create their account at the web vault at https://vault.<DOMAIN> using that email address. This works even if you have not configured SMTP for Vaultwarden.
It is strongly recommended for every user to enable two-step login (e.g. via an authenticator app or a security key) from the Security settings of their account in the web vault.
Using Bitwarden Clients
All the official Bitwarden clients support self-hosted servers. On the login screen of the browser extension, desktop app or mobile app, choose the self-hosted environment and set the server URL to https://vault.<DOMAIN>. You can also configure the Bitwarden CLI as follows:
Since the Service drops the X-Forwarded-For and X-Real-IP request headers by default (read more here), Vaultwarden sees every request as coming from the private IP address of the Cluster. Therefore, Vaultwarden's per-IP rate limiting of login attempts applies to all clients collectively, which is typically fine for a small number of users.
Vaultwarden also supports single sign-on via OpenID Connect through the chart's sso values. You can use the same self-hosted identity provider that you use to login to the Cluster, such as Authentik (read more here) or Keycloak (read more here). Read more about Vaultwarden's SSO support in the Vaultwarden wiki here.
Visibility
Octelium also provides OpenTelemetry-ready, application-layer L7 aware visibility and access logging in real time (read more about visibility here), including for anonymous Services. Here is an example of an access Log of a request to the admin panel that was blocked by the vault Service:
Here are a few more features that you might be interested in:
Self-hosting Immich for your photos and videos (read more here).
Self-hosting Jellyfin for your media (read more here).
HTTP plugins such as rate limiting and Lua scripting (read more here).
Application layer-aware ABAC access control via policy-as-code using CEL and Open Policy Agent (read more here).