{ config, pkgs, lib, ... }: with lib; let luaPam = pkgs.callPackage ./custom/luaPam.nix {}; luaPosix = pkgs.callPackage ./custom/luaPosix.nix {}; luaSha2 = pkgs.callPackage ./custom/luaSha2.nix {}; prosodyAuth = pkgs.callPackage ./custom/prosody-auth.nix {}; prosodyVirtHost = name: { enabled = true; domain = name; ssl = { key = "/var/lib/acme/yggdrasil.li/key.pem"; cert = "/var/lib/acme/yggdrasil.li/fullchain.pem"; extraOptions = { dhparam = config.security.dhparams.params.prosody.path; }; }; }; myDomains = [ "dirty-haskell.org" "www.dirty-haskell.org" "lists.dirty-haskell.org" "l.dirty-haskell.org" "online.141.li" "o.141.li" "ftp.141.li" "files.141.li" "f.141.li" "ymir.141.li" "141.li" "www.141.li" "lists.141.li" "l.141.li" "rpg.141.li" "odin.141.li" "ymir.xmpp.li" "xmpp.li" "www.xmpp.li" "lists.xmpp.li" "l.xmpp.li" "muc.xmpp.li" "proxy.xmpp.li" "upload.xmpp.li" "online.yggdrasil.li" "o.yggdrasil.li" "ftp.yggdrasil.li" "files.yggdrasil.li" "f.yggdrasil.li" "ymir.yggdrasil.li" "git.yggdrasil.li" "www.yggdrasil.li" "yggdrasil.li" "lists.yggdrasil.li" "l.yggdrasil.li" "rpg.yggdrasil.li" "odin.yggdrasil.li" "online.praseodym.org" "o.praseodym.org" "ftp.praseodym.org" "files.praseodym.org" "f.praseodym.org" "ymir.praseodym.org" "praseodym.org" "www.praseodym.org" "lists.praseodym.org" "l.praseodym.org" "rpg.praseodym.org" "git.rheperire.org" "api.rheperire.org" "www.rheperire.org" "rheperire.org" "ymir.kleen.li" "kleen.li" "www.kleen.li" "ymir.nights.email" "nights.email" "www.nights.email" ]; dnsZoneDir = ./ymir/zones; dnsZones = listToAttrs (flatten (mapAttrsToList dnsZone (builtins.readDir dnsZoneDir))); dnsZone = fName: type: optional (type == "regular" || type == "symlink") (nameValuePair (dnsZoneName fName) { data = readFile (dnsZoneDir + ("/" + fName)); }); dnsZoneName = fName: concatStringsSep "." (reverseList (splitString "." (removeSuffix ".soa" fName))); in rec { imports = [ ./nixpkgs.nix ./ymir/hw.nix ./ymir/mlmmj-expose.nix ./custom/zsh.nix ./users.nix ./custom/tinc/def.nix ./custom/tinc/yggdrasil.nix ./custom/ymir-nginx.nix ./custom/uucp.nix ./custom/unit-status-mail.nix ./utils/nix/module.nix ]; boot.loader.grub = { enable = true; version = 2; device = "/dev/vda"; }; boot.tmpOnTmpfs = true; boot.kernel.sysctl = { "net.ipv4.tcp_keepalive_time" = 60; "net.ipv4.tcp_keepalive_intvl" = 10; "net.ipv4.tcp_keepalive_probes" = 6; }; nixpkgs.config.allowUnfree = true; nixpkgs.overlays = [ (self: super: { prosody = self.callPackage ./customized/prosody.nix ({ inherit (self.lua51Packages) luasocket luaexpat luafilesystem luabitop luaevent luasec luadbi; lua5 = pkgs.lua5_1; withCommunityModules = ["carbons" "reload_modules" "csi" "cloud_notify" "csi_pump" "smacks" "track_muc_joins" "watchuntrusted"]; extraModules = [prosodyAuth]; extraLibs = [luaPam luaPosix luaSha2] ++ (with self.lua51Packages; [lua-zlib]); }); # uwsgi = pkgs.callPackage ./customized/uwsgi.nix { # extraPlugins = { # cgi = { # name = "cgi"; # interpreter = pkgs.python3.interpreter; # path = "plugins/cgi"; # inputs = [ pkgs.python3 ]; # install = '' # ${pkgs.python3.executable} -m compileall $out/${pkgs.python3.sitePackages}/ # ${pkgs.python3.executable} -O -m compileall $out/${pkgs.python3.sitePackages}/ # ''; # }; # }; # plugins = []; # }; cgit = super.stdenv.lib.overrideDerivation super.cgit (oldAttrs : { buildInputs = oldAttrs.buildInputs ++ [ self.perl self.python3 self.makeWrapper ]; postInstall = let pythonEnv = self.python3.buildEnv.override { extraLibs = with self.python3Packages; [ pygments markdown ]; }; in '' wrapProgram $out/lib/cgit/filters/syntax-highlighting.py --prefix PYTHONPATH ':' ${pythonEnv}/lib/*/site-packages wrapProgram $out/lib/cgit/filters/about-formatting.sh --prefix PATH ':' ${self.coreutils}/bin tmpFile=$(mktemp) chmod +x $tmpFile echo "#!${pythonEnv}/bin/python3" >$tmpFile tail -n +2 $out/lib/cgit/filters/html-converters/md2html >>$tmpFile mv -v $tmpFile $out/lib/cgit/filters/html-converters/md2html wrapProgram $out/lib/cgit/filters/html-converters/md2html --prefix PYTHONPATH ':' ${pythonEnv}/lib/*/site-packages wrapProgram $out/lib/cgit/filters/html-converters/man2html --prefix PATH ':' ${self.groff}/bin ''; }); push2bin = super.writeScriptBin "push2bin" '' #!${self.zsh}/bin/zsh PATH=${self.coreutils}/bin:${self.gawk}/bin baseDir=/srv/www/files baseUrl="https://f.141.li" tmpFile=$(mktemp "''${baseDir}/.upload.XXXXXXXXXX") function zshexit() { [[ -n "''${tmpFile}" && -e "''${tmpFile}" ]] && rm -f "''${tmpFile}" } prefix=$(tee "''${tmpFile}" | sha512sum | awk '{ print $1; }' | head -c 10) prefix=''${prefix:l} filename="$1" [[ -z "''${prefix}" || -z "''${filename}" ]] && exit 2 [[ ! -f "''${tmpFile}" || $(stat -c '%s' "''${tmpFile}") == "0" ]] && exit 3 mkdir -p "''${baseDir}/''${prefix}" mv "''${tmpFile}" "''${baseDir}/''${prefix}/''${filename}" chmod 755 "''${baseDir}/''${prefix}" chmod 644 "''${baseDir}/''${prefix}/''${filename}" printf "%s/%s/%s" "''${baseUrl}" "''${prefix}" "''${filename}" ''; pam_pwdfile = super.stdenv.mkDerivation rec { name = "pam-pwdfile-${version}"; version = "1.0"; src = super.fetchFromGitHub { owner = "tiwe-de"; repo = "libpam-pwdfile"; rev = "v${version}"; sha256 = "0sjzwsnlf1g0xbingmjvb9gh8lnwzkkfzw10194ibnppdn4gy0zy"; }; buildInputs = with self; [ pam ]; installFlags = [ "DESTDIR=$(out)" ]; }; }) ]; environment.systemPackages = with pkgs; [ git mosh rsync tmux zsh mlmmj rebuild-system ]; networking = { hostName = "ymir"; hostId = "1c5c994e"; firewall = { enable = true; allowPing = true; allowedTCPPorts = [ 21 # ftp 22 # ssh 25 # smtp 143 # imap 993 # imaps 5000 # xmpp proxy 5222 # xmpp.s2c 5269 # xmpp.s2s 655 # tinc.yggdrasil 656 # tinc.laeradhr 80 # http 443 # https 9418 # git 53 # DNS 6523 # Obby 4190 # Managesieve ]; allowedUDPPorts = [ 53 # DNS ]; allowedTCPPortRanges = [ { from = 20000; to = 21000; } # ftp ]; allowedUDPPortRanges = [ { from = 60000; to = 61000; } # mosh ]; interfaces.yggdrasil.allowedTCPPorts = [ 11332 # rspamd ]; }; enableIPv6 = true; interfaces."ens3" = { useDHCP = true; ipv6.addresses = [ { address = "2a03:4000:6:d004::"; prefixLength = 64; } ]; }; resolvconf.dnsExtensionMechanism = true; nameservers = [ "::1" "127.0.0.1" "10.141.1.1" "8.8.8.8" "8.8.4.4" ]; domain = "niflheim.yggdrasil"; search = [ "niflheim.yggdrasil" "yggdrasil" "asgard.yggdrasil" ]; }; users.extraUsers.root = let template = (import users/gkleen.nix); in { inherit (template) shell; openssh.authorizedKeys.keyFiles = template.openssh.authorizedKeys.keyFiles; }; # List services that you want to enable: services.openssh = { enable = true; passwordAuthentication = false; challengeResponseAuthentication = false; extraConfig = '' AllowGroups ssh ''; knownHosts = import ./knownHosts.nix; }; users.groups."ssh" = { members = ["gitolite" "uucp" "root"]; }; services.fcron = { enable = true; systab = '' %weekly,erroronlymail * * nix-collect-garbage --delete-older-than '7d' ''; }; users.groups."ssl" = { members = [ "prosody" "nginx" "postfix" "murmur" "infinoted" ]; }; services.journald = { rateLimitBurst = 0; extraConfig = '' SystemMaxUse=100M ''; }; services.prosody = { enable = true; admins = [ "gkleen@xmpp.li" "gkleen@praseodym.org" "gkleen@141.li" "gkleen@yggdrasil.li" ]; allowRegistration = false; extraModules = [ "posix" "private" "auth_custom" "carbons" "reload_modules" "smacks" "csi" "csi_pump" "cloud_notify" "pep" "disco" "admin_adhoc" "watchuntrusted" ]; extraConfig = '' reload_modules = { "group", "tls" } authentication="custom" custom_alias_file="/etc/prosody/aliases" custom_alias_secret_file="/etc/prosody/alias_secret" Component "alias.xmpp.li" Include "/etc/prosody/alias.xmpp.li.cfg.lua" Component "proxy.xmpp.li" "proxy65" proxy65_acl = {"xmpp.li", "yggdrasil.li", "praseodym.org", "141.li", "nights.email"}; ''; virtualHosts = builtins.listToAttrs (map (name: { inherit name; value = prosodyVirtHost name; }) ["xmpp.li" "yggdrasil.li" "praseodym.org" "141.li" "nights.email"]); uploadHttp = { domain = "upload.xmpp.li"; uploadFileSizeLimit = 1024 * 1024 * 1024; userQuota = 1024 * 1024 * 1024; }; muc = [ { domain = "muc.xmpp.li"; name = "Multi-User Chats"; restrictRoomCreation = true; maxHistoryMessages = 250; } ]; }; security.pam.services."xmpp".text = '' auth requisite pam_succeed_if.so user ingroup xmpp auth required pam_unix.so audit ''; users.groups."shadow" = { members = [ "prosody" ]; }; users.groups."xmpp" = {}; system.activationScripts."shadow-perms" = '' chown root:shadow /etc/shadow chmod 0640 /etc/shadow ''; services.yggdrasilTinc = { enable = true; connect = false; useDNS = false; interfaceConfig = { ipv4 = { addresses = [ { address = "10.141.5.1"; prefixLength = 16; } ]; routes = [ { address = "10.141.1.0"; prefixLength = 24; via = "10.141.1.1"; } ]; }; macAddress = "2e:1b:73:b2:49:6d"; }; }; users.extraUsers."nginx".extraGroups = ["uwsgi"]; services.uwsgi = { enable = true; plugins = ["python3" "cgi"]; instance = { type = "emperor"; uid = "root"; gid = "root"; vassals = { "git.yggdrasil.li" = { type = "normal"; processes = 1; threads = 8; chdir = "${pkgs.cgit}/cgit"; cgi = "${pkgs.cgit}/cgit/cgit.cgi"; env = [ "CGIT_CONFIG=/etc/cgit/git.yggdrasil.li" ]; socket = "/tmp/git.yggdrasil.li.sock"; chmod-socket = "660"; chown-socket = "uwsgi:nginx"; uid = "uwsgi"; gid = "uwsgi"; }; "git.rheperire.org" = { type = "normal"; processes = 1; threads = 8; chdir = "${pkgs.cgit}/cgit"; cgi = "${pkgs.cgit}/cgit/cgit.cgi"; env = [ "CGIT_CONFIG=/etc/cgit/git.rheperire.org" ]; socket = "/tmp/git.rheperire.org.sock"; chmod-socket = "660"; chown-socket = "uwsgi:nginx"; uid = "uwsgi"; gid = "uwsgi"; }; }; }; }; systemd.services."uwsgi" = { wantedBy = [ "nginx.service" ]; before = [ "nginx.service" ]; }; users.extraUsers."uwsgi".extraGroups = ["gitolite"]; environment.etc."cgit/git.yggdrasil.li" = { enable = true; text = '' robots=noindex, nofollow virtual-root=/ enable-git-config=1 remove-suffix=1 root-title=git.yggdrasil.li root-desc= enable-http-clone=1 enable-commit-graph=1 snapshots=tar tar.gz tar.bz2 tar.xz zip side-by-side-diffs=1 source-filter=${pkgs.cgit}/lib/cgit/filters/syntax-highlighting.py about-filter=${pkgs.cgit}/lib/cgit/filters/about-formatting.sh readme=:README.md readme=:README.txt readme=:README readme=:readme.md readme=:readme.txt readme=:readme clone-prefix=git://git.yggdrasil.li https://git.yggdrasil.li strict-export=git-daemon-export-ok section-from-path=2 scan-path=${config.services.gitolite.dataDir}/repositories ''; }; environment.etc."cgit/git.rheperire.org" = { enable = true; text = '' robots=noindex, nofollow virtual-root=/ enable-git-config=1 remove-suffix=1 root-title=git.rheperire.org root-desc= enable-http-clone=1 enable-commit-graph=1 snapshots=tar tar.gz tar.bz2 tar.xz zip side-by-side-diffs=1 source-filter=${pkgs.cgit}/lib/cgit/filters/syntax-highlighting.py about-filter=${pkgs.cgit}/lib/cgit/filters/about-formatting.sh readme=:README.md readme=:README.txt readme=:README readme=:readme.md readme=:readme.txt readme=:readme clone-prefix=git://git.rheperire.org https://git.rheperire.org strict-export=git-daemon-export-ok project-list=${pkgs.writeText "project-list" '' rheperire.git cryptoids.git ''} section-from-path=2 scan-path=${config.services.gitolite.dataDir}/repositories ''; }; services.gitolite = { enable = true; adminPubkey = builtins.readFile (builtins.head (import ./users/gkleen.nix).openssh.authorizedKeys.keyFiles); dataDir = "/srv/git"; user = "gitolite"; extraGitoliteRc = '' $RC{UMASK} = 0027; $RC{GIT_CONFIG_KEYS} = 'gitweb\.(owner|description|category)'; $RC{LOG_DEST} = 'syslog'; $RC{ROLES}{AUTHORS} = 1; $RC{GROUPLIST_PGM} = 'printf "@self-key-managers"'; $RC{HOSTNAME} = '${networking.hostName}'; $RC{LOCAL_CODE} = "$rc{GL_ADMIN_BASE}/local"; push(@{$RC{ENABLE}}, qw(create fork D cgit repo-specific-hooks macros)); ''; }; services.gitDaemon = { enable = true; basePath = services.gitolite.dataDir + "/repositories"; user = "gitolite"; group = "gitolite"; }; services.postfix = { enable = true; hostname = "ymir.yggdrasil.li"; recipientDelimiter = "+"; setSendmail = true; postmasterAlias = ""; rootAlias = ""; extraAliases = ""; virtual = '' blog@dirty-haskell.org dirty-haskell@lists.yggdrasil.li @nights.email some@nights.email ''; #destination = ["yggdrasil.li" "ymir.yggdrasil.li" "praseodym.org" "ymir.praseodym.org" "141.li" "ymir.141.li" "xmpp.li" "ymir.xmpp.li" "dirty-haskell.org" "explainuxul.de" "www.explainuxul.de" "lmu.li" "www.lmu.li" "localhost.yggdrasil.li" "localhost"]; destination = [''regexp:${pkgs.writeText "destination" '' /\.?yggdrasil\.li$/ ACCEPT /\.?praseodym\.org$/ ACCEPT /\.?141\.li$/ ACCEPT /\.?xmpp\.li$/ ACCEPT /\.?kleen\.li$/ ACCEPT /\.?dirty-haskell\.org$/ ACCEPT /\.?nights\.email$/ ACCEPT /\.?yggdrasil$/ ACCEPT /\.?localdomain$/ ACCEPT /^localhost$/ ACCEPT /\.?ymir$/ ACCEPT ''}'']; sslCert = "/var/lib/acme/yggdrasil.li/fullchain.pem"; sslKey = "/var/lib/acme/yggdrasil.li/key.pem"; config = { #the dh params smtpd_tls_dh1024_param_file = config.security.dhparams.params."postfix-1024".path; smtpd_tls_dh512_param_file = config.security.dhparams.params."postfix-512".path; #enable ECDH smtpd_tls_eecdh_grade = "strong"; #enabled SSL protocols, don't allow SSLv2 and SSLv3 smtpd_tls_protocols = [ "!SSLv2" "!SSLv3"]; smtpd_tls_mandatory_protocols = ["!SSLv2" "!SSLv3"]; #allowed ciphers for smtpd_tls_security_level=encrypt smtpd_tls_mandatory_ciphers = "high"; #allowed ciphers for smtpd_tls_security_level=may #smtpd_tls_ciphers = high #enforce the server cipher preference tls_preempt_cipherlist = true; #disable following ciphers for smtpd_tls_security_level=encrypt smtpd_tls_mandatory_exclude_ciphers = ["aNULL" "MD5" "DES" "ADH" "RC4" "PSD" "SRP" "3DES" "eNULL"]; #disable following ciphers for smtpd_tls_security_level=may smtpd_tls_exclude_ciphers = ["aNULL" "MD5" "DES" "ADH" "RC4" "PSD" "SRP" "3DES" "eNULL"]; #enable TLS logging to see the ciphers for inbound connections smtpd_tls_loglevel = "1"; #enable TLS logging to see the ciphers for outbound connections smtp_tls_loglevel = "1"; smtp_dns_support_level = "dnssec"; smtp_tls_security_level = "dane"; transport_maps = ''regexp:${pkgs.writeText "transport" '' /@(rpgs?|lists?|l)\.(.*\.)?(yggdrasil\.li|praseodym\.org|141\.li|xmpp\.li|kleen\.li|dirty-haskell\.org|nights\.email|yggdrasil|localdomain|localhost|ymir)$/ mlmmj: /@subs?\.(rpgs?|lists?|l)\.(.*\.)?(yggdrasil\.li|praseodym\.org|141\.li|xmpp\.li|kleen\.li|dirty-haskell\.org|nights\.email|yggdrasil|localdomain|localhost|ymir)$/ mlmmj-subs: /@odin(\.asgard\.yggdrasil)?$/ uucp:odin ''} regexp:/srv/mail/transport pipemap:{texthash:/srv/mail/discard,static:{discard:}}''; local_recipient_maps = ""; luser_relay = ''gkleen+''${local}''; # 10 GiB message_size_limit = "10737418240"; # 10 GiB mailbox_size_limit = "10737418240"; mailbox_transport_maps = "pipemap:{unix:passwd.byname, static:{lmtp:unix:private/dovecot-lmtp}}"; #mailbox_command = ${pkgs.dovecot}/libexec/dovecot/dovecot-lda -f "$SENDER" -a "$RECIPIENT" smtpd_sasl_type = "dovecot"; smtpd_sasl_path = "private/dovecot-auth"; smtpd_sasl_auth_enable = true; smtpd_sasl_security_options = ["noanonymous" "noplaintext"]; smtpd_sasl_tls_security_options = "noanonymous"; smtpd_tls_auth_only = true; smtpd_delay_reject = true; smtpd_helo_required = true; smtpd_helo_restrictions = "permit"; smtpd_recipient_restrictions = [ "reject_unauth_pipelining" "reject_non_fqdn_recipient" "reject_unknown_recipient_domain" "permit_mynetworks" "permit_sasl_authenticated" "reject_non_fqdn_helo_hostname" "reject_invalid_helo_hostname" "reject_unauth_destination" ]; smtpd_relay_restrictions = [ "permit_mynetworks" "permit_sasl_authenticated" "reject_unauth_destination" ]; mlmmj_destination_recipient_limit = "1"; mlmmj-subs_destination_recipient_limit = "1"; propagate_unmatched_extensions = ["canonical" "virtual" "alias"]; smtpd_authorized_verp_clients = "$authorized_verp_clients"; authorized_verp_clients = "$mynetworks"; milter_default_action = "accept"; smtpd_milters = ["local:private/dkim" "local:private/rspamd"]; non_smtpd_milters = ["local:private/dkim" "local:private/rspamd"]; alias_maps = ''texthash:${pkgs.writeText "aliases" '' postmaster gkleen webmaster gkleen abuse gkleen noc gkleen security gkleen hostmaster gkleen usenet gkleen news gkleen www gkleen uucp gkleen ftp gkleen root gkleen ''} texthash:/srv/mail/spm ''; queue_run_delay = "10s"; minimal_backoff_time = "1m"; maximal_backoff_time = "10m"; maximal_queue_lifetime = "100m"; bounce_queue_lifetime = "20m"; sender_canonical_maps = "tcp:localhost:10001"; sender_canonical_classes = "envelope_sender"; recipient_canonical_maps = "tcp:localhost:10002"; recipient_canonical_classes = ["envelope_recipient" "header_recipient"]; smtpd_discard_ehlo_keyword_address_maps = "cidr:${pkgs.writeText "esmtp_access" '' # Allow DSN requests from local subnet only 192.168.0.0/16 silent-discard 172.16.0.0/12 silent-discard 10.0.0.0/8 silent-discard 0.0.0.0/0 silent-discard, dsn fd00::/8 silent-discard ::/0 silent-discard, dsn ''}"; }; masterConfig = { uucp = { type = "unix"; private = true; privileged = true; chroot = false; command = "pipe"; args = [ "flags=Fqhu" "user=uucp" ''argv=${config.security.wrapperDir}/uux -z -a $sender - $nexthop!rmail ($recipient)'' ]; }; mlmmj = { type = "unix"; private = true; privileged = true; chroot = false; command = "pipe"; args = [ "flags=XORhu" "user=mlmmj" ''argv=${pkgs.mlmmj}/bin/mlmmj-receive -F -L /srv/mail/lists/''${user} -s ''${sender} -e ''${extension}'' ]; }; mlmmj-subs = { type = "unix"; private = true; privileged = true; chroot = false; command = "pipe"; args = [ "flags=Fqhu" "user=mlmmj" ''argv=${pkgs.mlmmj-exposed}/bin/mlmmj-exposed /srv/mail/lists/''${user} ''${extension}'' ]; }; }; networks = ["127.0.0.0/8" "[::ffff:127.0.0.0]/104" "[::1]/128" "10.141.0.0/16"]; }; services.postsrsd = { enable = true; domain = "srs.141.li"; separator = "+"; excludeDomains = [ ".yggdrasil.li" "yggdrasil.li" ".praseodym.org" "praseodym.org" ".141.li" "141.li" ".xmpp.li" "xmpp.li" ".kleen.li" "kleen.li" ".nights.email" "nights.email" ".lmu.li" "lmu.li" ".dirty-haskell.org" "dirty-haskell.org" ]; }; systemd.timers."mlmmj-maintd" = { description = "run mlmmj maintenance daemon"; wantedBy = [ "multi-user.target" ]; timerConfig = { OnActiveSec = "10m"; OnUnitActiveSec = "10m"; }; }; systemd.services."mlmmj-maintd" = { description = "mlmmj maintenance daemon"; serviceConfig = { User = "mlmmj"; Group = "mlmmj"; ExecStart = "${pkgs.mlmmj}/bin/mlmmj-maintd -F -d /srv/mail/lists"; }; }; services.opendkim = { enable = true; user = "postfix"; group = "postfix"; socket = "local:/var/lib/postfix/queue/private/dkim"; domains = ''csl:${concatStringsSep "," myDomains}''; keyPath = "/var/lib/dkim/"; selector = "ymir"; configFile = builtins.toFile "opendkim.conf" '' Syslog true MTACommand ${config.security.wrapperDir}/sendmail LogResults true ''; }; services.dovecot2 = { enable = true; enableImap = true; enableLmtp = true; enablePop3 = false; enablePAM = false; # do that manualy sslServerCert = "/var/lib/acme/yggdrasil.li/fullchain.pem"; sslServerKey = "/var/lib/acme/yggdrasil.li/key.pem"; mailLocation = "maildir:~/mail:LAYOUT=index:UTF-8"; modules = with pkgs; [ dovecot_pigeonhole ]; protocols = [ "sieve" ]; extraConfig = '' userdb { driver = passwd } passdb { driver = pam args = dovecot2 result_success = continue-ok } passdb { driver = passwd-file args = /srv/mail/dovecot.passwd result_success = continue-ok } mail_plugins = $mail_plugins quota mailbox_list_index = yes postmaster_address = postmaster@yggdrasil.li recipient_delimiter = + auth_username_format = %n service auth { unix_listener /var/lib/postfix/queue/private/dovecot-auth { mode = 0600 user = postfix group = postfix } } service lmtp { unix_listener /var/lib/postfix/queue/private/dovecot-lmtp { mode = 0600 user = postfix group = postfix } } protocol lmtp { mail_plugins = $mail_plugins sieve } protocol lda { mail_plugins = $mail_plugins sieve } namespace inbox { separator = / inbox = yes prefix = } plugin { quota = maildir:User quota quota_rule = *:storage=1GB quota_rule2 = Trash:storage=+10%% quota_status_overquota = "552 5.2.2 Mailbox is full" quota_status_success = DUNNO quota_status_nouser = DUNNO quota_grace = 10%% } protocol imap { mail_max_userip_connections = 50 mail_plugins = $mail_plugins imap_quota } service managesieve-login { inet_listener sieve { port = 4190 } } plugin { sieve = file:~/sieve;active=~/.dovecot.sieve sieve_redirect_envelope_from = orig_recipient } ''; }; security.pam.services.dovecot2.text = '' auth requisite pam_succeed_if.so user ingroup mail auth required pam_unix.so audit account sufficient pam_unix.so ''; users.groups."mail" = {}; users.extraUsers."mlmmj" = { isSystemUser = true; group = "mlmmj"; extraGroups = [ "mail" ]; }; users.extraGroups."mlmmj" = {}; users.extraGroups."mladmin" = { members = [ "gkleen" ]; }; users.extraGroups."infinoted" = { members = [ "infinoted" "gitolite" ]; }; security.sudo.extraConfig = '' %mladmin ALL=(mlmmj) NOPASSWD: ALL %infinoted ALL=(infinoted) NOPASSWD: ALL ''; security.polkit = { enable = true; extraConfig = '' polkit.addRule(function(action, subject) { if ( action.id == "org.freedesktop.systemd1.manage-units" && action.lookup("unit") == "infinoted.service" && subject.isInGroup("infinoted") ) { return polkit.Result.YES; } }); ''; }; security.wrappers = { "newgrp".source = "${pkgs.shadow}/bin/newgrp"; }; security.acme = { acceptTerms = true; certs = { "yggdrasil.li" = { allowKeysForGroup = true; group = "ssl"; webroot = "/srv/www/acme"; email = "phikeebaogobaegh@141.li"; extraDomains = builtins.listToAttrs (builtins.map (name: { inherit name; value = null; }) myDomains); postRun = '' systemctl reload nginx.service dovecot2.service postfix.service prosody.service vsftpd.service infinoted.service ''; }; }; }; systemd.services."acme-yggdrasil.li".requires = [ "nginx.service" ]; systemd.tmpfiles.rules = let mkDir = domain: "d /srv/www/acme 0775 root ssl 10d -"; in map mkDir myDomains; services.uucp = { enable = true; nodeName = "ymir"; remoteNodes = { "odin" = { publicKeys = ["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKT/BsAMLJs9NYhKIso4J3EF+VzRBm3c+qCQ5ONKc/1s uucp@odin"]; hostnames = ["odin.asgard.yggdrasil"]; }; "hel" = { publicKeys = ["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOWBybBQKbPucqBgULQ1phv7IKFWl1Xc4drkCx3D5mIz uucp@hel"]; hostnames = ["hel.midgard.yggdrasil"]; }; "sif" = { publicKeys = ["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINDLcU8Qi+Ogu+jBSd4hJ5XO6HhRYs6/Y4mVAtTwdime root@sif"]; hostnames = ["sif.midgard.yggdrasil"]; }; }; commandPath = ["${pkgs.rmail}/bin" "${pkgs.push2bin}/bin" "${pkgs.rspamd}/bin"]; defaultCommands = ["rmail" "push2bin" "rspamc"]; }; services.atd = { enable = true; }; users.groups."filebin" = { members = ["gkleen" "uucp"]; }; services.nsd = { enable = true; verbosity = 3; interfaces = [ "10.142.0.3" "188.68.51.254" "2a03:4000:6:d004::" ]; ipTransparent = true; remoteControl = { enable = true; }; zones = { "inwx" = { notify = [ "217.70.142.96 NOKEY" "185.181.104.96 NOKEY" ]; provideXFR = [ "217.70.142.96 NOKEY" "185.181.104.96 NOKEY" ]; outgoingInterface = "188.68.51.254"; children = dnsZones; dnssec = true; dnssecPolicy = { coverage = "2mo"; }; }; }; }; services.unbound = { enable = true; allowedAccess = ["127.0.0.0/8" "::ffff:127.0.0.0/104" "::1/128" "10.141.0.0/16"]; interfaces = ["127.0.0.1" "::1" "10.141.5.1"]; extraConfig = '' verbosity: 1 private-domain: "yggdrasil" domain-insecure: "10.in-addr.arpa" domain-insecure: "yggdrasil" local-zone: "10.in-addr.arpa" nodefault forward-zone: name: "10.in-addr.arpa" forward-addr: 10.141.1.1 forward-zone: name: "yggdrasil" forward-addr: 10.141.1.1 ''; }; services.dhcpd4 = { enable = true; interfaces = [ "yggdrasil" ]; machines = [ { hostName = "hel"; ethernetAddress = "ee:10:15:9a:cc:1f"; ipAddress = "hel.midgard.yggdrasil"; } { hostName = "sif"; ethernetAddress = "5c:93:21:c3:61:39"; ipAddress = "sif.midgard.yggdrasil"; } ]; extraConfig = '' option rfc3442-classless-static-routes code 121 = array of integer 8; option ms-classless-static-routes code 249 = array of integer 8; subnet 10.141.0.0 netmask 255.255.0.0 { range 10.141.255.0 10.141.255.254; option rfc3442-classless-static-routes 24, 10, 141, 4, 10, 141, 1, 5, 24, 10, 141, 1, 10, 141, 1, 1, 24, 192, 168, 178, 10, 141, 1, 1; option ms-classless-static-routes 24, 10, 141, 4, 10, 141, 1, 5, 24, 10, 141, 1, 10, 141, 1, 1, 24, 192, 168, 178, 10, 141, 1, 1; option domain-name "yggdrasil"; option domain-name-servers 10.141.1.1, 8.8.8.8, 8.8.4.4, 192.168.178.1; } ''; }; services.infinoted = { enable = true; keyFile = "/var/lib/acme/yggdrasil.li/key.pem"; certificateFile = "/var/lib/acme/yggdrasil.li/fullchain.pem"; plugins = [ "note-text" "note-chat" "logging" "autosave" "certificate-auth" "directory-sync" ]; extraConfig = '' [certificate-auth] ca-list=/var/lib/infinoted/ca.cert.pem ca-key=/var/lib/infinoted/ca.key.pem accept-unauthenticated-clients=true [autosave] interval=5 [directory-sync] directory=/var/lib/infinoted/dirsync interval=5 hook=${pkgs.writeScript "git-sync.sh" '' #!${pkgs.zsh}/bin/zsh git -C ''${2:h} rev-parse --is-inside-work-tree &>/dev/null || exit 0 repository=$(git -C ''${2:h} rev-parse --show-toplevel) [[ $? -ne 0 ]] && exit $? git() { $(whence -cp git) -C ''${repository} ''${@} } typeset -a changeSet changeSet=() git diff -z --name-only | \ while IFS= read -r -d $'\0' change; do changeSet=(''${changeSet} ''${change}); done [[ ''${changeSet[(i)$(realpath ''${2} --relative-to=''${repository})]} -le ''${#changeSet} ]] || exit 0 commitMessage=$(printf "%s modified via infinoted" $(realpath ''${2} --relative-to=''${repository})) git add ''${2} git commit -m ''${commitMessage} --no-edit ''${2} git push ''} ''; }; systemd.services."infinoted".serviceConfig.ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; users.extraUsers."infinoted" = { isSystemUser = true; }; services.haveged = { enable = true; }; system.autoUpgrade.enable = true; system.stateVersion = "17.09"; systemd.services."nixos-upgrade".path = with pkgs; [ git ]; systemd.services."nixos-upgrade".preStart = '' git -C /etc/nixos pull git -C /etc/nixos submodule update ''; systemd.status-mail = { onFailure = [ "nixos-upgrade" "postfix" "dovecot2" "prosody" "opendkim" "nsd" "unbound" "tinc@yggdrasil" "postsrsd" ]; }; services.vsftpd = { enable = true; forceLocalLoginsSSL = true; forceLocalDataSSL = true; localUsers = true; writeEnable = true; chrootlocalUser = true; rsaKeyFile = "/var/lib/acme/yggdrasil.li/key.pem"; rsaCertFile = "/var/lib/acme/yggdrasil.li/fullchain.pem"; extraConfig = '' local_umask=022 log_ftp_protocol=NO xferlog_enable=YES pam_service_name=vsftpd port_enable=NO pasv_enable=YES pasv_max_port=21000 pasv_min_port=20000 allow_writeable_chroot=YES guest_enable=YES guest_username=vsftpd virtual_use_local_privs=YES user_sub_token=$USER local_root=/srv/ftp/$USER hide_ids=YES ''; }; systemd.services."vsftpd".serviceConfig.ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; security.pam.services."vsftpd".text = '' auth required ${pkgs.pam_pwdfile}/lib/security/pam_pwdfile.so pwdfile=/srv/ftp.htpasswd account required pam_permit.so ''; users.extraUsers."vsftpd" = { home = mkForce "/srv/ftp"; }; security.dhparams = { enable = true; params = { nginx.bits = 3072; "postfix-512".bits = 512; "postfix-1024".bits = 1024; "dovecot2".bits = 2048; prosody.bits = 3072; }; }; services.rspamd = { enable = true; workers = { controller = {}; external = { type = "rspamd_proxy"; bindSockets = [ { mode = "0660"; socket = "/var/lib/postfix/queue/private/rspamd"; owner = config.services.rspamd.user; group = config.services.postfix.group; } ]; extraConfig = '' milter = yes; upstream "local" { default = yes; self_scan = yes; } ''; }; internal = { type = "rspamd_proxy"; bindSockets = [ "ymir.niflheim.yggdrasil:11332" ]; extraConfig = '' milter = yes; upstream "local" { default = yes; self_scan = yes; settings_id = "internal"; } ''; }; }; locals = { "milter_headers.conf".text = '' use = ["authentication-results", "x-spamd-result", "x-rspamd-queue-id", "x-rspamd-server", "x-spam-level", "x-spam-status"]; extended_headers_rcpt = ["@odin.asgard.yggdrasil"]; ''; "actions.conf".text = '' reject = 15; add_header = 10; greylist = 5; ''; "groups.conf".text = '' symbols { "BAYES_SPAM" { weight = 2.0; } } ''; "dmarc.conf".text = '' reporting = true; send_reports = true; report_settings { org_name = "Yggdrasil.li"; domain = "yggdrasil.li"; email = "postmaster@yggdrasil.li"; } ''; "redis.conf".text = '' servers = "localhost"; ''; "dkim_signing.conf".text = "enabled = false;"; "neural.conf".text = "enabled = false;"; "classifier-bayes.conf".text = '' enable = true; expire = 8640000; new_schema = true; backend = "redis"; per_user = true; min_learns = 0; autolearn = [0, 10]; statfile { symbol = "BAYES_HAM"; spam = false; } statfile { symbol = "BAYES_SPAM"; spam = true; } ''; "settings.conf".text = '' internal { priority = high; apply { milter_headers { skip_local = false; skip_authenticated = false; authenticated_headers = ["authentication-results", "x-spamd-result", "x-rspamd-queue-id", "x-rspamd-server", "x-spam-level", "x-spam-status"]; } actions { reject = null; greylist = null; add_header = 10; } rules_disabled = ["FORGED_RECIPIENTS", "RCVD_NO_TLS_LAST"]; } } ''; "redirectors.inc".text = '' visit.creeper.host ''; }; }; systemd.services.rspamd = { requires = [ "redis.service" ]; bindsTo = [ "redis.service" ]; }; services.redis = { enable = true; vmOverCommit = true; bind = "127.0.0.1 ::1"; }; }