{ config, inputs, lib, this, ... }: with lib; let cfg = config.nixfiles.modules.vaultwarden; in { options.nixfiles.modules.vaultwarden = { enable = mkEnableOption "Vaultwarden"; domain = mkOption { description = "Domain name sans protocol scheme."; type = with types; str; default = "vaultwarden.${config.networking.domain}"; }; }; config = let db = "vaultwarden"; in mkIf cfg.enable { ark.directories = [ "/var/lib/bitwarden_rs" ]; secrets.vaultwarden-environment = { file = "${inputs.self}/secrets/vaultwarden-environment"; owner = "vaultwarden"; group = "vaultwarden"; }; nixfiles.modules = { nginx = { enable = true; upstreams = with config.services.vaultwarden.config; { vaultwarden_rocket.servers."${ROCKET_ADDRESS}:${toString ROCKET_PORT}" = { }; vaultwarden_websocket.servers."${WEBSOCKET_ADDRESS}:${toString WEBSOCKET_PORT}" = { }; }; virtualHosts.${cfg.domain}.locations = { "/" = { proxyPass = "http://vaultwarden_rocket"; proxyWebsockets = true; }; "/notifications/hub" = { proxyPass = "http://vaultwarden_websocket"; proxyWebsockets = true; }; "/notifications/hub/negotiate" = { proxyPass = "http://vaultwarden_rocket"; proxyWebsockets = true; }; }; }; postgresql = { enable = true; extraPostStart = [ '' $PSQL "${db}" -tAc 'GRANT ALL ON SCHEMA "public" TO "${db}"' '' ]; }; }; services = { vaultwarden = { enable = true; config = { TZ = config.time.timeZone; WEB_VAULT_ENABLED = true; DOMAIN = optionalString (cfg.domain != null) "http://${cfg.domain}"; SIGNUPS_ALLOWED = false; INVITATIONS_ALLOWED = false; ORG_CREATION_USERS = "none"; PASSWORD_HINTS_ALLOWED = false; SHOW_PASSWORD_HINT = false; ROCKET_ADDRESS = "127.0.0.1"; ROCKET_PORT = 8812; WEBSOCKET_ENABLED = true; WEBSOCKET_ADDRESS = "127.0.0.1"; WEBSOCKET_PORT = 8813; LOG_LEVEL = "error"; DATABASE_URL = "postgresql://${db}@/${db}"; }; dbBackend = "postgresql"; environmentFile = config.secrets.vaultwarden-environment.path; }; postgresql = { ensureDatabases = [ db ]; ensureUsers = [ { name = db; ensureDBOwnership = true; } ]; }; fail2ban.jails = { vaultwarden = { enabled = true; settings = { filter = "vaultwarden"; port = "http,https"; }; }; vaultwarden-admin = { enabled = true; settings = { filter = "vaultwarden-admin"; port = "http,https"; }; }; }; }; environment.etc = { "fail2ban/filter.d/vaultwarden.conf".text = generators.toINI { } { Definition = { failregex = "^.*Username or password is incorrect\. Try again\. IP: \. Username:.*$"; ignoreregex = ""; journalmatch = "_SYSTEMD_UNIT=vaultwarden.service"; }; }; "fail2ban/filter.d/vaultwarden-admin.conf".text = generators.toINI { } { Definition = { failregex = "^.*Invalid admin token\. IP: .*$"; ignoreregex = ""; journalmatch = "_SYSTEMD_UNIT=vaultwarden.service"; }; }; }; topology = with cfg; { nodes.${this.hostname}.services.vaultwarden = { info = mkForce domain; }; }; }; }