# Vaultwarden Module # Provides: Lightweight Bitwarden-compatible password manager # # Usage: # myModules.vaultwarden = { # enable = true; # port = 8222; # domain = "vault.example.com"; # }; { config, lib, ... }: let cfg = config.myModules.vaultwarden; in { options.myModules.vaultwarden = { enable = lib.mkEnableOption "Vaultwarden password manager"; port = lib.mkOption { type = lib.types.port; default = 8222; description = "Port to expose Vaultwarden on localhost"; }; websocketPort = lib.mkOption { type = lib.types.port; default = 3012; description = "Port for WebSocket notifications"; }; domain = lib.mkOption { type = lib.types.str; example = "vault.example.com"; description = "Public domain name for Vaultwarden"; }; signupAllowed = lib.mkOption { type = lib.types.bool; default = true; description = "Whether to allow new user signups"; }; invitationsAllowed = lib.mkOption { type = lib.types.bool; default = false; description = "Whether to allow organization invitations"; }; showPasswordHint = lib.mkOption { type = lib.types.bool; default = false; description = "Whether to show password hints on login"; }; smtpHost = lib.mkOption { type = lib.types.nullOr lib.types.str; default = null; example = "smtp.example.com"; description = "SMTP server hostname for email notifications"; }; }; config = lib.mkIf cfg.enable { services.vaultwarden = { enable = true; dbBackend = "sqlite"; backupDir = "/var/backup/vaultwarden"; environmentFile = config.sops.templates."vaultwarden.env".path; config = { DOMAIN = "https://${cfg.domain}"; ROCKET_ADDRESS = "127.0.0.1"; ROCKET_PORT = cfg.port; WEBSOCKET_ENABLED = true; WEBSOCKET_ADDRESS = "127.0.0.1"; WEBSOCKET_PORT = cfg.websocketPort; SIGNUPS_ALLOWED = cfg.signupAllowed; INVITATIONS_ALLOWED = cfg.invitationsAllowed; SHOW_PASSWORD_HINT = cfg.showPasswordHint; # SMTP settings (optional) SMTP_HOST = lib.mkIf (cfg.smtpHost != null) cfg.smtpHost; SMTP_FROM = lib.mkIf (cfg.smtpHost != null) "vaultwarden@${cfg.domain}"; SMTP_PORT = lib.mkIf (cfg.smtpHost != null) 587; SMTP_SECURITY = lib.mkIf (cfg.smtpHost != null) "starttls"; }; }; # SOPS templates sops.templates."vaultwarden.env" = { content = '' ADMIN_TOKEN=${config.sops.placeholder.vaultwarden_admin_token} '' + lib.optionalString (cfg.smtpHost != null) '' SMTP_USERNAME=${config.sops.placeholder.vaultwarden_smtp_user} SMTP_PASSWORD=${config.sops.placeholder.vaultwarden_smtp_password} ''; }; # Secret definitions sops.secrets.vaultwarden_admin_token = { }; sops.secrets.vaultwarden_smtp_user = lib.mkIf (cfg.smtpHost != null) { }; sops.secrets.vaultwarden_smtp_password = lib.mkIf (cfg.smtpHost != null) { }; # Add nginx configuration for WebSocket support myModules.nginx.domains.${cfg.domain} = { port = cfg.port; extraConfig = '' client_max_body_size 128M; ''; extraLocations."/notifications/hub" = { proxyPass = "http://127.0.0.1:${toString cfg.websocketPort}"; extraConfig = '' proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; ''; }; extraLocations."/notifications/hub/negotiate" = { proxyPass = "http://127.0.0.1:${toString cfg.port}"; extraConfig = ""; }; }; # Ensure backups directory exists systemd.tmpfiles.rules = [ "d /var/backup/vaultwarden 0750 vaultwarden vaultwarden -" ]; }; }