diff options
Diffstat (limited to '')
-rw-r--r-- | modules/by-name/at/atuin-sync/module.nix | 45 | ||||
-rw-r--r-- | modules/by-name/ba/back/module.nix | 92 | ||||
-rw-r--r-- | modules/by-name/co/constants/module.nix | 98 | ||||
-rw-r--r-- | modules/by-name/gi/git-back/module.nix | 41 | ||||
-rw-r--r-- | modules/by-name/ma/mastodon/module.nix | 27 | ||||
-rw-r--r-- | modules/by-name/ma/matrix/module.nix | 78 | ||||
-rw-r--r-- | modules/by-name/ne/nextcloud/module.nix | 82 | ||||
-rw-r--r-- | modules/by-name/ng/nginx/module.nix | 5 | ||||
-rw-r--r-- | modules/by-name/re/redlib/module.nix | 5 | ||||
-rw-r--r-- | modules/by-name/ru/rust-motd/module.nix | 32 | ||||
-rw-r--r-- | modules/by-name/sh/sharkey/module.nix | 144 | ||||
-rw-r--r-- | modules/by-name/st/stalwart-mail/module.nix | 94 | ||||
-rw-r--r-- | modules/by-name/st/stalwart-mail/settings.nix | 56 | ||||
-rw-r--r-- | modules/by-name/sy/system-info/module.nix | 79 | ||||
-rw-r--r-- | modules/by-name/ta/taskchampion-sync/module.nix | 53 | ||||
-rw-r--r-- | modules/by-name/us/users/module.nix | 30 |
16 files changed, 707 insertions, 254 deletions
diff --git a/modules/by-name/at/atuin-sync/module.nix b/modules/by-name/at/atuin-sync/module.nix new file mode 100644 index 0000000..0db2e29 --- /dev/null +++ b/modules/by-name/at/atuin-sync/module.nix @@ -0,0 +1,45 @@ +{ + config, + lib, + vhackPackages, + ... +}: let + cfg = config.vhack.atuin-sync; +in { + options.vhack.atuin-sync = { + enable = lib.mkEnableOption "atuin sync server"; + + fqdn = lib.mkOption { + description = "The fully qualified domain name of this instance."; + type = lib.types.str; + example = "atuin-sync.atuin.sh"; + }; + }; + + config = lib.mkIf cfg.enable { + vhack.nginx.enable = true; + + services = { + nginx.virtualHosts."${cfg.fqdn}" = { + locations."/" = { + proxyPass = "http://127.0.0.1:${toString config.services.atuin.port}"; + recommendedProxySettings = true; + }; + + enableACME = true; + forceSSL = true; + }; + + atuin = { + enable = true; + package = vhackPackages.atuin-server-only; + host = "127.0.0.1"; + + # Nobody knows about the fqdn and even if, they can only upload encrypted blobs. + openRegistration = true; + + database.createLocally = true; + }; + }; + }; +} diff --git a/modules/by-name/ba/back/module.nix b/modules/by-name/ba/back/module.nix deleted file mode 100644 index d47ffce..0000000 --- a/modules/by-name/ba/back/module.nix +++ /dev/null @@ -1,92 +0,0 @@ -{ - config, - lib, - vhackPackages, - pkgs, - ... -}: let - cfg = config.vhack.back; -in { - options.vhack.back = { - enable = lib.mkEnableOption "Back issue tracker (inspired by tvix's panettone)"; - - domain = lib.mkOption { - type = lib.types.str; - description = "The domain to host this `back` instance on."; - }; - - settings = { - scan_path = lib.mkOption { - type = lib.types.path; - description = "The path to the directory under which all the repositories reside"; - }; - project_list = lib.mkOption { - type = lib.types.path; - description = "The path to the `projects.list` file."; - }; - - source_code_repository_url = lib.mkOption { - description = "The url to the source code of this instance of back"; - default = "https://git.foss-syndicate.org/vhack.eu/nixos-server/tree/pkgs/by-name/ba/back"; - type = lib.types.str; - }; - - root_url = lib.mkOption { - type = lib.types.str; - description = "The url to this instance of back."; - default = "https://${cfg.domain}"; - }; - }; - }; - - config = lib.mkIf cfg.enable { - systemd.services."back" = { - description = "Back issue tracking system."; - requires = ["network-online.target"]; - after = ["network-online.target"]; - wantedBy = ["default.target"]; - - serviceConfig = { - ExecStart = "${lib.getExe vhackPackages.back} ${(pkgs.formats.json {}).generate "config.json" cfg.settings}"; - - # Ensure that the service can read the repository - # FIXME(@bpeetz): This has the implied assumption, that all the exposed git - # repositories are readable for the git group. This should not be necessary. <2024-12-23> - User = "git"; - Group = "git"; - - DynamicUser = true; - Restart = "always"; - - # Sandboxing - ProtectSystem = "strict"; - ProtectHome = true; - PrivateTmp = true; - PrivateDevices = true; - ProtectHostname = true; - ProtectClock = true; - ProtectKernelTunables = true; - ProtectKernelModules = true; - ProtectKernelLogs = true; - ProtectControlGroups = true; - RestrictAddressFamilies = ["AF_UNIX" "AF_INET" "AF_INET6"]; - RestrictNamespaces = true; - LockPersonality = true; - MemoryDenyWriteExecute = true; - RestrictRealtime = true; - RestrictSUIDSGID = true; - RemoveIPC = true; - PrivateMounts = true; - # System Call Filtering - SystemCallArchitectures = "native"; - SystemCallFilter = ["~@cpu-emulation @debug @keyring @mount @obsolete @privileged @setuid"]; - }; - }; - services.nginx.virtualHosts."${cfg.domain}" = { - locations."/".proxyPass = "http://127.0.0.1:8000"; - - enableACME = true; - forceSSL = true; - }; - }; -} diff --git a/modules/by-name/co/constants/module.nix b/modules/by-name/co/constants/module.nix index fed14d3..2115a37 100644 --- a/modules/by-name/co/constants/module.nix +++ b/modules/by-name/co/constants/module.nix @@ -1,66 +1,94 @@ # This file is inspired by the `nixos/modules/misc/ids.nix` # file in nixpkgs. -{lib, ...}: { +{ + lib, + config, + ... +}: { options.vhack.constants = { ids.uids = lib.mkOption { internal = true; description = '' The user IDs used in the vhack.eu nixos config. ''; - type = lib.types.attrsOf lib.types.int; + type = lib.types.attrsOf (lib.types.ints.between 0 400); }; ids.gids = lib.mkOption { internal = true; description = '' The group IDs used in the vhack.eu nixos config. ''; - type = lib.types.attrsOf lib.types.int; + type = lib.types.attrsOf (lib.types.ints.between 0 400); }; }; config.vhack.constants = { ids.uids = { + # Keep this sorted with `!sort --numeric-sort --key=2 --field-separator="="` + systemd-coredump = 151; # GROUP + opendkim = 221; + mautrix-whatsapp = 222; + etebase-server = 223; + matrix-synapse = 224; + rspamd = 225; + knot-resolver = 226; + peertube = 231; + redis-mastodon = 232; + redis-peertube = 233; + redis-rspamd = 234; + redis-stalwart-mail = 235; + mastodon = 236; + stalwart-mail = 238; acme = 328; dhcpcd = 329; nscd = 330; sshd = 331; systemd-oom = 332; + resolvconf = 333; # GROUP nix-sync = 334; - redis-peertube = 990; - peertube = 992; # TODO Sort correctly - mastodon = 996; - redis-mastodon = 991; - matrix-synapse = 224; - mautrix-whatsapp = 225; - knot-resolver = 997; - redis-rspamd = 989; - rspamd = 225; - opendkim = 221; - virtualMail = 5000; - etebase-server = 998; + nextcloud = 335; + redis-nextcloud = 336; + taskchampion = 337; + stalwart-mail-certificates = 338; # GROUP + sharkey = 339; + redis-sharkey = 340; # As per the NixOS file, the uids should not be greater or equal to 400; }; - ids.gids = { - acme = 328; - dhcpcd = 329; - nscd = 330; - sshd = 331; - systemd-oom = 332; - resolvconf = 333; # This group is not matched to an user? - nix-sync = 334; - systemd-coredump = 151; # matches systemd-coredump user - redis-peertube = 990; - peertube = 992; - mastodon = 996; - redis-mastodon = 991; - matrix-synapse = 224; - knot-resolver = 997; - redis-rspamd = 989; - rspamd = 225; - opendkim = 221; - virtualMail = 5000; - etebase-server = 998; + ids.gids = let + inherit (config.vhack.constants.ids) uids; + in { + # Please add your groups to the users and inherit them here. + # This avoids having an user/group id mismatch. + inherit + (uids) + acme + dhcpcd + etebase-server + knot-resolver + mastodon + matrix-synapse + mautrix-whatsapp + nextcloud + nix-sync + nscd + opendkim + peertube + redis-mastodon + redis-nextcloud + redis-peertube + redis-rspamd + redis-stalwart-mail + rspamd + sshd + stalwart-mail + systemd-oom + sharkey + redis-sharkey + systemd-coredump # matches systemd-coredump user + resolvconf # This group is not matched to an user? + stalwart-mail-certificates # This group is used to connect nginx and stalwart-mail + ; # The gid should match the uid. Thus should not be >= 400; }; diff --git a/modules/by-name/gi/git-back/module.nix b/modules/by-name/gi/git-back/module.nix new file mode 100644 index 0000000..96f4913 --- /dev/null +++ b/modules/by-name/gi/git-back/module.nix @@ -0,0 +1,41 @@ +{ + config, + lib, + ... +}: let + cfg = config.vhack.git-back; +in { + options.vhack.git-back = { + enable = lib.mkEnableOption "Back integration into git-server"; + + domain = lib.mkOption { + type = lib.types.str; + description = "The domain where to deploy back"; + }; + }; + + config = lib.mkIf cfg.enable { + vhack.back = { + enable = true; + + user = "git"; + group = "git"; + + settings = { + scan_path = "${config.services.gitolite.dataDir}/repositories"; + project_list = "${config.services.gitolite.dataDir}/projects.list"; + root_url = "https://${cfg.domain}"; + }; + }; + + services.nginx = { + enable = true; + virtualHosts."${cfg.domain}" = { + locations."/".proxyPass = "http://127.0.0.1:8000"; + + enableACME = true; + forceSSL = true; + }; + }; + }; +} diff --git a/modules/by-name/ma/mastodon/module.nix b/modules/by-name/ma/mastodon/module.nix index 895428d..84f3ec8 100644 --- a/modules/by-name/ma/mastodon/module.nix +++ b/modules/by-name/ma/mastodon/module.nix @@ -37,16 +37,22 @@ in { owner = "mastodon"; group = "mastodon"; }; - vhack.persist.directories = [ - { - directory = "/var/lib/mastodon"; - user = "mastodon"; - group = "mastodon"; - mode = "0700"; - } - ]; - vhack.postgresql.enable = true; + vhack = { + persist.directories = [ + { + directory = "/var/lib/mastodon"; + user = "mastodon"; + group = "mastodon"; + mode = "0700"; + } + ]; + + postgresql.enable = true; + + nginx.enable = true; + }; + services.mastodon = { enable = true; @@ -54,7 +60,7 @@ in { # Unstable Mastodon package, used if # security updates aren't backported. - #package = applyPatches pkgs-unstable.mastodon; + #package = applyPatches pkgsUnstable.mastodon; localDomain = if cfg.enableTLD @@ -75,7 +81,6 @@ in { }; }; - vhack.nginx.enable = true; services.nginx = { enable = true; recommendedProxySettings = true; # required for redirections to work diff --git a/modules/by-name/ma/matrix/module.nix b/modules/by-name/ma/matrix/module.nix index 4b730da..ae3f04e 100644 --- a/modules/by-name/ma/matrix/module.nix +++ b/modules/by-name/ma/matrix/module.nix @@ -1,6 +1,5 @@ { config, - pkgs, lib, ... }: let @@ -29,6 +28,7 @@ in { description = "The age encrypted shared secret file for synapse, passed to agenix"; }; }; + config = lib.mkIf cfg.enable { age.secrets.matrix-synapse_registration_shared_secret = { file = cfg.sharedSecretFile; @@ -38,45 +38,53 @@ in { }; networking.firewall.allowedTCPPorts = [80 443]; - vhack.persist.directories = [ - { - directory = "/var/lib/matrix"; - user = "matrix-synapse"; - group = "matrix-synapse"; - mode = "0700"; - } - { - directory = "/var/lib/mautrix-whatsapp"; - user = "mautrix-whatsapp"; - group = "matrix-synapse"; - mode = "0750"; - } - ]; - systemd.tmpfiles.rules = [ - "d /etc/matrix 0755 matrix-synapse matrix-synapse" - ]; + vhack = { + persist.directories = [ + { + directory = "/var/lib/matrix"; + user = "matrix-synapse"; + group = "matrix-synapse"; + mode = "0700"; + } + { + directory = "/var/lib/mautrix-whatsapp"; + user = "mautrix-whatsapp"; + group = "matrix-synapse"; + mode = "0750"; + } + ]; - vhack.postgresql.enable = true; - vhack.nginx.enable = true; + postgresql.enable = true; + nginx.enable = true; + }; + + systemd = { + tmpfiles.rules = [ + "d /etc/matrix 0755 matrix-synapse matrix-synapse" + ]; + services.postgresql.postStart = '' + $PSQL -tAc "ALTER ROLE \"matrix-synapse\" WITH PASSWORD 'synapse';" + $PSQL -tAc "ALTER ROLE \"mautrix-whatsapp\" WITH PASSWORD 'whatsapp';" + ''; + }; services = { postgresql = { enable = true; - initialScript = pkgs.writeText "synapse-init.sql" '' - --Matrix: - CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse'; - CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse" - TEMPLATE template0 - LC_COLLATE = "C" - LC_CTYPE = "C"; - - --Whatsapp-bridge: - CREATE ROLE "mautrix-whatsapp" WITH LOGIN PASSWORD 'whatsapp'; - CREATE DATABASE "mautrix-whatsapp" WITH OWNER "mautrix-whatsapp" - TEMPLATE template0 - LC_COLLATE = "C" - LC_CTYPE = "C"; - ''; + ensureUsers = [ + { + name = "matrix-synapse"; + ensureDBOwnership = true; + } + { + name = "mautrix-whatsapp"; + ensureDBOwnership = true; + } + ]; + ensureDatabases = [ + "matrix-synapse" + "mautrix-whatsapp" + ]; }; nginx = { diff --git a/modules/by-name/ne/nextcloud/module.nix b/modules/by-name/ne/nextcloud/module.nix new file mode 100644 index 0000000..e0d7cb3 --- /dev/null +++ b/modules/by-name/ne/nextcloud/module.nix @@ -0,0 +1,82 @@ +{ + config, + pkgs, + lib, + ... +}: let + cfg = config.vhack.nextcloud; +in { + options.vhack.nextcloud = { + enable = lib.mkEnableOption "a sophisticated nextcloud setup"; + package = lib.mkOption { + type = lib.types.package; + default = pkgs.nextcloud31; + description = "The nextcloud package to use"; + }; + hostname = lib.mkOption { + type = lib.types.str; + description = "The nextcloud hostname (fqdn)"; + }; + adminpassFile = lib.mkOption { + type = lib.types.path; + description = "The age encrypted admin password file"; + }; + }; + config = lib.mkIf cfg.enable { + vhack = { + nginx.enable = true; + postgresql.enable = true; + persist.directories = [ + "/var/lib/nextcloud" + ]; + }; + age.secrets = { + adminpassFile = { + file = cfg.adminpassFile; + mode = "0700"; + owner = "nextcloud"; + group = "nextcloud"; + }; + }; + + services = { + nextcloud = { + enable = true; + extraApps = { + inherit (cfg.package.packages.apps) calendar contacts tasks; + }; + extraAppsEnable = true; + configureRedis = true; + config = { + adminuser = "admin"; + adminpassFile = config.age.secrets.adminpassFile.path; + dbname = "nextcloud"; + dbuser = "nextcloud"; + dbtype = "pgsql"; + }; + database.createLocally = true; + hostName = cfg.hostname; + https = true; + maxUploadSize = "5G"; + package = cfg.package; + settings = { + default_phone_region = "DE"; + }; + }; + nginx.virtualHosts.${cfg.hostname} = { + forceSSL = true; + enableACME = true; + }; + }; + users = { + users = { + "nextcloud".uid = config.vhack.constants.ids.uids.nextcloud; + "redis-nextcloud".uid = config.vhack.constants.ids.uids.redis-nextcloud; + }; + groups = { + "nextcloud".gid = config.vhack.constants.ids.gids.nextcloud; + "redis-nextcloud".gid = config.vhack.constants.ids.gids.redis-nextcloud; + }; + }; + }; +} diff --git a/modules/by-name/ng/nginx/module.nix b/modules/by-name/ng/nginx/module.nix index 1cb4e46..fa3337d 100644 --- a/modules/by-name/ng/nginx/module.nix +++ b/modules/by-name/ng/nginx/module.nix @@ -44,7 +44,10 @@ in { ]; users = { - users.acme.uid = config.vhack.constants.ids.uids.acme; + users.acme = { + uid = config.vhack.constants.ids.uids.acme; + group = "acme"; + }; groups.acme.gid = config.vhack.constants.ids.gids.acme; }; diff --git a/modules/by-name/re/redlib/module.nix b/modules/by-name/re/redlib/module.nix index eb5edba..909c9f1 100644 --- a/modules/by-name/re/redlib/module.nix +++ b/modules/by-name/re/redlib/module.nix @@ -32,10 +32,5 @@ in { forceSSL = true; }; }; - - # TODO(@bpeetz): Remove this at some point. <2025-02-04> - vhack.nginx.redirects = { - "libreddit.vhack.eu" = "${domain}"; - }; }; } diff --git a/modules/by-name/ru/rust-motd/module.nix b/modules/by-name/ru/rust-motd/module.nix index a6998f4..8d0939a 100644 --- a/modules/by-name/ru/rust-motd/module.nix +++ b/modules/by-name/ru/rust-motd/module.nix @@ -19,6 +19,13 @@ || v.openssh.authorizedKeys.keyFiles != [] ); userList = builtins.mapAttrs (n: v: 2) (lib.filterAttrs pred config.users.users); + + bannerFile = + pkgs.runCommandNoCCLocal "banner-file" { + nativeBuildInputs = [pkgs.figlet]; + } '' + echo "${config.system.name}" | figlet -f slant > "$out" + ''; in { options.vhack.rust-motd = { enable = lib.mkEnableOption "rust-motd"; @@ -49,25 +56,22 @@ in { banner = { color = "red"; - command = "${pkgs.hostname}/bin/hostname | ${pkgs.figlet}/bin/figlet -f slant"; - # if you don't want a dependency on figlet, you can generate your - # banner however you want, put it in a file, and then use something like: - # command = "cat banner.txt" + # Avoid some runtime dependencies. + command = "cat ${bannerFile}"; + }; + + cg_stats = { + state_file = "/var/lib/rust-motd/cg_stats_state"; + threshold = 0.02; # When to start generating output for a cgroup + }; + load_avg = { + format = "Load (1, 5, 15 min.): {one:.02}, {five:.02}, {fifteen:.02}"; }; uptime = { prefix = "Uptime:"; }; - # ssl_certificates = { - # sort_method = "manual"; - # - # certs = { - # "server1.vhack.eu" = "/var/lib/acme/server1.vhack.eu/cert.pem"; - # "vhack.eu" = "/var/lib/acme/vhack.eu/cert.pem"; - # }; - # }; - filesystems = { root = "/"; persistent = "/srv"; @@ -79,7 +83,7 @@ in { swap_pos = "beside"; # or "below" or "none" }; - fail2_ban = { + fail_2_ban = { jails = ["sshd"]; #, "anotherjail"] }; diff --git a/modules/by-name/sh/sharkey/module.nix b/modules/by-name/sh/sharkey/module.nix new file mode 100644 index 0000000..a296edd --- /dev/null +++ b/modules/by-name/sh/sharkey/module.nix @@ -0,0 +1,144 @@ +{ + config, + lib, + pkgs, + pkgsUnstable, + nixpkgs-unstable, + ... +}: let + cfg = config.vhack.sharkey; +in { + imports = [ + # TODO(@bpeetz): Remove this import once we update to NixOS 25.11 <2025-07-12> + "${nixpkgs-unstable}/nixos/modules/services/web-apps/sharkey.nix" + ]; + + options.vhack.sharkey = { + enable = lib.mkEnableOption "sharkey"; + + fqdn = lib.mkOption { + description = "The fully qualified domain name of this instance."; + type = lib.types.str; + example = "sharkey.shonk.social"; + }; + + package = lib.mkOption { + type = lib.types.package; + default = pkgsUnstable.sharkey; + defaultText = lib.literalExpression "vhackPackages.sharkey"; + description = "Sharkey package to use."; + }; + + mediaDirectory = lib.mkOption { + type = lib.types.path; + default = "/var/lib/sharkey"; + description = "The directory where sharkey stores it's data."; + }; + + settings = lib.mkOption { + inherit (pkgs.formats.yaml {}) type; + default = {}; + description = '' + Extra Configuration for Sharkey, see + <link xlink:href="https://activitypub.software/TransFem-org/Sharkey/-/blob/develop/.config/example.yml"/> + for supported settings. + + Note, that this is applied on-top of the neccessary config. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + services = { + sharkey = { + enable = true; + + inherit (cfg) package; + openFirewall = false; + setupRedis = true; + setupPostgresql = true; + + settings = + cfg.settings + // { + url = "https://${cfg.fqdn}/"; + port = 5312; + + inherit (cfg) mediaDirectory; + fulltextSearch.provider = "sqlLike"; + }; + }; + + nginx.virtualHosts."${cfg.fqdn}" = { + locations."/" = { + proxyPass = "http://127.0.0.1:${toString config.services.sharkey.settings.port}"; + proxyWebsockets = true; + }; + + enableACME = true; + forceSSL = true; + }; + }; + + systemd.services.sharkey = { + # TODO(@bpeetz): `postgresql.target` is only available in NixOS 25.11, as such we + # need to override this back to the postgresql.service. <2025-07-12> + after = lib.mkForce [ + "postgresql.service" + "redis-sharkey.service" + ]; + bindsTo = lib.mkForce [ + "postgresql.service" + "redis-sharkey.service" + ]; + + serviceConfig = { + # The upstream service uses DynamicUsers, which currently poses issues to our + # directory persisting strategy. + User = "sharkey"; + Group = "sharkey"; + DynamicUser = lib.mkForce false; + }; + }; + + vhack = { + nginx.enable = true; + + persist.directories = [ + { + directory = "${config.services.redis.servers."sharkey".settings.dir}"; + user = "sharkey"; + group = "redis-sharey"; + mode = "0770"; + } + { + directory = "${cfg.mediaDirectory}"; + user = "sharkey"; + group = "sharkey"; + mode = "0700"; + } + ]; + }; + + users = { + groups.sharkey = { + gid = config.vhack.constants.ids.gids.sharkey; + }; + users.sharkey = { + isSystemUser = true; + group = "sharkey"; + uid = config.vhack.constants.ids.uids.sharkey; + home = cfg.package; + packages = [cfg.package]; + }; + + groups.redis-sharkey = { + gid = config.vhack.constants.ids.gids.redis-sharkey; + }; + users.redis-sharkey = { + group = "redis-sharkey"; + uid = config.vhack.constants.ids.uids.redis-sharkey; + }; + }; + }; +} diff --git a/modules/by-name/st/stalwart-mail/module.nix b/modules/by-name/st/stalwart-mail/module.nix index 6905005..4565bf4 100644 --- a/modules/by-name/st/stalwart-mail/module.nix +++ b/modules/by-name/st/stalwart-mail/module.nix @@ -18,7 +18,7 @@ in { options.vhack.stalwart-mail = { enable = lib.mkEnableOption "starwart-mail"; - package = lib.mkPackageOption vhackPackages "stalwart-mail-free" {}; + package = lib.mkPackageOption vhackPackages "stalwart-mail-patched" {}; admin = lib.mkOption { description = '' @@ -41,8 +41,8 @@ in { }; principals = lib.mkOption { - default = []; - type = lib.types.listOf (lib.types.submodule { + default = null; + type = lib.types.nullOr (lib.types.listOf (lib.types.submodule { options = { name = lib.mkOption { type = lib.types.str; @@ -61,7 +61,32 @@ in { }; secret = lib.mkOption { - type = lib.types.str; + type = let + prefix = pre: lib.types.strMatching "^${lib.strings.escapeRegex pre}.*"; + in + lib.types.oneOf [ + (prefix "$argon2") + (prefix "$pbkdf2") + (prefix "$scrypt") + (prefix "$2") # bcrypt + (prefix "$6$") # sha-512 + (prefix "$5$") # sha-256 + (prefix "$sha1") + (prefix "$1") # md5 + (prefix "_") # BSDi crypt + (prefix "{SHA}") # base64 sha + (prefix "{SSHA}") # base64 salted sha + + # unix crypt + (prefix "{CRYPT}") + (prefix "{crypt}") + + # Plain text + (prefix "{PLAIN}") + (prefix "{plain}") + (prefix "{CLEAR}") + (prefix "{clear}") + ]; description = '' Sets the password for the user account. Passwords can be stored hashed or in plain text (not recommended). @@ -77,7 +102,7 @@ in { ''; }; }; - }); + })); }; dataDirectory = lib.mkOption { @@ -160,25 +185,16 @@ in { # However, this decision could obviously be reversed in the future. <2025-02-08> enable = false; inherit (cfg) package; - # dataDir = cfg.dataDirectory; }; - # FIXME(@bpeetz): This is currently needed for a successful acme http-01 challenge. - # We could also use the DNS challenge. <2025-03-01> nginx.virtualHosts."${cfg.fqdn}" = { - enableACME = false; - extraConfig = - # This is copied directly from the nixos nginx module. - # Rule for legitimate ACME Challenge requests (like /.well-known/acme-challenge/xxxxxxxxx) - # We use ^~ here, so that we don't check any regexes (which could - # otherwise easily override this intended match accidentally). - '' - location ^~ /.well-known/acme-challenge/ { - root ${config.security.acme.certs.${cfg.fqdn}.webroot}; - auth_basic off; - auth_request off; - } - ''; + locations."/" = { + proxyPass = "http://${builtins.elemAt config.services.stalwart-mail.settings.server.listener.http.bind 0}"; + recommendedProxySettings = true; + }; + + useACMEHost = "${cfg.fqdn}"; + forceSSL = true; }; redis = { @@ -209,7 +225,7 @@ in { security.acme.certs = { "${cfg.fqdn}" = { domain = cfg.fqdn; - group = "stalwart-mail"; + group = "stalwart-mail-certificates"; }; }; @@ -239,7 +255,7 @@ in { { directory = "${config.services.redis.servers."stalwart-mail".settings.dir}"; user = "stalwart-mail"; - group = "redis"; + group = "redis-stalwart-mail"; mode = "0770"; } ]; @@ -249,10 +265,31 @@ in { # service is restarted on a potentially large number of files. # That would cause unnecessary and unwanted delays. users = { - groups.stalwart-mail = {}; - users.stalwart-mail = { - isSystemUser = true; - group = "stalwart-mail"; + groups = { + stalwart-mail = { + gid = config.vhack.constants.ids.gids.stalwart-mail; + }; + stalwart-mail-certificates = { + gid = config.vhack.constants.ids.gids.stalwart-mail-certificates; + }; + redis-stalwart-mail = { + gid = config.vhack.constants.ids.gids.redis-stalwart-mail; + }; + }; + users = { + nginx = { + extraGroups = ["stalwart-mail-certificates"]; + }; + stalwart-mail = { + isSystemUser = true; + group = "stalwart-mail"; + uid = config.vhack.constants.ids.uids.stalwart-mail; + extraGroups = ["stalwart-mail-certificates"]; + }; + redis-stalwart-mail = { + group = "redis-stalwart-mail"; + uid = config.vhack.constants.ids.uids.redis-stalwart-mail; + }; }; }; @@ -311,8 +348,7 @@ in { ${lib.getExe cfg.package} --config="$CACHE_DIRECTORY/mutable_config_file.toml" ''; - Restart = "on-failure"; - RestartSec = 5; + Restart = "no"; KillMode = "process"; KillSignal = "SIGINT"; diff --git a/modules/by-name/st/stalwart-mail/settings.nix b/modules/by-name/st/stalwart-mail/settings.nix index 7032ae0..907cea9 100644 --- a/modules/by-name/st/stalwart-mail/settings.nix +++ b/modules/by-name/st/stalwart-mail/settings.nix @@ -18,6 +18,11 @@ if cfg.security != null then cfg.security.verificationMode else "disable"; + + directory = + if cfg.principals == null + then "internal" + else "in-memory"; in { config.services.stalwart-mail.settings = lib.mkIf cfg.enable { # https://www.rfc-editor.org/rfc/rfc6376.html#section-3.3 @@ -219,7 +224,7 @@ in { require = true; }; rcpt = { - directory = "'in-memory'"; + directory = "'${directory}'"; catch-all = true; subaddressing = true; }; @@ -236,7 +241,7 @@ in { }; auth = { mechanisms = ["LOGIN" "PLAIN"]; - directory = "'in-memory'"; + directory = "'${directory}'"; require = true; must-match-sender = true; errors = { @@ -339,13 +344,13 @@ in { hostname = cfg.fqdn; listener = { - # TODO(@bpeetz): Add this <2025-02-08> - # # HTTP (used for jmap) - # "http" = { - # bind = ["[::]:8080"]; - # protocol = "http"; - # tls.implicit = true; - # }; + # HTTP (used for jmap) + "http" = { + bind = ["127.0.0.1:8112"]; + protocol = "http"; + # handled by ngnix + tls.implicit = false; + }; # IMAP "imap" = { @@ -401,11 +406,12 @@ in { certificate = "default"; }; - # TODO(@bpeetz): Configure that <2025-02-07> - # http = { - # url = ""; - # allowed-endpoint = ["404"]; - # }; + http = { + url = "protocol + '://' + config_get('server.hostname') + ':' + local_port"; + + # We are behind a nginx proxy, and can thus trust this header. + use-x-forwarded = true; + }; auto-ban = { # Ban if the same IP fails to login 10 times in a day @@ -467,6 +473,14 @@ in { # Perform “maintenance” every day at 3 am local time. purge.frequency = "0 3 *"; }; + "rocksdb-directory" = lib.mkIf (cfg.principals == null) { + type = "rocksdb"; + path = "${cfg.dataDirectory}/storage/directory"; + compression = "lz4"; + + # Perform “maintenance” every day at 1 am local time. + purge.frequency = "0 1 *"; + }; "rocksdb-full-text-search" = { type = "rocksdb"; path = "${cfg.dataDirectory}/storage/full-text-search"; @@ -505,7 +519,7 @@ in { full-text.default-language = "en"; fts = "rocksdb-full-text-search"; - directory = "in-memory"; + directory = "${directory}"; lookup = "redis"; @@ -516,9 +530,15 @@ in { encryption.enable = false; }; - directory."in-memory" = { - type = "memory"; - inherit (cfg) principals; + directory = { + "in-memory" = lib.mkIf (cfg.principals != null) { + type = "memory"; + inherit (cfg) principals; + }; + "internal" = lib.mkIf (cfg.principals == null) { + type = "internal"; + store = "rocksdb-directory"; + }; }; certificate = { diff --git a/modules/by-name/sy/system-info/module.nix b/modules/by-name/sy/system-info/module.nix new file mode 100644 index 0000000..8136ae5 --- /dev/null +++ b/modules/by-name/sy/system-info/module.nix @@ -0,0 +1,79 @@ +{ + lib, + config, + pkgs, + ... +}: let + mkVirtualHostDisplay = name: value: let + aliases = + if value.serverAliases != [] + then + ": " + + builtins.concatStringsSep " " value.serverAliases + else ""; + in '' + ${name}${aliases} + ''; + vHosts = builtins.concatStringsSep "" (builtins.attrValues (builtins.mapAttrs mkVirtualHostDisplay config.services.nginx.virtualHosts)); + + mkOpenPortDisplay = mode: port: let + checkEnabled = service: name: + if config.vhack.${service}.enable + then name + else "<port is '${name}' but service 'vhack.${service}' is not enabled.>"; + mappings = { + "22" = checkEnabled "openssh" "ssh"; + "80" = checkEnabled "nginx" "http"; + "443" = checkEnabled "nginx" "https"; + + "53" = checkEnabled "dns" "dns"; + + "24" = checkEnabled "mail" "mail-lmtp"; + "465" = checkEnabled "mail" "mail-smtp-tls"; + "25" = checkEnabled "mail" "mail-smtp"; + "993" = checkEnabled "mail" "mail-imap-tls"; + "995" = checkEnabled "mail" "mail-pop3-tls"; + + "10222" = checkEnabled "taskchampion-sync" "taskchampion-sync"; + + # TODO(@bpeetz): Check which service opens these ports: <2025-01-28> + "64738" = "???"; + "4190" = "???"; + }; + in '' + ${mode} ${builtins.toString port}: ${ + if (builtins.hasAttr "${builtins.toString port}" mappings) + then mappings.${builtins.toString port} + else + builtins.throw + "'${builtins.toString port}' is still missing from the system info port -> name map. Maybe add it?" + } + ''; + + # TODO(@bpeetz): This should probably also include the allowed TCP/UDP port ranges. <2025-01-28> + openTCPPorts = builtins.concatStringsSep "" (builtins.map (mkOpenPortDisplay "TCP") config.networking.firewall.allowedTCPPorts); + openUDPPorts = builtins.concatStringsSep "" (builtins.map (mkOpenPortDisplay "UDP") config.networking.firewall.allowedUDPPorts); + + markdown = pkgs.writeText "${config.networking.hostName}-system-info.md" '' + ## Virtual Hosts + ${vHosts} + ## Open ports + ${openTCPPorts} + ${openUDPPorts} + ''; +in { + options.vhack.system-info = { + markdown = lib.mkOption { + type = lib.types.package; + description = '' + A derivation, that builds a markdown file, showing relevant system + information for this host. + ''; + readOnly = true; + }; + }; + + config.vhack.system-info = { + inherit markdown; + }; +} diff --git a/modules/by-name/ta/taskchampion-sync/module.nix b/modules/by-name/ta/taskchampion-sync/module.nix new file mode 100644 index 0000000..a722883 --- /dev/null +++ b/modules/by-name/ta/taskchampion-sync/module.nix @@ -0,0 +1,53 @@ +{ + config, + lib, + ... +}: let + cfg = config.vhack.taskchampion-sync; + dataDirectory = "/var/lib/taskchampion-sync-server"; +in { + options.vhack.taskchampion-sync = { + enable = lib.mkEnableOption "taskchampion-sync"; + + fqdn = lib.mkOption { + description = "The fully qualified domain name of this instance."; + type = lib.types.str; + example = "task-sync.tw.online"; + }; + }; + + config = lib.mkIf cfg.enable { + users = { + users.taskchampion.uid = config.vhack.constants.ids.uids.taskchampion; + groups.taskchampion.gid = config.vhack.constants.ids.uids.taskchampion; + }; + + vhack = { + persist.directories = [ + { + directory = dataDirectory; + user = "taskchampion"; + group = "taskchampion"; + mode = "0700"; + } + ]; + nginx.enable = true; + }; + + services = { + taskchampion-sync-server = { + enable = true; + dataDir = dataDirectory; + }; + + nginx.virtualHosts."${cfg.fqdn}" = { + locations."/" = { + proxyPass = "http://127.0.0.1:${toString config.services.taskchampion-sync-server.port}"; + recommendedProxySettings = true; + }; + enableACME = true; + forceSSL = true; + }; + }; + }; +} diff --git a/modules/by-name/us/users/module.nix b/modules/by-name/us/users/module.nix index a197b13..6011204 100644 --- a/modules/by-name/us/users/module.nix +++ b/modules/by-name/us/users/module.nix @@ -27,20 +27,22 @@ }; }; - extraUsers = lib.listToAttrs (builtins.map mkUser [ - { - name = "soispha"; - password = "$y$jFT$3.8XmUyukZvpExMUxDZkI.$IVrJgm8ysNDF/0vDD2kF6w73ozXgr1LMVRNN4Bq7pv1"; - sshKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIME4ZVa+IoZf6T3U08JG93i6QIAJ4amm7mkBzO14JSkz cardno:000F_18F83532"; - uid = 1000; - } - { - name = "sils"; - password = "$y$jFT$KpFnahVCE9JbE.5P3us8o.$ZzSxCusWqe3sL7b6DLgOXNNUf114tiiptM6T8lDxtKC"; - sshKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAe4o1PM6VasT3KZNl5NYvgkkBrPOg36dqsywd10FztS openpgp:0x21D20D6A"; - uid = 1001; - } - ]); + extraUsers = lib.listToAttrs ( + builtins.map mkUser [ + { + name = "soispha"; + password = "$y$jFT$3.8XmUyukZvpExMUxDZkI.$IVrJgm8ysNDF/0vDD2kF6w73ozXgr1LMVRNN4Bq7pv1"; + sshKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIME4ZVa+IoZf6T3U08JG93i6QIAJ4amm7mkBzO14JSkz cardno:000F_18F83532"; + uid = 1000; + } + { + name = "sils"; + password = "$y$jFT$KpFnahVCE9JbE.5P3us8o.$ZzSxCusWqe3sL7b6DLgOXNNUf114tiiptM6T8lDxtKC"; + sshKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILn7Oumr5IYtTTIKRFvDnofGXXiDLBQE9jVF+7UE+4G5 vhack.eu"; + uid = 1001; + } + ] + ); in { options.vhack.users = { enable = lib.mkEnableOption "user setup"; |