8.4 KiB
Vaultwarden Module Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Add Vaultwarden password manager as a NixOS module with Podman container, Nginx reverse proxy, and SOPS secrets.
Architecture: Podman container running vaultwarden/server image with HTTP and WebSocket ports, integrated with existing Nginx module for reverse proxy and TLS, using SOPS for admin token secret management.
Tech Stack: NixOS, Podman, Nginx, SOPS-nix, Vaultwarden
File Structure
| File | Purpose |
|---|---|
modules/nginx.nix |
Modify - add extraLocations option for WebSocket support |
modules/vaultwarden.nix |
New module - defines options and container config |
modules/default.nix |
Add import for vaultwarden module |
configuration.nix |
Enable module, declare SOPS secrets/templates |
Task 1: Extend Nginx Module for Extra Locations
Files:
-
Modify:
modules/nginx.nix -
Step 1: Add
extraLocationsoption to domain submodule
Add a new option after extraConfig (around line 46):
extraLocations = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule {
options = {
proxyPass = lib.mkOption {
type = lib.types.str;
description = "Proxy target URL";
};
extraConfig = lib.mkOption {
type = lib.types.lines;
default = "";
description = "Extra Nginx config for this location";
};
};
});
default = { };
description = "Additional location blocks to add to this virtual host";
};
- Step 2: Update virtualHosts generation to include extraLocations
Replace the virtualHosts block (lines 76-87) with:
virtualHosts = lib.mapAttrs' (domain: opts: {
name = domain;
value = {
enableACME = true;
forceSSL = true;
locations = {
"/" = {
proxyPass = "http://127.0.0.1:${toString opts.port}";
extraConfig = opts.extraConfig;
};
} // lib.mapAttrs' (locPath: locOpts: {
name = locPath;
value = {
proxyPass = locOpts.proxyPass;
extraConfig = locOpts.extraConfig;
};
}) opts.extraLocations;
};
}) cfg.domains;
- Step 3: Verify syntax
Run: nix-instantiate --parse modules/nginx.nix
Expected: No parse errors
- Step 4: Commit
git add modules/nginx.nix
git commit -m "feat(nginx): add extraLocations option for WebSocket support
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>"
Task 2: Create Vaultwarden Module File
Files:
-
Create:
modules/vaultwarden.nix -
Step 1: Create module file
# Vaultwarden Module (Podman)
# Provides: Bitwarden-compatible password manager
#
# Usage:
# myModules.vaultwarden = {
# enable = true;
# port = 8222;
# websocketPort = 3012;
# domain = "vault.example.com";
# };
{
config,
lib,
pkgs,
...
}:
let
cfg = config.myModules.vaultwarden;
in
{
options.myModules.vaultwarden = {
enable = lib.mkEnableOption "Vaultwarden password manager";
domain = lib.mkOption {
type = lib.types.str;
example = "vault.example.com";
description = "Public domain for Vaultwarden";
};
port = lib.mkOption {
type = lib.types.port;
default = 8222;
description = "HTTP port for Vaultwarden web interface";
};
websocketPort = lib.mkOption {
type = lib.types.port;
default = 3012;
description = "WebSocket port for real-time sync";
};
};
config = lib.mkIf cfg.enable {
# Enable podman
myModules.podman.enable = true;
# Vaultwarden container
virtualisation.oci-containers.containers."vaultwarden" = {
image = "vaultwarden/server:latest";
ports = [
"127.0.0.1:${toString cfg.port}:80"
"127.0.0.1:${toString cfg.websocketPort}:3012"
];
environmentFiles = [
config.sops.templates."vaultwarden.env".path
];
environment = {
SHOW_PASSWORD_HINT = "false";
SIGNUPS_ALLOWED = "true";
};
volumes = [
"vaultwarden-data:/data"
];
};
# Register with Nginx (using extraLocations for WebSocket)
myModules.nginx.domains."${cfg.domain}" = {
port = cfg.port;
extraLocations."/notifications/hub" = {
proxyPass = "http://127.0.0.1:${toString cfg.websocketPort}";
extraConfig = ''
proxyHttpVersion 1.1;
proxySetHeader Upgrade $http_upgrade;
proxySetHeader Connection "upgrade";
'';
};
};
};
}
- Step 2: Verify file was created
Run: cat modules/vaultwarden.nix | head -20
Expected: Module header and options visible
- Step 3: Commit module file
git add modules/vaultwarden.nix
git commit -m "feat: add Vaultwarden module (Podman)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>"
Task 3: Register Module in default.nix
Files:
-
Modify:
modules/default.nix -
Step 1: Add vaultwarden import
Edit modules/default.nix to add ./vaultwarden.nix to imports:
# Module exports
{
imports = [
./system.nix
./podman.nix
./nginx.nix
./searxng.nix
./openclaw-podman.nix
./vaultwarden.nix
];
}
- Step 2: Verify syntax
Run: nix-instantiate --parse modules/default.nix
Expected: No parse errors
- Step 3: Commit
git add modules/default.nix
git commit -m "feat: register Vaultwarden module in default.nix
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>"
Task 4: Configure Vaultwarden in configuration.nix
Files:
-
Modify:
configuration.nix -
Step 1: Add Vaultwarden module configuration
Add after the OpenClaw section (around line 95):
# === Vaultwarden ===
myModules.vaultwarden = {
enable = true;
port = 8222;
websocketPort = 3012;
domain = "vault.ashisgreat.xyz";
};
- Step 2: Add SOPS secret declaration
Add after the OpenClaw secrets (around line 100):
sops.secrets.vaultwarden_admin_token = { };
- Step 3: Add SOPS template
Add after the openclaw.env template (around line 108):
sops.templates."vaultwarden.env" = {
content = ''
ADMIN_TOKEN=${config.sops.placeholder.vaultwarden_admin_token}
'';
};
- Step 4: Verify configuration builds
Run: nixos-rebuild build --flake .#nixos
Expected: Build succeeds without errors
- Step 5: Commit
git add configuration.nix
git commit -m "feat: enable Vaultwarden with secrets configuration
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>"
Task 5: Add Admin Token Secret (Manual)
Files:
-
Modify:
secrets/secrets.yaml(encrypted) -
Step 1: Edit secrets file
Run: nix-shell -p sops --run "sops secrets/secrets.yaml"
- Step 2: Add vaultwarden_admin_token
Add this entry to the YAML file:
vaultwarden_admin_token: "your-secure-admin-token-here"
Replace your-secure-admin-token-here with a strong password/token.
- Step 3: Save and exit
The file will be re-encrypted automatically.
Task 6: Deploy and Verify
- Step 1: Deploy configuration
Run: sudo nixos-rebuild switch --flake .#nixos
Expected: Deployment succeeds
- Step 2: Verify container is running
Run: sudo podman ps | grep vaultwarden
Expected: Container listed as running
- Step 3: Verify web interface
Run: curl -I http://127.0.0.1:8222
Expected: HTTP 200 response
- Step 4: Final commit (if any changes)
git status
# If secrets.yaml was modified (git tracks encrypted version):
git add secrets/secrets.yaml
git commit -m "chore: add Vaultwarden admin token secret
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>"
Summary
After completing all tasks:
- Nginx module supports extra locations for WebSocket endpoints
- Vaultwarden will be accessible at
https://vault.ashisgreat.xyz - WebSocket sync enabled for real-time updates
- Admin panel accessible at
/adminwith the configured token - SQLite database persisted in Podman volume
vaultwarden-data