diff --git a/system/flake.nix b/system/flake.nix index 30d0e78..4896261 100644 --- a/system/flake.nix +++ b/system/flake.nix @@ -36,7 +36,7 @@ inherit nixpkgs; }; lib = nixpkgs.lib // { - quotePotentialIpV6 = addr: + quoteListenAddr = addr: if nixpkgs.lib.hasInfix ":" addr then "[${addr}]" else addr; }; specialArgs = { diff --git a/system/hosts/nixserver/default.nix b/system/hosts/nixserver/default.nix index cfc69b6..d953cb9 100644 --- a/system/hosts/nixserver/default.nix +++ b/system/hosts/nixserver/default.nix @@ -34,6 +34,7 @@ in { ./matrix.nix ./fdroid.nix ./mumble.nix + ./mailserver.nix ]; system.stateVersion = "22.11"; @@ -75,11 +76,7 @@ in { path = /persist; directories = [ { directory = /var/www/${cfg.domainName}; } - { directory = /var/lib/maubot; } - { directory = /var/lib/fdroid; } - { directory = config.mailserver.dkimKeyDirectory; } - { directory = config.mailserver.mailDirectory; } - { directory = /home/user; } + { directory = /home/${config.common.mainUsername}; } { directory = /root; } { directory = /nix; } ]; @@ -109,12 +106,12 @@ in { allowedUDPPorts = [ # dns 53 853 - # wireguard - # 5553 ]; }; # UNBOUND + users.users.${config.common.mainUsername}.extraGroups = [ config.services.unbound.group ]; + services.unbound = { enable = true; package = pkgs.unbound-with-systemd.override { @@ -166,8 +163,6 @@ in { startWhenNeeded = false; }; - users.users.user.extraGroups = [ config.services.unbound.group ]; - services.postgresql.enable = true; services.postgresql.package = pkgs.postgresql_13; @@ -203,7 +198,7 @@ in { }); services.searx.runInUwsgi = true; services.searx.uwsgiConfig = let inherit (config.services.searx) settings; in { - socket = "${lib.quotePotentialIpV6 settings.server.bind_address}:${toString settings.server.port}"; + socket = "${lib.quoteListenAddr settings.server.bind_address}:${toString settings.server.port}"; }; services.searx.environmentFile = /var/lib/searx/searx.env; services.searx.settings = { @@ -239,9 +234,9 @@ in { services.nginx.virtualHosts."search.${cfg.domainName}" = let inherit (config.services.searx) settings; in { enableACME = true; forceSSL = true; - # locations."/".proxyPass = "http://${lib.quotePotentialIpV6 settings.server.bind_address}:${toString settings.server.port}"; + # locations."/".proxyPass = "http://${lib.quoteListenAddr settings.server.bind_address}:${toString settings.server.port}"; locations."/".extraConfig = '' - uwsgi_pass "${lib.quotePotentialIpV6 settings.server.bind_address}:${toString settings.server.port}"; + uwsgi_pass "${lib.quoteListenAddr settings.server.bind_address}:${toString settings.server.port}"; include ${config.services.nginx.package}/conf/uwsgi_params; ''; }; @@ -295,55 +290,11 @@ in { globalRedirect = cfg.domainName; }; - # MAILSERVER - # roundcube - services.nginx.virtualHosts."mail.${cfg.domainName}" = { - enableACME = true; - }; - services.roundcube = { - enable = true; - package = pkgs.roundcube.withPlugins (plugins: [ plugins.persistent_login ]); - dicts = with pkgs.aspellDicts; [ en ru ]; - hostName = "mail.${cfg.domainName}"; - maxAttachmentSize = 100; - plugins = [ "persistent_login" ]; - }; - mailserver = { - enable = true; - fqdn = "mail.${cfg.domainName}"; - domains = [ cfg.domainName ]; - certificateScheme = 1; - certificateFile = config.security.acme.certs."mail.${cfg.domainName}".directory + "/fullchain.pem"; - keyFile = config.security.acme.certs."mail.${cfg.domainName}".directory + "/key.pem"; - localDnsResolver = false; - recipientDelimiter = "-"; - lmtpSaveToDetailMailbox = "no"; - hierarchySeparator = "/"; - }; - - # Only allow local connections to noreply account - mailserver.loginAccounts."noreply@${cfg.domainName}" = { - # password is set in private.nix - hashedPassword = cfg.hashedNoreplyPassword; - sendOnly = true; - }; - services.dovecot2.extraConfig = - let - passwd = builtins.toFile "dovecot2-local-passwd" '' - noreply@${cfg.domainName}:{plain}${cfg.unhashedNoreplyPassword}::::::allow_nets=local,127.0.0.0/8,::1 - ''; - in '' - passdb { - driver = passwd-file - args = ${passwd} - } - ''; - # GITEA services.nginx.virtualHosts."git.${cfg.domainName}" = let inherit (config.services.gitea) settings; in { enableACME = true; forceSSL = true; - locations."/".proxyPass = "http://${lib.quotePotentialIpV6 settings.server.HTTP_ADDR}:${toString settings.server.HTTP_PORT}"; + locations."/".proxyPass = "http://${lib.quoteListenAddr settings.server.HTTP_ADDR}:${toString settings.server.HTTP_PORT}"; }; services.gitea = { enable = true; diff --git a/system/hosts/nixserver/fdroid.nix b/system/hosts/nixserver/fdroid.nix index dbb89d9..a7d0111 100644 --- a/system/hosts/nixserver/fdroid.nix +++ b/system/hosts/nixserver/fdroid.nix @@ -5,6 +5,9 @@ let cfg = config.server; in { + impermanence.directories = [ + { directory = /var/lib/fdroid; user = "fdroid"; group = "fdroid"; mode = "0755"; } + ]; services.nginx.virtualHosts."${cfg.domainName}" = { locations."/fdroid/".alias = "/var/lib/fdroid/repo/"; }; diff --git a/system/hosts/nixserver/mailserver.nix b/system/hosts/nixserver/mailserver.nix new file mode 100644 index 0000000..238dbeb --- /dev/null +++ b/system/hosts/nixserver/mailserver.nix @@ -0,0 +1,56 @@ +{ config +, pkgs +, ... }: + +let + cfg = config.server; +in { + impermanence.directories = [ + { directory = config.mailserver.dkimKeyDirectory; user = "opendkim"; group = "opendkim"; mode = "0755"; } + { directory = config.mailserver.mailDirectory; user = "virtualMail"; group = "virtualMail"; mode = "0700"; } + ]; + + # roundcube + # TODO: fix sending mail via roundcube + services.nginx.virtualHosts."mail.${cfg.domainName}" = { + enableACME = true; + }; + services.roundcube = { + enable = true; + package = pkgs.roundcube.withPlugins (plugins: [ plugins.persistent_login ]); + dicts = with pkgs.aspellDicts; [ en ru ]; + hostName = "mail.${cfg.domainName}"; + maxAttachmentSize = 100; + plugins = [ "persistent_login" ]; + }; + mailserver = { + enable = true; + fqdn = "mail.${cfg.domainName}"; + domains = [ cfg.domainName ]; + certificateScheme = 1; + certificateFile = config.security.acme.certs."mail.${cfg.domainName}".directory + "/fullchain.pem"; + keyFile = config.security.acme.certs."mail.${cfg.domainName}".directory + "/key.pem"; + localDnsResolver = false; + recipientDelimiter = "-"; + lmtpSaveToDetailMailbox = "no"; + hierarchySeparator = "/"; + }; + + # Only allow local connections to noreply account + mailserver.loginAccounts."noreply@${cfg.domainName}" = { + # password is set in private.nix + hashedPassword = cfg.hashedNoreplyPassword; + sendOnly = true; + }; + services.dovecot2.extraConfig = + let + passwd = builtins.toFile "dovecot2-local-passwd" '' + noreply@${cfg.domainName}:{plain}${cfg.unhashedNoreplyPassword}::::::allow_nets=local,127.0.0.0/8,::1 + ''; + in '' + passdb { + driver = passwd-file + args = ${passwd} + } + ''; +} diff --git a/system/hosts/nixserver/matrix.nix b/system/hosts/nixserver/matrix.nix index 697b604..029db3e 100644 --- a/system/hosts/nixserver/matrix.nix +++ b/system/hosts/nixserver/matrix.nix @@ -39,7 +39,7 @@ in { locations = { "= /.well-known/matrix/server".extraConfig = matrixServerConfigResponse; "= /.well-known/matrix/client".extraConfig = matrixClientConfigResponse; - "/".proxyPass = "http://${lib.quotePotentialIpV6 matrixAddr}:${toString matrixPort}"; + "/".proxyPass = "http://${lib.quoteListenAddr matrixAddr}:${toString matrixPort}"; }; }; @@ -47,7 +47,7 @@ in { systemd.services.heisenbridge.after = [ "matrix-synapse.service" ]; services.heisenbridge = { enable = true; - homeserver = "http://${lib.quotePotentialIpV6 matrixAddr}:${toString matrixPort}/"; + homeserver = "http://${lib.quoteListenAddr matrixAddr}:${toString matrixPort}/"; }; # so synapse can read the registration users.groups.heisenbridge.members = [ "matrix-synapse" ]; diff --git a/system/hosts/nixserver/maubot.nix b/system/hosts/nixserver/maubot.nix index 1a141f6..5816785 100644 --- a/system/hosts/nixserver/maubot.nix +++ b/system/hosts/nixserver/maubot.nix @@ -9,9 +9,12 @@ let maubotAddr = "127.0.0.1"; maubotPort = 29316; in { + impermanence.directories = [ + { directory = /var/lib/maubot; user = "maubot"; group = "maubot"; mode = "0755"; } + ]; services.nginx.virtualHosts."matrix.${cfg.domainName}".locations = { "/_matrix/maubot/" = { - proxyPass = "http://${lib.quotePotentialIpV6 maubotAddr}:${toString maubotPort}"; + proxyPass = "http://${lib.quoteListenAddr maubotAddr}:${toString maubotPort}"; proxyWebsockets = true; }; }; diff --git a/system/hosts/nixserver/mumble.nix b/system/hosts/nixserver/mumble.nix index bc6b45b..b017c32 100644 --- a/system/hosts/nixserver/mumble.nix +++ b/system/hosts/nixserver/mumble.nix @@ -33,7 +33,7 @@ in { forceSSL = true; globalRedirect = cfg.domainName; locations."/music".extraConfig = "return 301 https://mumble.${cfg.domainName}/music/;"; - locations."/music/".proxyPass = "http://${lib.quotePotentialIpV6 settings.webinterface.listening_addr}:${toString settings.webinterface.listening_port}/"; + locations."/music/".proxyPass = "http://${lib.quoteListenAddr settings.webinterface.listening_addr}:${toString settings.webinterface.listening_port}/"; }; services.botamusique = { diff --git a/system/hosts/nixserver/options.nix b/system/hosts/nixserver/options.nix index 11d3875..d7fc0e3 100644 --- a/system/hosts/nixserver/options.nix +++ b/system/hosts/nixserver/options.nix @@ -12,7 +12,7 @@ lanCidrV4 = mkOption { type = types.str; description = "LAN mask (IPv4)"; - example = "192.168.1.0/96"; + example = "192.168.1.0/24"; default = "0.0.0.0/0"; }; lanCidrV6 = mkOption { @@ -33,19 +33,14 @@ example = "fd01:abcd::2"; default = null; }; - noreplyPassword = mkOption { - type = types.str; - description = "noreply (only available via localhost) account password"; - default = "totallysafe"; - }; hashedNoreplyPassword = mkOption { type = types.str; - description = "hashed noreply password via mkpasswd -sm bcrypt"; + description = "hashed noreply password via mkpasswd -sm bcrypt for external access"; }; unhashedNoreplyPassword = mkOption { type = types.str; - description = "unhashed noreply password. \ - This should preferably be different from the password that is hashed for better security (yes, really)"; + description = "unhashed noreply password for internal access only. \ + This should be different from the password that is hashed for better security"; }; pizzabotMagic = mkOption { type = types.str; diff --git a/system/modules/common.nix b/system/modules/common.nix index 5712d16..1a88092 100644 --- a/system/modules/common.nix +++ b/system/modules/common.nix @@ -10,7 +10,7 @@ workstation = mkOption { type = types.bool; default = false; - description = "whether this device is a workstation (meaning a device for personal use rather than a server)"; + description = "whether this device is a workstation (meaning a device for personal use rather than a server/embedded device)"; }; mainUsername = mkOption { type = types.str;