From 595b301a8d5a0019898c01b67f15cd556b7501e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20J=C3=A4ckel?= Date: Mon, 8 Dec 2025 22:55:48 +0100 Subject: [PATCH 1/3] nixos/vaultwarden: format --- .../services/security/vaultwarden/default.nix | 180 +++++++++--------- 1 file changed, 92 insertions(+), 88 deletions(-) diff --git a/nixos/modules/services/security/vaultwarden/default.nix b/nixos/modules/services/security/vaultwarden/default.nix index 5bcd5eee6324..c2778b535d13 100644 --- a/nixos/modules/services/security/vaultwarden/default.nix +++ b/nixos/modules/services/security/vaultwarden/default.nix @@ -212,98 +212,102 @@ in } ]; - users.users.vaultwarden = { - inherit group; - isSystemUser = true; - }; - users.groups.vaultwarden = { }; + systemd = { + services.vaultwarden = { + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; + path = with pkgs; [ openssl ]; + serviceConfig = { + User = user; + Group = group; + EnvironmentFile = [ configFile ] ++ cfg.environmentFile; + ExecStart = lib.getExe vaultwarden; + LimitNOFILE = "1048576"; + CapabilityBoundingSet = [ "" ]; + DeviceAllow = [ "" ]; + DevicePolicy = "closed"; + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = !useSendmail; + PrivateDevices = !useSendmail; + PrivateTmp = true; + PrivateUsers = !useSendmail; + ProcSubset = "pid"; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "noaccess"; + ProtectSystem = "strict"; + RemoveIPC = true; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + "AF_UNIX" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + inherit StateDirectory; + StateDirectoryMode = "0700"; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + ] + ++ lib.optionals (!useSendmail) [ + "~@privileged" + ]; + Restart = "always"; + UMask = "0077"; + }; + wantedBy = [ "multi-user.target" ]; + }; - systemd.services.vaultwarden = { - after = [ "network-online.target" ]; - wants = [ "network-online.target" ]; - path = with pkgs; [ openssl ]; - serviceConfig = { - User = user; - Group = group; - EnvironmentFile = [ configFile ] ++ cfg.environmentFile; - ExecStart = lib.getExe vaultwarden; - LimitNOFILE = "1048576"; - CapabilityBoundingSet = [ "" ]; - DeviceAllow = [ "" ]; - DevicePolicy = "closed"; - LockPersonality = true; - MemoryDenyWriteExecute = true; - NoNewPrivileges = !useSendmail; - PrivateDevices = !useSendmail; - PrivateTmp = true; - PrivateUsers = !useSendmail; - ProcSubset = "pid"; - ProtectClock = true; - ProtectControlGroups = true; - ProtectHome = true; - ProtectHostname = true; - ProtectKernelLogs = true; - ProtectKernelModules = true; - ProtectKernelTunables = true; - ProtectProc = "noaccess"; - ProtectSystem = "strict"; - RemoveIPC = true; - RestrictAddressFamilies = [ - "AF_INET" - "AF_INET6" - "AF_UNIX" - ]; - RestrictNamespaces = true; - RestrictRealtime = true; - RestrictSUIDSGID = true; - inherit StateDirectory; - StateDirectoryMode = "0700"; - SystemCallArchitectures = "native"; - SystemCallFilter = [ - "@system-service" - ] - ++ lib.optionals (!useSendmail) [ - "~@privileged" - ]; - Restart = "always"; - UMask = "0077"; + services.backup-vaultwarden = lib.mkIf (cfg.backupDir != null) { + description = "Backup vaultwarden"; + environment = { + DATA_FOLDER = dataDir; + BACKUP_FOLDER = cfg.backupDir; + }; + path = with pkgs; [ sqlite ]; + # if both services are started at the same time, vaultwarden fails with "database is locked" + before = [ "vaultwarden.service" ]; + serviceConfig = { + SyslogIdentifier = "backup-vaultwarden"; + Type = "oneshot"; + User = lib.mkDefault user; + Group = lib.mkDefault group; + ExecStart = "${pkgs.bash}/bin/bash ${./backup.sh}"; + }; + wantedBy = [ "multi-user.target" ]; + }; + + timers.backup-vaultwarden = lib.mkIf (cfg.backupDir != null) { + description = "Backup vaultwarden on time"; + timerConfig = { + OnCalendar = lib.mkDefault "23:00"; + Persistent = "true"; + Unit = "backup-vaultwarden.service"; + }; + wantedBy = [ "multi-user.target" ]; + }; + + tmpfiles.settings = lib.mkIf (cfg.backupDir != null) { + "10-vaultwarden".${cfg.backupDir}.d = { + inherit user group; + mode = "0770"; + }; }; - wantedBy = [ "multi-user.target" ]; }; - systemd.services.backup-vaultwarden = lib.mkIf (cfg.backupDir != null) { - description = "Backup vaultwarden"; - environment = { - DATA_FOLDER = dataDir; - BACKUP_FOLDER = cfg.backupDir; - }; - path = with pkgs; [ sqlite ]; - # if both services are started at the same time, vaultwarden fails with "database is locked" - before = [ "vaultwarden.service" ]; - serviceConfig = { - SyslogIdentifier = "backup-vaultwarden"; - Type = "oneshot"; - User = lib.mkDefault user; - Group = lib.mkDefault group; - ExecStart = "${pkgs.bash}/bin/bash ${./backup.sh}"; - }; - wantedBy = [ "multi-user.target" ]; - }; - - systemd.timers.backup-vaultwarden = lib.mkIf (cfg.backupDir != null) { - description = "Backup vaultwarden on time"; - timerConfig = { - OnCalendar = lib.mkDefault "23:00"; - Persistent = "true"; - Unit = "backup-vaultwarden.service"; - }; - wantedBy = [ "multi-user.target" ]; - }; - - systemd.tmpfiles.settings = lib.mkIf (cfg.backupDir != null) { - "10-vaultwarden".${cfg.backupDir}.d = { - inherit user group; - mode = "0770"; + users = { + groups.vaultwarden = { }; + users.vaultwarden = { + inherit group; + isSystemUser = true; }; }; }; From 16270a08a89ed762b5029f9190b4fe684f33b141 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20J=C3=A4ckel?= Date: Mon, 8 Dec 2025 23:00:48 +0100 Subject: [PATCH 2/3] nixos/vaultwarden: add configureNginx option --- .../services/security/vaultwarden/default.nix | 64 ++++++++++++++----- 1 file changed, 49 insertions(+), 15 deletions(-) diff --git a/nixos/modules/services/security/vaultwarden/default.nix b/nixos/modules/services/security/vaultwarden/default.nix index c2778b535d13..9b67ec506580 100644 --- a/nixos/modules/services/security/vaultwarden/default.nix +++ b/nixos/modules/services/security/vaultwarden/default.nix @@ -115,21 +115,7 @@ in DOMAIN = "https://bitwarden.example.com"; SIGNUPS_ALLOWED = false; - # Vaultwarden currently recommends running behind a reverse proxy - # (nginx or similar) for TLS termination, see - # https://github.com/dani-garcia/vaultwarden/wiki/Hardening-Guide#reverse-proxying - # > you should avoid enabling HTTPS via vaultwarden's built-in Rocket TLS support, - # > especially if your instance is publicly accessible. - # - # A suitable NixOS nginx reverse proxy example config might be: - # - # services.nginx.virtualHosts."bitwarden.example.com" = { - # enableACME = true; - # forceSSL = true; - # locations."/" = { - # proxyPass = "http://127.0.0.1:''${toString config.services.vaultwarden.config.ROCKET_PORT}"; - # }; - # }; + # Vaultwarden recommends running behind a reverse proxy, the configureNginx option can be used for that. ROCKET_ADDRESS = "127.0.0.1"; ROCKET_PORT = 8222; @@ -171,6 +157,18 @@ in ''; }; + configureNginx = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether to configure nginx to serve VaultWarden."; + }; + + domain = lib.mkOption { + type = with lib.types; nullOr str; + default = null; + description = "The domain under which VaultWarden will be reachable."; + }; + environmentFile = lib.mkOption { type = with lib.types; coercedTo path lib.singleton (listOf path); default = [ ]; @@ -210,8 +208,44 @@ in assertion = cfg.backupDir != null -> !(lib.hasPrefix dataDir cfg.backupDir); message = "Backup directory can not be in ${dataDir}"; } + { + assertion = cfg.configureNginx -> cfg.domain != null; + message = "Setting services.vaultwarden.configureNginx to true requires configuring services.vaultwarden.domain!"; + } ]; + services = { + nginx = lib.mkIf cfg.configureNginx { + enable = true; + upstreams.vaultwarden.servers."127.0.0.1:${toString cfg.config.ROCKET_PORT}" = { }; + virtualHosts.${cfg.domain} = { + forceSSL = true; + locations = { + "/".proxyPass = "http://vaultwarden"; + "= /notifications/anonymous-hub" = { + proxyPass = "http://vaultwarden"; + proxyWebsockets = true; + }; + "= /notifications/hub" = { + proxyPass = "http://vaultwarden"; + proxyWebsockets = true; + }; + }; + }; + }; + + vaultwarden.config = lib.mkMerge [ + { + DOMAIN = lib.mkIf (cfg.domain != null) "https://${cfg.domain}"; + } + (lib.mkIf cfg.configureNginx { + ENABLE_WEBSOCKET = true; + ROCKET_ADDRESS = "127.0.0.1"; + ROCKET_PORT = lib.mkDefault 8222; + }) + ]; + }; + systemd = { services.vaultwarden = { after = [ "network-online.target" ]; From 25729b3bfd189b4b2894efcf1e56689be008841f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20J=C3=A4ckel?= Date: Mon, 8 Dec 2025 23:01:52 +0100 Subject: [PATCH 3/3] nixos/vaultwarden: add configurePostgres option --- .../services/security/vaultwarden/default.nix | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/nixos/modules/services/security/vaultwarden/default.nix b/nixos/modules/services/security/vaultwarden/default.nix index 9b67ec506580..d8b19dfb282d 100644 --- a/nixos/modules/services/security/vaultwarden/default.nix +++ b/nixos/modules/services/security/vaultwarden/default.nix @@ -7,6 +7,7 @@ let cfg = config.services.vaultwarden; + user = config.users.users.vaultwarden.name; group = config.users.groups.vaultwarden.name; @@ -163,6 +164,12 @@ in description = "Whether to configure nginx to serve VaultWarden."; }; + configurePostgres = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether to configure a local PostgreSQL server."; + }; + domain = lib.mkOption { type = with lib.types; nullOr str; default = null; @@ -234,8 +241,20 @@ in }; }; + postgresql = lib.mkIf cfg.configurePostgres { + enable = true; + ensureDatabases = [ "vaultwarden" ]; + ensureUsers = [ + { + name = "vaultwarden"; + ensureDBOwnership = true; + } + ]; + }; + vaultwarden.config = lib.mkMerge [ { + DATABASE_URL = lib.mkIf cfg.configurePostgres "postgresql:///vaultwarden?host=/run/postgresql"; DOMAIN = lib.mkIf (cfg.domain != null) "https://${cfg.domain}"; } (lib.mkIf cfg.configureNginx { @@ -248,7 +267,8 @@ in systemd = { services.vaultwarden = { - after = [ "network-online.target" ]; + after = [ "network-online.target" ] ++ lib.optional cfg.configurePostgres "postgresql.target"; + requires = lib.mkIf cfg.configurePostgres [ "postgresql.target" ]; wants = [ "network-online.target" ]; path = with pkgs; [ openssl ]; serviceConfig = {