diff --git a/modules/default.nix b/modules/default.nix index 1e8d13b..cf4cc67 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -6,5 +6,6 @@ ./nginx.nix ./searxng.nix ./openclaw-podman.nix + ./vaultwarden.nix ]; } diff --git a/modules/vaultwarden.nix b/modules/vaultwarden.nix new file mode 100644 index 0000000..bb0baec --- /dev/null +++ b/modules/vaultwarden.nix @@ -0,0 +1,137 @@ +# Vaultwarden Module +# Provides: Lightweight Bitwarden-compatible password manager +# +# Usage: +# myModules.vaultwarden = { +# enable = true; +# port = 8222; +# domain = "vault.example.com"; +# }; + +{ + config, + lib, + pkgs, + ... +}: + +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 -" + ]; + }; +}