{ config, pkgs, ... }: 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" "files.141.li" "f.141.li" "ymir.141.li" "141.li" "www.141.li" "lists.141.li" "l.141.li" "files.lmu.li" "f.lmu.li" "ymir.lmu.li" "lmu.li" "www.lmu.li" "lists.lmu.li" "l.lmu.li" "ymir.xmpp.li" "xmpp.li" "www.xmpp.li" "lists.xmpp.li" "l.xmpp.li" "files.yggdrasil.li" "f.yggdrasil.li" "ymir.yggdrasil.li" "git.yggdrasil.li" "www.yggdrasil.li" "yggdrasil.li" "lists.yggdrasil.li" "l.yggdrasil.li" "files.praseodym.org" "f.praseodym.org" "ymir.praseodym.org" "praseodym.org" "www.praseodym.org" "lists.praseodym.org" "l.praseodym.org" ]; in rec { imports = [ ./ymir/hw.nix ./ymir/mlmmj-expose.nix ./custom/zsh.nix ./users.nix ./custom/tinc/def.nix ./custom/ymir-nginx.nix ./custom/uucp.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.packageOverrides = pkgs: rec { prosody = pkgs.callPackage ./customized/prosody.nix ({ inherit (pkgs.lua51Packages) luasocket luasec luaexpat luafilesystem luabitop luaevent luazlib; lua5 = pkgs.lua5_1; communityModules = ["mod_carbons" "mod_reload_modules"]; 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 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}" ''; }; environment.systemPackages = with pkgs; [ git mosh rsync tmux zsh mlmmj ]; networking = { hostName = "ymir"; hostId = "1c5c994e"; firewall = { enable = true; allowPing = true; allowedTCPPorts = [ 22 # ssh 25 # smtp 143 # imap 993 # imaps 5222 # xmpp.s2c 5269 # xmpp.s2s 655 # tinc.yggdrasil 656 # tinc.laeradhr 80 # http 443 # https 9418 # git 64738 # murmur ]; allowedUDPPorts = [ 64738 # murmur ]; allowedUDPPortRanges = [ { from = 60000; to = 61000; } # mosh ]; }; enableIPv6 = true; defaultGateway6 = "fe80::1"; interfaces."enp0s3" = { ipv6Address = "2a03:4000:6:d004::"; ipv6PrefixLength = 64; }; }; 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; 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" ]; }; services.timesyncd = { enable = true; }; 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" ]; 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" ''; virtualHosts = builtins.listToAttrs (map (name: { inherit name; value = prosodyVirtHost name; }) ["xmpp.li" "yggdrasil.li" "praseodym.org" "141.li"]); }; 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.customTinc.networks = ((import ./custom/tinc/yggdrasil.nix) { inherit (pkgs) stdenv nettools openresolv; name = "ymir"; connect = false; useDNS = true; ipConf = { ip4 = [ { address = "10.141.5.1"; prefixLength = 16; } ]; }; }) // ((import ./custom/tinc/laeradhr.nix) { inherit (pkgs) stdenv nettools openresolv; name = "ymir"; connect = false; useDNS = false; ipConf = { ip4 = [ { address = "10.142.0.3"; prefixLength = 16; } ]; }; }); users.extraUsers."nginx".extraGroups = ["uwsgi"]; services.uwsgi = { enable = true; plugins = ["python3" "cgi"]; instance = { type = "normal"; processes = 1; threads = 8; chdir = "${pkgs.cgit}/cgit"; cgi = "${pkgs.cgit}/cgit/cgit.cgi"; socket = "/tmp/cgit.sock"; chmod-socket = "660"; chown-socket = "uwsgi:nginx"; }; }; users.extraUsers."uwsgi".extraGroups = ["git"]; environment.etc."cgitrc" = { 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 http://git.yggdrasil.li strict-export=git-daemon-export-ok project-list=/srv/git/projects.list 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"; }; users.extraUsers."gitolite" = { group = "git"; }; services.gitDaemon = { enable = true; basePath = services.gitolite.dataDir + "/repositories"; }; services.postfix = { enable = true; hostname = "ymir.yggdrasil.li"; recipientDelimiter = "+"; setSendmail = true; postmasterAlias = ""; rootAlias = ""; extraAliases = ""; virtual = '' blog@dirty-haskell.org dirty-haskell@lists.yggdrasil.li ''; #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 /\.?dirty-haskell\.org$/ ACCEPT /\.?lmu\.li$/ 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"; extraConfig = '' #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 = yes #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:}} 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 = yes smtpd_sasl_security_options = noanonymous, noplaintext smtpd_sasl_tls_security_options = noanonymous smtpd_tls_auth_only = yes smtpd_delay_reject = yes smtpd_helo_required = yes 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_unknown_reverse_client_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 /.*/ 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 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 ''; extraMasterConf = '' uucp unix - n n - - pipe flags=Fqhu user=uucp argv=/var/setuid-wrappers/uux -z -a $sender - $nexthop!rmail ($recipient) mlmmj unix - n n - - pipe flags=ORhu user=mlmmj argv=${pkgs.mlmmj}/bin/mlmmj-receive -F -L /var/spool/lists/''${user} mlmmj-subs unix - n n - - pipe flags=ORhu user=mlmmj argv=${pkgs.mlmmj-exposed}/bin/mlmmj-exposed /var/spool/lists/''${user} ''${extension} policy-spf unix - n n - - spawn user=nobody argv=${pkgs.pythonPackages.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 = false; # domain = "141.li"; # separator = "+"; # excludeDomains = [ ".yggdrasil.li" "yggdrasil.li" # ".praseodym.org" "praseodym.org" # ".141.li" "141.li" # ".xmpp.li" "xmpp.li" # ".lmu.li" "lmu.li" # ".dirty-haskell.org" "dirty-haskell.org" # ]; # }; systemd.timers."mlmmj-maintd" = { description = "run mlmmj maintenance daemon"; wantedBy = [ "multi-user.target" ]; timerConfig = { OnStartupSec = "7200"; }; }; systemd.services."mlmmj-maintd" = { description = "mlmmj maintenance daemon"; serviceConfig = { User = "mlmmj"; Group = "mlmmj"; ExecStart = "${pkgs.mlmmj}/bin/mlmmj-maintd -F -d /var/spool/lists"; }; }; services.opendkim = { enable = true; user = "postfix"; group = "postfix"; socket = "local:/var/lib/postfix/queue/private/dkim"; domains = ''csl:${pkgs.lib.concatStringsSep "," myDomains}''; keyFile = /var/lib/dkim/ymir.private; selector = "ymir"; configFile = builtins.toFile "opendkim.conf" '' Syslog true MTACommand /var/setuid-wrappers/sendmail LogResults true ''; }; services.dovecot2 = { enable = true; enableImap = true; enableLmtp = true; enablePop3 = false; enablePAM = true; sslServerCert = "/var/lib/acme/yggdrasil.li/fullchain.pem"; sslServerKey = "/var/lib/acme/yggdrasil.li/key.pem"; mailLocation = "maildir:~/mail:LAYOUT=index:UTF-8"; extraConfig = '' 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 { separator = / inbox = yes } 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 } # service quota-status { # executable = quota-status -p postfix # unix_listener /var/lib/postfix/queue/private/policy-quota { # mode = 0660 # user = postfix # group = postfix # # You can choose any port you want # } # client_limit = 1 # } ''; }; 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 = "/var/spool/lists"; createHome = true; group = "mlmmj"; }; users.extraGroups."mlmmj" = {}; 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); postRun = '' systemctl reload nginx.service prosodyctl reload ''; }; }; }; services.uucp = { enable = true; nodeName = "ymir"; remoteNodes = ["isaac" "hel"]; # legacy name for odin sshUser = { openssh.authorizedKeys.keys = [ ''no-port-forwarding,no-X11-forwarding,no-agent-forwarding,command="/var/setuid-wrappers/uucico" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEgtDHA7oDIaRwggGGznNaKZF68rFTziqefSCn1t9ZKe uucp@odin'' ''no-port-forwarding,no-X11-forwarding,no-agent-forwarding,command="/var/setuid-wrappers/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"]; interval = "@mail(no) 1h"; }; services.atd = { enable = true; }; users.groups."filebin" = { members = ["gkleen" "uucp"]; }; }