{ 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"; }; }; myDomains = [ "dirty-haskell.org" "www.dirty-haskell.org" "lists.dirty-haskell.org" "l.dirty-haskell.org" "ftp.141.li" "files.141.li" "f.141.li" "ymir.141.li" "141.li" "www.141.li" "lists.141.li" "l.141.li" "bragi.141.li" "ymir.xmpp.li" "xmpp.li" "www.xmpp.li" "lists.xmpp.li" "l.xmpp.li" "muc.xmpp.li" "proxy.xmpp.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" "bragi.yggdrasil.li" "ftp.praseodym.org" "files.praseodym.org" "f.praseodym.org" "ymir.praseodym.org" "praseodym.org" "www.praseodym.org" "lists.praseodym.org" "l.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 = [ ./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 ]; boot.loader.grub = { enable = true; version = 2; device = "/dev/vda"; }; 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.config.packageOverrides = pkgs: rec { vsftpd = pkgs.vsftpd.override { sslEnable = true; }; prosody = pkgs.callPackage ./customized/prosody.nix ({ inherit (pkgs.lua51Packages) luasocket luaexpat luafilesystem luabitop luaevent luazlib luasec; lua5 = pkgs.lua5_1; communityModules = ["mod_carbons" "mod_reload_modules" "mod_csi" "mod_cloud_notify" "mod_csi_pump" "mod_smacks" "mod_track_muc_joins" "mod_watchuntrusted"]; extraModules = [prosodyAuth]; extraLibs = [luaPam luaPosix luaSha2]; }); 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 = pkgs.stdenv.lib.overrideDerivation pkgs.cgit (oldAttrs : { buildInputs = oldAttrs.buildInputs ++ [ pkgs.perl pkgs.python3 pkgs.makeWrapper ]; postInstall = let pythonEnv = pkgs.python3.buildEnv.override { extraLibs = with pkgs.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 ':' ${pkgs.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 ':' ${pkgs.groff}/bin ''; }); push2bin = pkgs.writeScriptBin "push2bin" '' #!${pkgs.zsh}/bin/zsh PATH=${pkgs.coreutils}/bin:${pkgs.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 = pkgs.stdenv.mkDerivation rec { name = "pam-pwdfile-${version}"; version = "1.0"; src = pkgs.fetchFromGitHub { owner = "tiwe-de"; repo = "libpam-pwdfile"; rev = "v${version}"; sha256 = "0sjzwsnlf1g0xbingmjvb9gh8lnwzkkfzw10194ibnppdn4gy0zy"; }; buildInputs = with pkgs; [ pam ]; installFlags = [ "DESTDIR=$(out)" ]; }; }; environment.systemPackages = with pkgs; [ git mosh rsync tmux zsh mlmmj ]; 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 64738 # murmur 53 # DNS 6523 # Obby ]; allowedUDPPorts = [ 64738 # murmur 53 # DNS ]; allowedTCPPortRanges = [ { from = 20000; to = 21000; } # ftp ]; allowedUDPPortRanges = [ { from = 60000; to = 61000; } # mosh ]; }; enableIPv6 = true; interfaces."ens3" = { useDHCP = true; ipv6.addresses = [ { ipv6Address = "2a03:4000:6:d004::"; ipv6PrefixLength = 64; } ]; }; 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; }; services.ntp = { enable = false; }; # List services that you want to enable: services.openssh = { enable = true; passwordAuthentication = false; challengeResponseAuthentication = false; extraConfig = '' AllowGroups ssh ''; }; 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.timesyncd = { enable = true; }; services.journald = { rateLimitBurst = 0; }; services.prosody = { enable = true; admins = [ "gkleen@xmpp.li" "gkleen@praseodym.org" "gkleen@141.li" "gkleen@yggdrasil.li" ]; allowRegistration = false; extraModules = [ "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" log = { { levels = { min = "info" }, to = "console" } } Component "alias.xmpp.li" Include "/etc/prosody/alias.xmpp.li.cfg.lua" Component "muc.xmpp.li" "muc" restrict_room_creation = true max_history_messages = 100 name = "Multi-user chats" 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"]); }; 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; } ]; }; }; services.customTinc.networks = ((import ./custom/tinc/laeradhr.nix) { inherit (pkgs) stdenv nettools openresolv; name = "ymir"; connect = false; useDNS = false; ipConf = { ipv4.addresses = [ { address = "10.142.0.3"; prefixLength = 16; } ]; }; }); 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"; }; }; }; }; 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=/srv/git/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=/srv/git/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 = "/etc/ssl/dhparam.pem"; smtpd_tls_dh512_param_file = "/etc/ssl/dhparam.pem"; #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" '' /@(lists?|l)\./ mlmmj: /@subs?\.(lists?|l)\./ mlmmj-subs: ''} 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" ''check_client_access regexp:${pkgs.writeText "spfpolicy" '' /(^|\.)tu-muenchen\.de$/ DUNNO /(^|\.)tum\.de$/ DUNNO /(^|\.)lmu\.de$/ DUNNO /(^|\.)uni-muenchen\.de$/ DUNNO /(^|\.)lrz\.de$/ DUNNO /(^|\.)badw-muenchen\.de$/ DUNNO /(^|\.)badw\.de$/ DUNNO /(^|\.)hm\.edu$/ DUNNO /(^|\.)hswt\.de$/ DUNNO /(^|\.)mhn\.de$/ DUNNO /(^|\.)mwn\.de$/ DUNNO /(^|\.)boulderwelt\.de$/ DUNNO /.*/ spfcheck ''}'' ]; smtpd_restriction_classes = "spfcheck"; spfcheck = "check_policy_service unix:private/policy-spf"; smtpd_relay_restrictions = [ "permit_mynetworks" "permit_sasl_authenticated" "reject_unauth_destination" ]; mlmmj_destination_recipient_limit = "1"; mlmmj-subs_destination_recipient_limit = "1"; policy-spf_time_limit = "3600s"; propagate_unmatched_extensions = ["canonical" "virtual" "alias"]; milter_default_action = "accept"; milter_protocol = "2"; smtpd_milters = "local:private/dkim"; non_smtpd_milters = "local:private/dkim"; 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"]; }; 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=ORhu" "user=mlmmj" ''argv=${pkgs.mlmmj}/bin/mlmmj-receive -F -L /srv/mail/lists/''${user}'' ]; }; 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}'' ]; }; policy-spf = { type = "unix"; private = true; privileged = true; chroot = false; command = "spawn"; args = [ "user=nobody" ''argv=${pkgs.pypolicyd-spf}/bin/policyd-spf ${./ymir/spf.conf}'' ]; }; }; 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.postgrey = { enable = false; socket = { path = "/var/lib/postfix/queue/private/policy-greylist"; mode = "0777"; }; delay = 60; autoWhitelist = 1; maxAge = 7; retryWindow = 1; }; 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"; 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 } } 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 } ''; }; 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; home = "/srv/mail/lists"; createHome = 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 = { certs = { "yggdrasil.li" = { allowKeysForGroup = true; group = "ssl"; webroot = "/srv/www/acme/yggdrasil.li"; email = "phikeebaogobaegh@141.li"; extraDomains = builtins.listToAttrs (builtins.map (name: { inherit name; value = "/srv/www/acme/${name}"; }) myDomains); activationDelay = "6h"; postDelay = '' systemctl reload nginx.service ${pkgs.prosody}/bin/prosodyctl reload ''; }; }; }; systemd.services."acme-yggdrasil.li".requires = [ "nginx.service" ]; services.uucp = { enable = true; nodeName = "ymir"; remoteNodes = ["isaac" "hel"]; # legacy name for odin sshUser = { openssh.authorizedKeys.keys = [ ''restrict,command="${config.security.wrapperDir}/uucico" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEgtDHA7oDIaRwggGGznNaKZF68rFTziqefSCn1t9ZKe uucp@odin'' ''restrict,command="${config.security.wrapperDir}/uucico" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOWBybBQKbPucqBgULQ1phv7IKFWl1Xc4drkCx3D5mIz uucp@hel'' ]; }; sshConfig = '' Host isaac Hostname odin.asgard.yggdrasil IdentityFile ~/.ssh/odin Host hel Hostname hel.midgard.yggdrasil IdentityFile ~/.ssh/hel ''; commandPath = ["${pkgs.rmail}/bin" "${pkgs.push2bin}/bin"]; defaultCommands = ["rmail" "push2bin"]; }; 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.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 ''} ''; }; users.extraUsers."infinoted" = { home = "/var/lib/infinoted"; createHome = 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 ''; }; 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"; }; }