nixos-vps/docs/superpowers/plans/2026-03-18-vaultwarden.md
ashisgreat22 a2a0dfaa58 docs: update Vaultwarden plan with nginx extraLocations fix
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 03:15:34 +01:00

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 extraLocations option 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:

  1. Nginx module supports extra locations for WebSocket endpoints
  2. Vaultwarden will be accessible at https://vault.ashisgreat.xyz
  3. WebSocket sync enabled for real-time updates
  4. Admin panel accessible at /admin with the configured token
  5. SQLite database persisted in Podman volume vaultwarden-data