diff --git a/Makefile b/Makefile
index aefd17147..5b898c54c 100644
--- a/Makefile
+++ b/Makefile
@@ -35,7 +35,7 @@ ifeq ($(filter),json)
 else
 	filter() { cat; }
 endif
-	nix-instantiate \
+	result=$$(nix-instantiate \
 		$${extraArgs-} \
 		--eval \
 		-A "$$get" \
@@ -45,8 +45,9 @@ endif
 		--argstr current-host-name "$$HOSTNAME" \
 		--argstr current-user-name "$$LOGNAME" \
 		$${system+--argstr system "$$system"} \
-		$${target+--argstr target "$$target"} \
-		| filter
+		$${target+--argstr target "$$target"})
+	echo "$$result" | filter
+
 else
 $(error unbound variable: system[s])
 endif
diff --git a/krebs/3modules/Reaktor.nix b/krebs/3modules/Reaktor.nix
index 1ec49b81e..92400139c 100644
--- a/krebs/3modules/Reaktor.nix
+++ b/krebs/3modules/Reaktor.nix
@@ -1,25 +1,15 @@
-{ config, pkgs,lib, ... }:
-
+{ config, lib, pkgs, ... }:
 
+with lib;
 let
 
-  inherit (lib)
-    mkIf
-    mkOption
-    types
-    singleton
-    isString
-    optionalString
-    concatStrings
-    escapeShellArg
-  ;
-
   ReaktorConfig = pkgs.writeText "config.py" ''
       ${if (isString cfg.overrideConfig ) then ''
       # Overriden Config
       ${cfg.overrideConfig}
       '' else ""}
       ## Extra Config
+      ${concatStringsSep "\n" (map (plug: plug.config) cfg.plugins)}
       ${cfg.extraConfig}
     '';
   cfg = config.krebs.Reaktor;
@@ -46,7 +36,6 @@ let
       '';
     };
 
-
     overrideConfig = mkOption {
       default = null;
       type = types.nullOr types.str;
@@ -55,6 +44,9 @@ let
         Reaktor default cfg can be retrieved via `reaktor get-config`
       '';
     };
+    plugins = mkOption {
+      default = [pkgs.ReaktorPlugins.nixos-version];
+    };
     extraConfig = mkOption {
       default = "";
       type = types.string;
@@ -62,6 +54,14 @@ let
         configuration appended to the default or overridden configuration
       '';
     };
+
+    workdir = mkOption {
+      default = "/var/lib/Reaktor";
+      type = types.str;
+      description = ''
+        Reaktor working directory
+      '';
+    };
     extraEnviron = mkOption {
       default = {};
       type = types.attrsOf types.str;
@@ -70,12 +70,17 @@ let
           REAKTOR_HOST
           REAKTOR_PORT
           REAKTOR_STATEDIR
-          REAKTOR_CHANNELS
 
           debug and nickname can be set separately via the Reaktor api
       '';
     };
-
+    channels = mkOption {
+      default = [ "#krebs" ];
+      type = types.listOf types.str;
+      description = ''
+        Channels the Reaktor should connect to at startup.
+      '';
+    };
     debug = mkOption {
       default = false;
       description = ''
@@ -86,12 +91,11 @@ let
 
   imp = {
     # for reaktor get-config
-    users.extraUsers = singleton {
+    users.extraUsers = singleton rec {
       name = "Reaktor";
-      # uid = config.ids.uids.Reaktor;
-      uid = 2066439104; #genid Reaktor
+      uid = genid name;
       description = "Reaktor user";
-      home = "/var/lib/Reaktor";
+      home = cfg.workdir;
       createHome = true;
     };
 
@@ -113,6 +117,9 @@ let
         GIT_SSL_CAINFO = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
         REAKTOR_NICKNAME = cfg.nickname;
         REAKTOR_DEBUG = (if cfg.debug  then "True" else "False");
+        REAKTOR_CHANNELS = lib.concatStringsSep "," cfg.channels;
+        state_dir = cfg.workdir;
+
         } // cfg.extraEnviron;
       serviceConfig= {
         ExecStartPre = pkgs.writeScript "Reaktor-init" ''
diff --git a/krebs/3modules/apt-cacher-ng.nix b/krebs/3modules/apt-cacher-ng.nix
index 75296bafb..371d39b6f 100644
--- a/krebs/3modules/apt-cacher-ng.nix
+++ b/krebs/3modules/apt-cacher-ng.nix
@@ -119,16 +119,14 @@ let
   imp = {
 
     users.extraUsers.acng = {
-    # uid = config.ids.uids.acng;
-      uid = 897955083; #genid Reaktor
+      uid = genid "acng";
       description = "apt-cacher-ng";
       home = acng-home;
       createHome = false;
     };
 
     users.extraGroups.acng = {
-      gid = 897955083; #genid Reaktor
-    # gid = config.ids.gids.Reaktor;
+      gid = genid "acng";
     };
 
     systemd.services.apt-cacher-ng = {
diff --git a/krebs/3modules/backup.nix b/krebs/3modules/backup.nix
new file mode 100644
index 000000000..01bb16a2b
--- /dev/null
+++ b/krebs/3modules/backup.nix
@@ -0,0 +1,286 @@
+{ config, lib, pkgs, ... }:
+with lib;
+let
+  out = {
+    options.krebs.backup = api;
+    config = mkIf cfg.enable imp;
+  };
+
+  cfg = config.krebs.backup;
+
+  api = {
+    enable = mkEnableOption "krebs.backup" // { default = true; };
+    plans = mkOption {
+      default = {};
+      type = types.attrsOf (types.submodule ({
+        # TODO enable = mkEnableOption "TODO" // { default = true; };
+        options = {
+          method = mkOption {
+            type = types.enum ["pull" "push"];
+          };
+          name = mkOption {
+            type = types.str;
+          };
+          src = mkOption {
+            type = types.krebs.file-location;
+          };
+          dst = mkOption {
+            type = types.krebs.file-location;
+          };
+          startAt = mkOption {
+            type = types.str;
+          };
+          snapshots = mkOption {
+            type = types.attrsOf (types.submodule {
+              options = {
+                format = mkOption {
+                  type = types.str; # TODO date's +FORMAT
+                };
+                retain = mkOption {
+                  type = types.nullOr types.int;
+                  default = null; # null = retain all snapshots
+                };
+              };
+            });
+          };
+        };
+      }));
+    };
+  };
+
+  imp = {
+    users.groups.backup.gid = genid "backup";
+    users.users = {}
+      // {
+        root.openssh.authorizedKeys.keys =
+          map (plan: plan.dst.host.ssh.pubkey)
+              (filter isPullSrc (attrValues cfg.plans))
+          ++
+          map (plan: plan.src.host.ssh.pubkey)
+              (filter isPushDst (attrValues cfg.plans))
+          ;
+      }
+      ;
+    systemd.services =
+      flip mapAttrs' (filterAttrs (_:isPullDst) cfg.plans) (name: plan: {
+        name = "backup.${name}.pull";
+        value = makePullService plan;
+      })
+      //
+      flip mapAttrs' (filterAttrs (_:isPushSrc) cfg.plans) (name: plan: {
+        name = "backup.${name}.push";
+        value = makePushService plan;
+      })
+      ;
+  };
+
+  isPushSrc = plan:
+    plan.method == "push" &&
+    plan.src.host.name == config.krebs.build.host.name;
+
+  isPullSrc = plan:
+    plan.method == "pull" &&
+    plan.src.host.name == config.krebs.build.host.name;
+
+  isPushDst = plan:
+    plan.method == "push" &&
+    plan.dst.host.name == config.krebs.build.host.name;
+
+  isPullDst = plan:
+    plan.method == "pull" &&
+    plan.dst.host.name == config.krebs.build.host.name;
+
+  # TODO push destination needs this in the dst.user's PATH
+  service-path = [
+    pkgs.coreutils
+    pkgs.gnused
+    pkgs.openssh
+    pkgs.rsync
+    pkgs.utillinux
+  ];
+
+  # TODO if there is plan.user, then use its privkey
+  makePushService = plan: assert isPushSrc plan; {
+    path = service-path;
+    serviceConfig = {
+      ExecStart = push plan;
+      Type = "oneshot";
+    };
+    startAt = plan.startAt;
+  };
+
+  makePullService = plan: assert isPullDst plan; {
+    path = service-path;
+    serviceConfig = {
+      ExecStart = pull plan;
+      Type = "oneshot";
+    };
+    startAt = plan.startAt;
+  };
+
+  push = plan: let
+    # We use writeDashBin and return the absolute path so systemd will produce
+    # nice names in the log, i.e. without the Nix store hash.
+    out = "${main}/bin/${main.name}";
+
+    main = writeDashBin "backup.${plan.name}.push" ''
+      set -efu
+      dst=${shell.escape plan.dst.path}
+
+      mkdir -m 0700 -p "$dst"
+      exec flock -n "$dst" ${critical-section}
+    '';
+
+    critical-section = writeDash "backup.${plan.name}.push.critical-section" ''
+      # TODO check if there is a previous
+      set -efu
+      identity=${shell.escape plan.src.host.ssh.privkey.path}
+      src=${shell.escape plan.src.path}
+      dst_target=${shell.escape "root@${getFQDN plan.dst.host}"}
+      dst_path=${shell.escape plan.dst.path}
+      dst=$dst_target:$dst_path
+
+      # Export NOW so runtime of rsync doesn't influence snapshot naming.
+      export NOW
+      NOW=$(date +%s)
+
+      echo >&2 "update snapshot: current; $src -> $dst"
+      rsync >&2 \
+          -aAXF --delete \
+          -e "ssh -F /dev/null -i $identity" \
+          --rsync-path ${shell.escape
+            "mkdir -m 0700 -p ${shell.escape plan.dst.path} && rsync"} \
+          --link-dest="$dst_path/current" \
+          "$src/" \
+          "$dst/.partial"
+
+      exec ssh -F /dev/null \
+          -i "$identity" \
+          "$dst_target" \
+          -T \
+          env NOW="$NOW" /bin/sh < ${remote-snapshot}
+      EOF
+    '';
+
+    remote-snapshot = writeDash "backup.${plan.name}.push.remote-snapshot" ''
+      set -efu
+      dst=${shell.escape plan.dst.path}
+
+      if test -e "$dst/current"; then
+        mv "$dst/current" "$dst/.previous"
+      fi
+      mv "$dst/.partial" "$dst/current"
+      rm -fR "$dst/.previous"
+      echo >&2
+
+      (${(take-snapshots plan).text})
+    '';
+
+  in out;
+
+  # TODO admit plan.dst.user and its ssh identity
+  pull = plan: let
+    # We use writeDashBin and return the absolute path so systemd will produce
+    # nice names in the log, i.e. without the Nix store hash.
+    out = "${main}/bin/${main.name}";
+
+    main = writeDashBin "backup.${plan.name}.pull" ''
+      set -efu
+      dst=${shell.escape plan.dst.path}
+
+      mkdir -m 0700 -p "$dst"
+      exec flock -n "$dst" ${critical-section}
+    '';
+
+    critical-section = writeDash "backup.${plan.name}.pull.critical-section" ''
+      # TODO check if there is a previous
+      set -efu
+      identity=${shell.escape plan.dst.host.ssh.privkey.path}
+      src=${shell.escape "root@${getFQDN plan.src.host}:${plan.src.path}"}
+      dst=${shell.escape plan.dst.path}
+
+      # Export NOW so runtime of rsync doesn't influence snapshot naming.
+      export NOW
+      NOW=$(date +%s)
+
+      echo >&2 "update snapshot: current; $dst <- $src"
+      mkdir -m 0700 -p ${shell.escape plan.dst.path}
+      rsync >&2 \
+          -aAXF --delete \
+          -e "ssh -F /dev/null -i $identity" \
+          --link-dest="$dst/current" \
+          "$src/" \
+          "$dst/.partial"
+      mv "$dst/current" "$dst/.previous"
+      mv "$dst/.partial" "$dst/current"
+      rm -fR "$dst/.previous"
+      echo >&2
+
+      exec ${take-snapshots plan}
+    '';
+  in out;
+
+  take-snapshots = plan: writeDash "backup.${plan.name}.take-snapshots" ''
+    set -efu
+    NOW=''${NOW-$(date +%s)}
+    dst=${shell.escape plan.dst.path}
+
+    snapshot() {(
+      : $ns $format $retain
+      name=$(date --date="@$NOW" +"$format")
+      if ! test -e "$dst/$ns/$name"; then
+        echo >&2 "create snapshot: $ns/$name"
+        mkdir -m 0700 -p "$dst/$ns"
+        rsync >&2 \
+            -aAXF --delete \
+            --link-dest="$dst/current" \
+            "$dst/current/" \
+            "$dst/$ns/.partial.$name"
+        mv "$dst/$ns/.partial.$name" "$dst/$ns/$name"
+        echo >&2
+      fi
+      case $retain in
+        ([0-9]*)
+          delete_from=$(($retain + 1))
+          ls -r "$dst/$ns" \
+            | sed -n "$delete_from,\$p" \
+            | while read old_name; do
+                echo >&2 "delete snapshot: $ns/$old_name"
+                rm -fR "$dst/$ns/$old_name"
+              done
+          ;;
+        (ALL)
+          :
+          ;;
+      esac
+    )}
+
+    ${concatStringsSep "\n" (mapAttrsToList (ns: { format, retain ? null, ... }:
+      toString (map shell.escape [
+        "ns=${ns}"
+        "format=${format}"
+        "retain=${if retain == null then "ALL" else toString retain}"
+        "snapshot"
+      ]))
+      plan.snapshots)}
+  '';
+
+  # TODO getFQDN: admit hosts in other domains
+  getFQDN = host: "${host.name}.${config.krebs.search-domain}";
+
+  writeDash = name: text: pkgs.writeScript name ''
+    #! ${pkgs.dash}/bin/dash
+    ${text}
+  '';
+
+  writeDashBin = name: text: pkgs.writeTextFile {
+    executable = true;
+    destination = "/bin/${name}";
+    name = name;
+    text = ''
+      #! ${pkgs.dash}/bin/dash
+      ${text}
+    '';
+  };
+
+in out
diff --git a/krebs/3modules/bepasty-server.nix b/krebs/3modules/bepasty-server.nix
index c99c3d11a..e74841205 100644
--- a/krebs/3modules/bepasty-server.nix
+++ b/krebs/3modules/bepasty-server.nix
@@ -130,12 +130,12 @@ let
     ) cfg.servers;
 
     users.extraUsers.bepasty = {
-      uid = 2796546855; #genid bepasty
+      uid = genid "bepasty";
       group = "bepasty";
       home = "/var/lib/bepasty-server";
     };
     users.extraGroups.bepasty = {
-      gid = 2796546855; #genid bepasty
+      gid = genid "bepasty";
     };
   };
 
diff --git a/krebs/3modules/buildbot/master.nix b/krebs/3modules/buildbot/master.nix
new file mode 100644
index 000000000..74385a433
--- /dev/null
+++ b/krebs/3modules/buildbot/master.nix
@@ -0,0 +1,385 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+let
+  buildbot = pkgs.buildbot;
+  buildbot-master-config = pkgs.writeText "buildbot-master.cfg" ''
+    # -*- python -*-
+    from buildbot.plugins import *
+    import re
+    import json
+    c = BuildmasterConfig = {}
+
+    c['slaves'] = []
+    slaves = json.loads('${builtins.toJSON cfg.slaves}')
+    slavenames = [ s for s in slaves ]
+    for k,v in slaves.items():
+      c['slaves'].append(buildslave.BuildSlave(k, v))
+
+    # TODO: configure protocols?
+    c['protocols'] = {'pb': {'port': 9989}}
+
+    ####### Build Inputs
+    c['change_source'] = cs = []
+
+    ${ concatStringsSep "\n"
+    (mapAttrsToList (n: v: ''
+        #### Change_Source: Begin of ${n}
+        ${v}
+        #### Change_Source: End of ${n}
+      '') cfg.change_source )}
+
+    ####### Build Scheduler
+    c['schedulers'] = sched = []
+
+    ${ concatStringsSep "\n"
+    (mapAttrsToList (n: v: ''
+        #### Schedulers: Begin of ${n}
+        ${v}
+        #### Schedulers: End of ${n}
+      '') cfg.scheduler )}
+
+    ###### Builder
+    c['builders'] = bu = []
+    
+    # Builder Pre: Begin
+    ${cfg.builder_pre}
+    # Builder Pre: End
+
+    ${ concatStringsSep "\n"
+    (mapAttrsToList (n: v: ''
+        #### Builder: Begin of ${n}
+        ${v}
+        #### Builder: End of ${n}
+      '') cfg.builder )}
+
+
+    ####### Status
+    c['status'] = st = []
+
+    # If you want to configure this url, override with extraConfig
+    c['buildbotURL'] = "http://${config.networking.hostName}:${toString cfg.web.port}/"
+
+    ${optionalString (cfg.web.enable) ''
+      from buildbot.status import html
+      from buildbot.status.web import authz, auth
+      authz_cfg=authz.Authz(
+          auth=auth.BasicAuth([ ("${cfg.web.username}","${cfg.web.password}") ]),
+          # TODO: configure harder
+          gracefulShutdown = False,
+          forceBuild = 'auth',
+          forceAllBuilds = 'auth',
+          pingBuilder = False,
+          stopBuild = 'auth',
+          stopAllBuilds = 'auth',
+          cancelPendingBuild = 'auth'
+      )
+      # TODO: configure krebs.nginx
+      st.append(html.WebStatus(http_port=${toString cfg.web.port}, authz=authz_cfg))
+      ''}
+
+    ${optionalString (cfg.irc.enable) ''
+      from buildbot.status import words
+      irc = words.IRC("${cfg.irc.server}", "${cfg.irc.nick}",
+                      channels=${builtins.toJSON cfg.irc.channels},
+                      notify_events={
+                        'success': 1,
+                        'failure': 1,
+                        'exception': 1,
+                        'successToFailure': 1,
+                        'failureToSuccess': 1,
+                      }${optionalString cfg.irc.allowForce ",allowForce=True"})
+      c['status'].append(irc)
+      ''}
+
+    ${ concatStringsSep "\n"
+    (mapAttrsToList (n: v: ''
+        #### Status: Begin of ${n}
+        ${v}
+        #### Status: End of ${n}
+      '') cfg.status )}
+
+    ####### PROJECT IDENTITY
+    c['title'] = "${cfg.title}"
+    c['titleURL'] = "http://krebsco.de"
+
+
+    ####### DB URL
+    # TODO: configure
+    c['db'] = {
+        'db_url' : "sqlite:///state.sqlite",
+    }
+    ${cfg.extraConfig}
+    '';
+
+  cfg = config.krebs.buildbot.master;
+
+  api = {
+    enable = mkEnableOption "Buildbot Master";
+    title = mkOption {
+      default = "Buildbot CI";
+      type = types.str;
+      description = ''
+        Title of the Buildbot Installation
+      '';
+    };
+    workDir = mkOption {
+      default = "/var/lib/buildbot/master";
+      type = types.str;
+      description = ''
+        Path to build bot master directory.
+        Will be created on startup.
+      '';
+    };
+
+    secrets = mkOption {
+      default = [];
+      type = types.listOf types.str;
+      example = [ "cac.json" ];
+      description = ''
+        List of all the secrets in <secrets> which should be copied into the
+        buildbot master directory.
+      '';
+    };
+
+    slaves = mkOption {
+      default = {};
+      type = types.attrsOf types.str;
+      description = ''
+        Attrset of slavenames with their passwords
+        slavename = slavepassword
+      '';
+    };
+
+    change_source = mkOption {
+      default = {};
+      type = types.attrsOf types.str;
+      example = {
+        stockholm = ''
+          cs.append(changes.GitPoller(
+                  'http://cgit.gum/stockholm',
+                  workdir='stockholm-poller', branch='master',
+                  project='stockholm',
+                  pollinterval=120))
+        '';
+      };
+      description = ''
+        Attrset of all the change_sources which should be configured.
+        It will be directly included into the master configuration.
+
+        At the end an change object should be appended to <literal>cs</literal>
+      '';
+    };
+
+    scheduler = mkOption {
+      default = {};
+      type = types.attrsOf types.str;
+      example = {
+        force-scheduler = ''
+          sched.append(schedulers.ForceScheduler(
+                                      name="force",
+                                      builderNames=["full-tests"]))
+        '';
+      };
+      description = ''
+        Attrset of all the schedulers which should be configured.
+        It will be directly included into the master configuration.
+
+        At the end an change object should be appended to <literal>sched</literal>
+      '';
+    };
+
+    builder_pre = mkOption {
+      default = "";
+      type = types.lines;
+      example = ''
+        grab_repo = steps.Git(repourl=stockholm_repo, mode='incremental')
+      '';
+      description = ''
+        some code before the builders are being assembled.
+        can be used to define functions used by multiple builders
+      '';
+    };
+
+    builder = mkOption {
+      default = {};
+      type = types.attrsOf types.str;
+      example = {
+        fast-test = ''
+        '';
+      };
+      description = ''
+        Attrset of all the builder which should be configured.
+        It will be directly included into the master configuration.
+
+        At the end an change object should be appended to <literal>bu</literal>
+      '';
+    };
+
+    status = mkOption {
+      default = {};
+      type = types.attrsOf types.str;
+      description = ''
+        Attrset of all the extra status which should be configured.
+        It will be directly included into the master configuration.
+
+        At the end an change object should be appended to <literal>st</literal>
+
+        Right now IRC and Web status can be configured by setting
+        <literal>buildbot.master.irc.enable</literal> and
+        <literal>buildbot.master.web.enable</literal>
+      '';
+    };
+
+    # Configurable Stati
+    web = mkOption {
+      default = {};
+      type = types.submodule ({ config2, ... }: {
+        options = {
+          enable = mkEnableOption "Buildbot Master Web Status";
+          username = mkOption {
+            default = "krebs";
+            type = types.str;
+            description = ''
+              username for web authentication
+            '';
+          };
+          hostname = mkOption {
+            default = config.networking.hostName;
+            type = types.str;
+            description = ''
+              web interface Hostname
+            '';
+          };
+          password = mkOption {
+            default = "bob";
+            type = types.str;
+            description = ''
+              password for web authentication
+            '';
+          };
+          port = mkOption {
+            default = 8010;
+            type = types.int;
+            description = ''
+              port for buildbot web status
+            '';
+          };
+        };
+      });
+    };
+
+    irc = mkOption {
+      default = {};
+      type = types.submodule ({ config, ... }: {
+        options = {
+          enable = mkEnableOption "Buildbot Master IRC Status";
+          channels = mkOption {
+            default = [ "nix-buildbot-meetup" ];
+            type = with types; listOf str;
+            description = ''
+              irc channels the bot should connect to
+            '';
+          };
+          allowForce = mkOption {
+            default = false;
+            type = types.bool;
+            description = ''
+              Determines if builds can be forced via IRC
+            '';
+          };
+          nick = mkOption {
+            default = "nix-buildbot";
+            type = types.str;
+            description = ''
+              nickname for IRC
+            '';
+          };
+          server = mkOption {
+            default = "irc.freenode.net";
+            type = types.str;
+            description = ''
+              Buildbot Status IRC Server to connect to
+            '';
+          };
+        };
+      });
+    };
+
+    extraConfig = mkOption {
+      default = "";
+      type = types.lines;
+      description = ''
+        extra config appended to the generated master.cfg
+      '';
+    };
+  };
+
+  imp = {
+
+    users.extraUsers.buildbotMaster = {
+      uid = genid "buildbotMaster";
+      description = "Buildbot Master";
+      home = cfg.workDir;
+      createHome = false;
+    };
+
+    users.extraGroups.buildbotMaster = {
+      gid = 672626386;
+    };
+
+    systemd.services.buildbotMaster = {
+      description = "Buildbot Master";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      # TODO: add extra dependencies to master like svn and cvs
+      path = [ pkgs.git ];
+      environment = {
+        SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
+      };
+      serviceConfig = let
+        workdir="${lib.shell.escape cfg.workDir}";
+        secretsdir="${lib.shell.escape (toString <secrets>)}";
+      in {
+        PermissionsStartOnly = true;
+        Type = "forking";
+        PIDFile = "${workdir}/twistd.pid";
+        # TODO: maybe also prepare buildbot.tac?
+        ExecStartPre = pkgs.writeScript "buildbot-master-init" ''
+          #!/bin/sh
+          set -efux
+          if [ ! -e ${workdir} ];then
+            mkdir -p ${workdir}
+            ${buildbot}/bin/buildbot create-master -r -l 10 -f ${workdir}
+          fi
+          # always override the master.cfg
+          cp ${buildbot-master-config} ${workdir}/master.cfg
+
+          # copy secrets
+          ${ concatMapStringsSep "\n"
+            (f: "cp ${secretsdir}/${f} ${workdir}/${f}" ) cfg.secrets }
+          # sanity
+          ${buildbot}/bin/buildbot checkconfig ${workdir}
+
+          # TODO: maybe upgrade? not sure about this
+          #       normally we should write buildbot.tac by our own
+          # ${buildbot}/bin/buildbot upgrade-master ${workdir}
+
+          chmod 700 -R ${workdir}
+          chown buildbotMaster:buildbotMaster -R ${workdir}
+        '';
+        ExecStart = "${buildbot}/bin/buildbot start ${workdir}";
+        ExecStop = "${buildbot}/bin/buildbot stop ${workdir}";
+        ExecReload = "${buildbot}/bin/buildbot reconfig ${workdir}";
+        PrivateTmp = "true";
+        User = "buildbotMaster";
+        Restart = "always";
+        RestartSec = "10";
+      };
+    };
+  };
+in
+{
+  options.krebs.buildbot.master = api;
+  config = mkIf cfg.enable imp;
+}
diff --git a/makefu/3modules/buildbot/slave.nix b/krebs/3modules/buildbot/slave.nix
similarity index 96%
rename from makefu/3modules/buildbot/slave.nix
rename to krebs/3modules/buildbot/slave.nix
index 69d0361bf..0e7796d8a 100644
--- a/makefu/3modules/buildbot/slave.nix
+++ b/krebs/3modules/buildbot/slave.nix
@@ -39,7 +39,7 @@ let
     s.setServiceParent(application)
     '';
   default-packages = [ pkgs.git pkgs.bash ];
-  cfg = config.makefu.buildbot.slave;
+  cfg = config.krebs.buildbot.slave;
 
   api = {
     enable = mkEnableOption "Buildbot Slave";
@@ -127,7 +127,7 @@ let
   imp = {
 
     users.extraUsers.buildbotSlave = {
-      uid = 1408105834; #genid buildbotMaster
+      uid = genid "buildbotSlave";
       description = "Buildbot Slave";
       home = cfg.workDir;
       createHome = false;
@@ -144,6 +144,7 @@ let
       path = default-packages ++ cfg.packages;
 
       environment = {
+          SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
           NIX_REMOTE="daemon";
       } // cfg.extraEnviron;
 
@@ -180,6 +181,6 @@ let
   };
 in
 {
-  options.makefu.buildbot.slave = api;
+  options.krebs.buildbot.slave = api;
   config = mkIf cfg.enable imp;
 }
diff --git a/krebs/3modules/default.nix b/krebs/3modules/default.nix
index 740ba67b8..ba1f425d9 100644
--- a/krebs/3modules/default.nix
+++ b/krebs/3modules/default.nix
@@ -7,8 +7,11 @@ let
   out = {
     imports = [
       ./apt-cacher-ng.nix
+      ./backup.nix
       ./bepasty-server.nix
       ./build.nix
+      ./buildbot/master.nix
+      ./buildbot/slave.nix
       ./current.nix
       ./exim-retiolum.nix
       ./exim-smarthost.nix
diff --git a/krebs/3modules/exim-retiolum.nix b/krebs/3modules/exim-retiolum.nix
index e1315d8c8..ea012c38c 100644
--- a/krebs/3modules/exim-retiolum.nix
+++ b/krebs/3modules/exim-retiolum.nix
@@ -1,14 +1,12 @@
 { config, pkgs, lib, ... }:
 
-with builtins;
 with lib;
 let
   cfg = config.krebs.exim-retiolum;
 
   out = {
     options.krebs.exim-retiolum = api;
-    config =
-      mkIf cfg.enable imp;
+    config = mkIf cfg.enable imp;
   };
 
   api = {
@@ -16,13 +14,13 @@ let
   };
 
   imp = {
-    services.exim =
-      # This configuration makes only sense for retiolum-enabled hosts.
-      # TODO modular configuration
-      assert config.krebs.retiolum.enable;
-      {
-        enable = true;
-        config = ''
+    services.exim = {
+      enable = true;
+      config =
+        # This configuration makes only sense for retiolum-enabled hosts.
+        # TODO modular configuration
+        assert config.krebs.retiolum.enable;
+        ''
           primary_hostname = ${retiolumHostname}
           domainlist local_domains    = @ : localhost
           domainlist relay_to_domains = *.retiolum
@@ -134,7 +132,7 @@ let
 
           begin authenticators
         '';
-      };
+    };
   };
 
   # TODO get the hostname from somewhere else.
diff --git a/krebs/3modules/fetchWallpaper.nix b/krebs/3modules/fetchWallpaper.nix
index 83ecf4177..f320c7505 100644
--- a/krebs/3modules/fetchWallpaper.nix
+++ b/krebs/3modules/fetchWallpaper.nix
@@ -51,7 +51,7 @@ let
   imp = {
     users.users.fetchWallpaper = {
       name = "fetchWallpaper";
-      uid = 3332383611; #genid fetchWallpaper
+      uid = genid "fetchWallpaper";
       description = "fetchWallpaper user";
       home = cfg.stateDir;
       createHome = true;
diff --git a/krebs/3modules/git.nix b/krebs/3modules/git.nix
index 234129497..e6267d7e6 100644
--- a/krebs/3modules/git.nix
+++ b/krebs/3modules/git.nix
@@ -145,14 +145,14 @@ let
         ]) (filter (x: hasAttr "allow-receive-ref" x.perm) cfg.rules));
       };
     
-    users.extraUsers = singleton {
+    users.extraUsers = singleton rec {
       description = "Git repository hosting user";
       name = "git";
       shell = "/bin/sh";
       openssh.authorizedKeys.keys =
         mapAttrsToList (_: makeAuthorizedKey git-ssh-command)
           config.krebs.users;
-      uid = 129318403; # genid git
+      uid = genid name;
     };
   };
 
@@ -238,9 +238,9 @@ let
     };
   };
 
-  fcgitwrap-user = {
+  fcgitwrap-user = rec {
     name = "fcgiwrap";
-    uid = 2867890860; # genid fcgiwrap
+    uid = genid name;
     group = "fcgiwrap";
   };
 
diff --git a/krebs/3modules/github-hosts-sync.nix b/krebs/3modules/github-hosts-sync.nix
index 5503ee8d6..2aa18d53a 100644
--- a/krebs/3modules/github-hosts-sync.nix
+++ b/krebs/3modules/github-hosts-sync.nix
@@ -56,9 +56,9 @@ let
     };
   };
 
-  user = {
+  user = rec {
     name = "github-hosts-sync";
-    uid = 3220554646; # genid github-hosts-sync
+    uid = genid name;
   };
 
   # TODO move to lib?
diff --git a/krebs/3modules/go.nix b/krebs/3modules/go.nix
index 793d1f60d..08a93dab7 100644
--- a/krebs/3modules/go.nix
+++ b/krebs/3modules/go.nix
@@ -1,6 +1,5 @@
 { config, lib, pkgs, ... }:
 
-with builtins;
 with lib;
 
 let
@@ -31,9 +30,9 @@ let
       bind = mkDefault "127.0.0.1";
     };
 
-    users.extraUsers.go = {
+    users.extraUsers.go = rec {
       name = "go";
-      uid = 42774411; #genid go
+      uid = genid name;
       description = "go url shortener user";
       home = "/var/lib/go";
       createHome = true;
diff --git a/krebs/3modules/makefu/default.nix b/krebs/3modules/makefu/default.nix
index 1970a0777..31516d591 100644
--- a/krebs/3modules/makefu/default.nix
+++ b/krebs/3modules/makefu/default.nix
@@ -83,6 +83,9 @@ with lib;
             '';
         };
       };
+      ssh.privkey.path = <secrets/ssh_host_ed25519_key>;
+      ssh.pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHDM0E608d/6rGzXqGbNSuMb2RlCojCJSiiz6QcPOC2G root@pornocauster";
+
     };
 
     vbob = {
@@ -108,6 +111,8 @@ with lib;
             '';
         };
       };
+      ssh.privkey.path = <secrets/ssh_host_ed25519_key>;
+      ssh.pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICPLTMl+thSq77cjYa2XF7lz5fA7JMftrLo8Dy/OBXSg root@nixos";
     };
     flap = rec {
       cores = 1;
@@ -238,6 +243,8 @@ with lib;
           '';
         };
       };
+      ssh.privkey.path = <secrets/ssh_host_ed25519_key>;
+      ssh.pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH4Tjx9qK6uWtxT1HCpeC0XvDZKO/kaPygyKatpAqU6I root@wry";
     };
     filepimp = rec {
       cores = 1;
@@ -287,6 +294,8 @@ with lib;
             '';
         };
       };
+      ssh.privkey.path = <secrets/ssh_host_ed25519_key>;
+      ssh.pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIujMZ3ZFxKpWeB/cjfKfYRr77+VRZk0Eik+92t03NoA root@servarch";
     };
     gum = rec {
       cores = 1;
@@ -327,6 +336,8 @@ with lib;
             '';
         };
       };
+      ssh.privkey.path = <secrets/ssh_host_ed25519_key>;
+      ssh.pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIcxWFEPzke/Sdd9qNX6rSJgXal8NmINYajpFCxXfYdj root@gum";
     };
   };
   users = addNames rec {
diff --git a/krebs/3modules/realwallpaper.nix b/krebs/3modules/realwallpaper.nix
index 7e02538f5..b377368f7 100644
--- a/krebs/3modules/realwallpaper.nix
+++ b/krebs/3modules/realwallpaper.nix
@@ -1,13 +1,7 @@
 arg@{ config, lib, pkgs, ... }:
 
+with lib;
 let
-  inherit (lib)
-    mkEnableOption
-    mkOption
-    types
-    mkIf
-  ;
-
   cfg = config.krebs.realwallpaper;
 
   out = {
@@ -89,7 +83,7 @@ let
     };
 
     users.extraUsers.realwallpaper = {
-      uid = 2009435407; #genid realwallpaper
+      uid = genid "realwallpaper";
       home = cfg.workingDir;
       createHome = true;
     };
diff --git a/krebs/3modules/retiolum.nix b/krebs/3modules/retiolum.nix
index 28ac67306..e0e2692a8 100644
--- a/krebs/3modules/retiolum.nix
+++ b/krebs/3modules/retiolum.nix
@@ -133,9 +133,9 @@ let
     };
   };
 
-  user = {
+  user = rec {
     name = "retiolum";
-    uid = 301281149; # genid retiolum
+    uid = genid name;
   };
 
   tinc = cfg.tincPackage;
diff --git a/krebs/3modules/shared/default.nix b/krebs/3modules/shared/default.nix
index b332676c6..518e46587 100644
--- a/krebs/3modules/shared/default.nix
+++ b/krebs/3modules/shared/default.nix
@@ -7,6 +7,7 @@ let
     "test-arch"
     "test-centos6"
     "test-centos7"
+    "test-all-krebs-modules"
   ] (name: {
     inherit name;
     cores = 1;
diff --git a/krebs/3modules/tinc_graphs.nix b/krebs/3modules/tinc_graphs.nix
index ba81dd416..1f32c2e59 100644
--- a/krebs/3modules/tinc_graphs.nix
+++ b/krebs/3modules/tinc_graphs.nix
@@ -120,7 +120,7 @@ let
     };
 
     users.extraUsers.tinc_graphs = {
-      uid = 3925439960; #genid tinc_graphs
+      uid = genid "tinc_graphs";
       home = "/var/spool/tinc_graphs";
     };
 
diff --git a/krebs/3modules/urlwatch.nix b/krebs/3modules/urlwatch.nix
index 206bc5697..31cbfcf6e 100644
--- a/krebs/3modules/urlwatch.nix
+++ b/krebs/3modules/urlwatch.nix
@@ -5,7 +5,6 @@
 # cache = url: "${cfg.dataDir}/.urlwatch/cache/${hashString "sha1" url}"
 # TODO hooks.py
 
-with builtins;
 with lib;
 let
   cfg = config.krebs.urlwatch;
@@ -136,9 +135,9 @@ let
     };
   };
 
-  user = {
+  user = rec {
     name = "urlwatch";
-    uid = 3467631196; # genid urlwatch
+    uid = genid name;
   };
 in
 out
diff --git a/krebs/4lib/default.nix b/krebs/4lib/default.nix
index 1cabeae27..dfc51bbe4 100644
--- a/krebs/4lib/default.nix
+++ b/krebs/4lib/default.nix
@@ -7,6 +7,8 @@ let out = rec {
 
   eq = x: y: x == y;
 
+  mod = x: y: x - y * (x / y);
+
   addName = name: set:
     set // { inherit name; };
 
@@ -17,6 +19,7 @@ let out = rec {
   dir.has-default-nix = path: pathExists (path + "/default.nix");
 
   dns = import ./dns.nix { inherit lib; };
+  genid = import ./genid.nix { lib = lib // out; };
   git = import ./git.nix { lib = lib // out; };
   listset = import ./listset.nix { inherit lib; };
   shell = import ./shell.nix { inherit lib; };
diff --git a/krebs/4lib/genid.nix b/krebs/4lib/genid.nix
new file mode 100644
index 000000000..0aed1d351
--- /dev/null
+++ b/krebs/4lib/genid.nix
@@ -0,0 +1,37 @@
+{ lib, ... }:
+with lib;
+with builtins;
+let out = genid;
+
+  # id = genid s = (hash s + min) % max
+  # min <= genid s < max
+  #
+  # min = 2^24 =   16777216 = 0x001000000
+  # max = 2^32 = 4294967296 = 0x100000000
+  #
+  # id is bigger than UID of nobody and GID of nogroup
+  # see <nixos/modules/misc/ids.nix> and some spare for stuff like lxd.
+  #
+  # :: str -> uint32
+  genid = s: sum16 (addmod16_16777216 (hash s));
+
+  # :: str -> list8 uint4
+  hash = s:
+    map hexint (stringToCharacters (substring 32 8 (hashString "sha1" s)));
+
+  # :: list uint -> uint
+  sum16 = foldl (a: i: a * 16 + i) 0;
+
+  # :: list8 uint4 -> list1 uint8 ++ list6 uint4
+  addmod16_16777216 = x: let
+    a = 16 * head x + head (tail x);
+    d = tail (tail x);
+  in [(mod (a + 1) 256)] ++ d;
+
+  # :: char -> uint4
+  hexint = x: hexvals.${toLower x};
+
+  # :: attrset char uint4
+  hexvals = listToAttrs (imap (i: c: { name = c; value = i - 1; })
+                        (stringToCharacters "0123456789abcdef"));
+in out
diff --git a/krebs/4lib/types.nix b/krebs/4lib/types.nix
index c52afa246..81ce659bd 100644
--- a/krebs/4lib/types.nix
+++ b/krebs/4lib/types.nix
@@ -177,4 +177,21 @@ types // rec {
   addr6 = str;
   hostname = str;
   label = str;
+
+  krebs.file-location = types.submodule {
+    options = {
+      # TODO user
+      host = mkOption {
+        type = host;
+      };
+      # TODO merge with ssl.privkey.path
+      path = mkOption {
+        type = types.either types.path types.str;
+        apply = x: {
+          path = toString x;
+          string = x;
+        }.${typeOf x};
+      };
+    };
+  };
 }
diff --git a/krebs/5pkgs/Reaktor/plugins.nix b/krebs/5pkgs/Reaktor/plugins.nix
new file mode 100644
index 000000000..7490be4ca
--- /dev/null
+++ b/krebs/5pkgs/Reaktor/plugins.nix
@@ -0,0 +1,120 @@
+{ stdenv, lib, pkgs, makeWrapper }:
+
+rec {
+  # Begin API
+  buildBaseReaktorPlugin = { name
+                        , config # python extra configuration for plugin
+                        , phases ? []
+                        , ... } @ attrs:
+    stdenv.mkDerivation (attrs // {
+      name = "Reaktor-plugin-" + name;
+      isReaktorPlugin = true;
+    });
+
+  buildSimpleReaktorPlugin = name: { script
+                        , path ? []
+                        , env ? {}
+                        , append_rule ? false # append the rule instead of insert
+                        , pattern ? ""
+                        , ... } @ attrs:
+    let
+      path_env = { "PATH" = lib.makeSearchPath "bin" (path ++ [ pkgs.coreutils ]); };
+      src_dir = pkgs.substituteAll ( {
+        inherit name;
+        dir = "bin";
+        isExecutable = true;
+        src = script;
+      });
+      src_file = "${src_dir}/bin/${name}";
+      config = ''
+        public_commands.${if append_rule then "append(" else "insert(0," }{
+          'capname' : "${name}",
+          'pattern' : ${if pattern == "" then
+                          ''indirect_pattern.format("${name}")'' else
+                          ''"${pattern}"'' },
+          'argv'    : ["${src_file}"],
+          'env'     : ${builtins.toJSON (path_env // env)} })
+      '';
+      config_file = pkgs.writeText "plugin.py" config;
+    in buildBaseReaktorPlugin (attrs // rec {
+      inherit name config;
+
+      phases = [ "installPhase" ];
+      buildInputs = [ makeWrapper ];
+      installPhase = ''
+        mkdir -p $out/bin $out/etc/Reaktor
+        ln -s ${src_file} $out/bin
+        wrapProgram $out/bin/${name} \
+          --prefix PATH : ${path_env.PATH}
+        ln -s ${config_file} $out/etc/Reaktor/plugin.py
+      '';
+
+    });
+  # End API
+
+  # Begin Plugins
+  random-emoji = buildSimpleReaktorPlugin "emoji" {
+    path = with pkgs; [ gnused gnugrep xmlstarlet curl ];
+    script = ./scripts/random-emoji.sh;
+  };
+
+  sed-plugin = buildSimpleReaktorPlugin "sed-plugin" {
+    path = [ pkgs.gnused pkgs.python3 ];
+    # only support s///gi the plugin needs to see every msg
+    # TODO: this will eat up the last regex, fix Reaktor to support fallthru
+    append_rule = true;
+    pattern = "^(?P<args>.*)$$";
+    script = ./scripts/sed-plugin.py;
+  };
+
+  shack-correct = buildSimpleReaktorPlugin "shack-correct" {
+    path = [ pkgs.gnused ];
+    pattern = "^(?P<args>.*Shack.*)$$";
+    script = ./scripts/shack-correct.sh;
+  };
+
+  nixos-version = buildSimpleReaktorPlugin "nixos-version" {
+    script = pkgs.writeScript "nixos-version" ''
+      #! /bin/sh
+      . /etc/os-release
+      echo "$PRETTY_NAME"
+      '';
+  };
+  stockholm-issue = buildSimpleReaktorPlugin "stockholm-issue" {
+    script = ./scripts/random-issue.sh;
+    path = with pkgs; [ git gnused lentil ];
+    env = { "origin" = "http://cgit.gum/stockholm"; };
+  };
+
+  titlebot =
+  let
+    pypkgs = pkgs.python3Packages;
+    titlebot_cmds =  pypkgs.buildPythonPackage {
+      name = "titlebot_cmds";
+      propagatedBuildInputs =  with pypkgs; [ setuptools ];
+      src = pkgs.fetchurl {
+        url = "https://github.com/makefu/reaktor-titlebot/archive/2.1.0.tar.gz";
+        sha256 = "0wvf09wmk8b52f9j65qrw81nwrhs9pfhijwrlkzp5l7l2q8cjkp6";
+        };
+      };
+  in buildBaseReaktorPlugin rec {
+    name = "titlebot";
+    phases = [ "installPhase" ];
+    installPhase = ''
+      mkdir -p $out
+      ln -s ${titlebot_cmds}/* $out
+    '';
+    config = ''
+      def titlebot_cmd(cmd):
+        from os import environ
+        return {  'capname': None,
+                  'env': { 'TITLEDB':
+                    environ['state_dir']+'/suggestions.json' },
+                  'pattern': '^\\.' + cmd + '\\s*(?:\\s+(?P<args>.*))?$$',
+                  'argv': [ '${titlebot_cmds}/bin/' + cmd ] }
+      for i in ['up','help','list','top','new']:
+        public_commands.insert(0,titlebot_cmd(i))
+      commands.insert(0,titlebot_cmd('clear'))
+    '';
+  };
+}
diff --git a/makefu/2configs/Reaktor/random-emoji.sh b/krebs/5pkgs/Reaktor/scripts/random-emoji.sh
similarity index 100%
rename from makefu/2configs/Reaktor/random-emoji.sh
rename to krebs/5pkgs/Reaktor/scripts/random-emoji.sh
diff --git a/makefu/2configs/Reaktor/random-issue.sh b/krebs/5pkgs/Reaktor/scripts/random-issue.sh
similarity index 100%
rename from makefu/2configs/Reaktor/random-issue.sh
rename to krebs/5pkgs/Reaktor/scripts/random-issue.sh
diff --git a/makefu/2configs/Reaktor/sed-plugin.py b/krebs/5pkgs/Reaktor/scripts/sed-plugin.py
similarity index 100%
rename from makefu/2configs/Reaktor/sed-plugin.py
rename to krebs/5pkgs/Reaktor/scripts/sed-plugin.py
diff --git a/makefu/2configs/Reaktor/shack-correct.sh b/krebs/5pkgs/Reaktor/scripts/shack-correct.sh
similarity index 100%
rename from makefu/2configs/Reaktor/shack-correct.sh
rename to krebs/5pkgs/Reaktor/scripts/shack-correct.sh
diff --git a/krebs/5pkgs/cacpanel/default.nix b/krebs/5pkgs/cacpanel/default.nix
index 3e3e2e1fc..3df4dffed 100644
--- a/krebs/5pkgs/cacpanel/default.nix
+++ b/krebs/5pkgs/cacpanel/default.nix
@@ -2,11 +2,11 @@
 
 python3Packages.buildPythonPackage rec {
   name = "cacpanel-${version}";
-  version = "0.2.1";
+  version = "0.2.3";
 
   src = pkgs.fetchurl {
     url = "https://pypi.python.org/packages/source/c/cacpanel/cacpanel-${version}.tar.gz";
-    sha256 = "1zaazg5r10kgva32zh4fhpw6l6h51ijkwpa322na0kh4x6f6aqj3";
+    sha256 = "1fib7416qqv8yzrj75kxra7ccpz9abqh58b6gkaavws2fa6m3mm8";
   };
 
   propagatedBuildInputs = with python3Packages; [
diff --git a/krebs/5pkgs/default.nix b/krebs/5pkgs/default.nix
index 7df7b7d3c..c4b1dafe4 100644
--- a/krebs/5pkgs/default.nix
+++ b/krebs/5pkgs/default.nix
@@ -26,6 +26,8 @@ subdirs // rec {
     inherit (subdirs) get jq;
   };
 
+  ReaktorPlugins = pkgs.callPackage ./Reaktor/plugins.nix {};
+
   execve = name: { filename, argv, envp ? {}, destination ? "" }:
     writeC name { inherit destination; } ''
       #include <unistd.h>
@@ -40,6 +42,10 @@ subdirs // rec {
       }
     '';
 
+  test = {
+    infest-cac-centos7 = pkgs.callPackage ./test/infest-cac-centos7 {};
+  };
+
   execveBin = name: cfg: execve name (cfg // { destination = "/bin/${name}"; });
 
   writeC = name: { destination ? "" }: src: pkgs.runCommand name {} ''
diff --git a/krebs/5pkgs/genid/default.nix b/krebs/5pkgs/genid/default.nix
deleted file mode 100644
index c75bec317..000000000
--- a/krebs/5pkgs/genid/default.nix
+++ /dev/null
@@ -1,22 +0,0 @@
-{ lib, pkgs, ... }:
-
-pkgs.writeScriptBin "genid" ''
-  #! /bin/sh
-  # usage: genid NAME
-  set -euf
-
-  export PATH=${lib.makeSearchPath "bin" (with pkgs; [
-    bc
-    coreutils
-  ])}
-
-  name=$1
-  hash=$(printf %s "$name" | sha1sum | cut -d\  -f1 | tr a-f A-F)
-  echo "
-    min=2^24  # bigger than nobody and nogroup, see <nixos/modules/misc/ids.nix>
-              # and some spare for stuff like lxd.
-    max=2^32  # see 2^(8*sizeof(uid_t))
-    ibase=16
-    ($hash + min) % max
-  " | bc
-''
diff --git a/krebs/5pkgs/krebszones/default.nix b/krebs/5pkgs/krebszones/default.nix
index f6fd672dc..9230192bd 100644
--- a/krebs/5pkgs/krebszones/default.nix
+++ b/krebs/5pkgs/krebszones/default.nix
@@ -1,5 +1,10 @@
 { lib, pkgs,python3Packages,fetchurl, ... }:
 
+# TODO: Prepare a diff of future and current
+## ovh-zone export krebsco.de --config ~/secrets/krebs/cfg.json |sed 's/[ ]\+/ /g' | sort current
+## sed 's/[ ]\+/ /g'/etc/zones/krebsco.de | sort > future
+## diff future.sorted current.sorted
+
 python3Packages.buildPythonPackage rec {
   name = "krebszones-${version}";
   version = "0.4.4";
diff --git a/krebs/5pkgs/snapraid/default.nix b/krebs/5pkgs/snapraid/default.nix
deleted file mode 100644
index 41db0f284..000000000
--- a/krebs/5pkgs/snapraid/default.nix
+++ /dev/null
@@ -1,33 +0,0 @@
-{stdenv, fetchurl}:
-let
-  s = # Generated upstream information
-  rec {
-    baseName="jq";
-    version="1.5";
-    name="${baseName}-${version}";
-    url=https://github.com/stedolan/jq/releases/download/jq-1.5/jq-1.5.tar.gz;
-    sha256="0g29kyz4ykasdcrb0zmbrp2jqs9kv1wz9swx849i2d1ncknbzln4";
-  };
-  buildInputs = [
-  ];
-in
-stdenv.mkDerivation {
-  inherit (s) name version;
-  inherit buildInputs;
-  src = fetchurl {
-    inherit (s) url sha256;
-  };
-
-  # jq is linked to libjq:
-  configureFlags = [
-    "LDFLAGS=-Wl,-rpath,\\\${libdir}"
-  ];
-  meta = {
-    inherit (s) version;
-    description = ''A lightweight and flexible command-line JSON processor'';
-    license = stdenv.lib.licenses.mit ;
-    maintainers = [stdenv.lib.maintainers.raskin];
-    platforms = stdenv.lib.platforms.linux ++ stdenv.lib.platforms.darwin;
-  };
-}
-
diff --git a/krebs/5pkgs/krebs-ci/default.nix b/krebs/5pkgs/test/infest-cac-centos7/default.nix
similarity index 74%
rename from krebs/5pkgs/krebs-ci/default.nix
rename to krebs/5pkgs/test/infest-cac-centos7/default.nix
index f5b302b52..7f2e3f231 100644
--- a/krebs/5pkgs/krebs-ci/default.nix
+++ b/krebs/5pkgs/test/infest-cac-centos7/default.nix
@@ -1,7 +1,9 @@
 { stdenv, coreutils,makeWrapper, cac, cacpanel, gnumake, gnused, jq, openssh, ... }:
 
 stdenv.mkDerivation rec {
-  name = "krebs-ci-0.1.0";
+  name = "${shortname}-${version}";
+  shortname = "infest-cac-centos7";
+  version = "0.2.0";
 
   src = ./notes;
 
@@ -23,9 +25,9 @@ stdenv.mkDerivation rec {
   installPhase =
     ''
       mkdir -p $out/bin
-      cp ${src} $out/bin/krebs-ci
-      chmod +x $out/bin/krebs-ci
-      wrapProgram $out/bin/krebs-ci \
+      cp ${src} $out/bin/${shortname}
+      chmod +x $out/bin/${shortname}
+      wrapProgram $out/bin/${shortname} \
               --prefix PATH : ${path}
     '';
   meta = with stdenv.lib; {
diff --git a/krebs/5pkgs/krebs-ci/notes b/krebs/5pkgs/test/infest-cac-centos7/notes
similarity index 51%
rename from krebs/5pkgs/krebs-ci/notes
rename to krebs/5pkgs/test/infest-cac-centos7/notes
index 7e34d6a28..6bfb6906e 100755
--- a/krebs/5pkgs/krebs-ci/notes
+++ b/krebs/5pkgs/test/infest-cac-centos7/notes
@@ -1,12 +1,24 @@
 #! /bin/sh
 
 # nix-shell -p gnumake jq openssh cac cacpanel
-set -euf
+set -eufx
 
 # 2 secrets are required:
+
 krebs_cred=${krebs_cred-./cac.json}
 retiolum_key=${retiolum_key-./retiolum.rsa_key.priv}
 
+clear_defer(){
+  echo "${trapstr:-exit}"
+  trap - INT TERM EXIT KILL
+}
+defer(){
+  if test -z "${debug:-}"; then
+    trapstr="$1;${trapstr:-exit}"
+    trap "$trapstr" INT TERM EXIT KILL
+  fi
+}
+
 # Sanity
 if test ! -r "$krebs_cred";then
   echo "\$krebs_cred=$krebs_cred must be readable"; exit 1
@@ -18,46 +30,73 @@ fi
 krebs_secrets=$(mktemp -d)
 sec_file=$krebs_secrets/cac_config
 krebs_ssh=$krebs_secrets/tempssh
+export cac_resources_cache=$krebs_secrets/res_cache.json
+export cac_servers_cache=$krebs_secrets/servers_cache.json
+export cac_tasks_cache=$krebs_secrets/tasks_cache.json
+export cac_templates_cache=$krebs_secrets/templates_cache.json
 # we need to receive this key from buildmaster to speed up tinc bootstrap
-TRAP="rm $sec_file;rm -r $krebs_secrets"
-trap "$TRAP" INT TERM EXIT
+defer "trap - INT TERM EXIT"
+defer "rm -r $krebs_secrets"
 
 cat > $sec_file <<EOF
 cac_login="$(jq -r .email $krebs_cred)"
-cac_key="$(cac-cli panel --config $krebs_cred settings | jq -r .apicode)"
+cac_key="$(cac-cli --config $krebs_cred panel settings | jq -r .apicode)"
 EOF
 
 export cac_secrets=$sec_file
-cac-cli panel --config $krebs_cred update-api-ip
+cac-cli --config $krebs_cred panel  add-api-ip
 
 # test login:
 cac update
 cac servers
 
-# Template 26: CentOS7
-# TODO: use cac templates to determine the real Centos7 template in case it changes
-name=$( cac build cpu=1 ram=512 storage=10 os=26 2>&1\
-  | jq -r .servername)
+# preserve old trap
+old_trapstr=$(clear_defer)
+while true;do
+  # Template 26: CentOS7
+  # TODO: use cac templates to determine the real Centos7 template in case it changes
+  out=$(cac build cpu=1 ram=512 storage=10 os=26 2>&1)
+  if name=$(echo "$out" | jq -r .servername);then
+    id=servername:$name
+    echo "got a working machine, id=$id"
+  else
+    echo "Unable to build a virtual machine, retrying in 15 seconds" >&2
+    echo "Output of build program: $out" >&2
+    sleep 15
+    continue
+  fi
 
-id=servername:$name
-trap "cac delete $id;$TRAP" INT TERM EXIT
-# TODO: timeout?
-always_update=true cac waitstatus $id "Powered On"
+  clear_defer >/dev/null
+  defer "cac delete $id"
 
-wait_login_cac(){
-  # timeout
-  for t in `seq 60`;do
-    # now we have a working cac server
-    if cac ssh $1 cat /etc/redhat-release | \
-      grep CentOS ;then
-      return 0
-    fi
-    sleep 10
-  done
-  return 1
-}
-# die on timeout
-wait_login_cac $id
+  # TODO: timeout?
+
+  wait_login_cac(){
+    # we wait for 30 minutes
+    for t in `seq 180`;do
+      # now we have a working cac server
+      if cac ssh $1 -o ConnectTimeout=10 \
+                    cat /etc/redhat-release | \
+                      grep CentOS ;then
+        return 0
+      fi
+      sleep 10
+    done
+    return 1
+  }
+  # die on timeout
+  if ! wait_login_cac $id;then
+    echo "unable to boot a working system within time frame, retrying..." >&2
+    echo "Cleaning up old image,last status: $(cac update;cac getserver $id | jq -r .status)"
+    eval "$(clear_defer | sed 's/;exit//')"
+    sleep 15
+  else
+    echo "got a working system" >&2
+    break
+  fi
+done
+clear_defer >/dev/null
+defer "cac delete $id;$old_trapstr"
 
 mkdir -p shared/2configs/temp
 cac generatenetworking $id > \
@@ -94,7 +133,7 @@ cac powerop $id reset
 
 wait_login(){
   # timeout
-  for t in `seq 20`;do
+  for t in `seq 90`;do
     # now we have a working cac server
     if ssh -o StrictHostKeyChecking=no \
            -o UserKnownHostsFile=/dev/null \
diff --git a/krebs/Zhosts/bobby b/krebs/Zhosts/bobby
new file mode 100644
index 000000000..aac6e377b
--- /dev/null
+++ b/krebs/Zhosts/bobby
@@ -0,0 +1,11 @@
+Subnet = 10.243.111.112/32
+Subnet = 42:0:0:0:0:0:111:112/128
+
+-----BEGIN RSA PUBLIC KEY-----
+MIIBCgKCAQEA+AScnIqFdzGl+iRZTNZ7r91n/r1H4GzDsrAupUvJ4mi7nDN4eP8s
+uLvKtJp22RxfuF3Kf4KhHb8LHQ8bLLN/KDaNDXrCNBc69d7vvLsjoY+wfGLJNu4Y
+Ad/8J4r3rdb83mTA3IHb47T/70MERPBr2gF84YiG6ZoQrPQuTk4lHxaI83SOhjny
+0F0ucS/rBV6Vv9y5/756TKi1cFPSpY4X+qeWc8xWrBGJcJiiqYb8ZX2o/lkAJ5c+
+jI/VdybGFVGY9+bp4Jw5xBIo5KGuFnm8+blRmSDDl3joRneKQSx9FAu7RUwoajBu
+cEbi1529NReQzIFT6Vt22ymbHftxOiuh4QIDAQAB
+-----END RSA PUBLIC KEY-----
diff --git a/krebs/Zhosts/kebsco b/krebs/Zhosts/kebsco
new file mode 100644
index 000000000..2fd1c5f42
--- /dev/null
+++ b/krebs/Zhosts/kebsco
@@ -0,0 +1,11 @@
+Subnet = 10.243.212.68
+Subnet = 42:9d30:3845:c822:988b:96c5:39ab:90b7
+
+-----BEGIN RSA PUBLIC KEY-----
+MIIBCgKCAQEA0dEwTZh2uzJpP9GL7YRyiLuezJqYiJ8/4Bl4IPshJnuO9IGbEcto
+0cFm9uM9gxxqggfaCi96DsIQNlyqff2vDfEj3mdIu9T3tkRROByQF8y1NWX29NyH
+zZEX8Ri8u4U2KdYTEzPXEFxBEl0GQX9mMtlvwzCq7V4ueCcWB1xDA+DtJjpd894z
+3FOw0rIxYmfYhLAL5B3rzF74bcHFGV30f4JWq11wLBkyR6/Q5gxgZzkKYGwdZ/SN
+C6gg86abKdp65/Wq5P331IbwPBal1ZhGbaAo1y7JpjpLvZytI2jboXeQuPZ8P5hU
+L3zKKceAibPKrw9+y8lb+IKoYLF7I1KYIwIDAQAB
+-----END RSA PUBLIC KEY-----
diff --git a/krebs/default.nix b/krebs/default.nix
index ad0205426..15d0e8e2e 100644
--- a/krebs/default.nix
+++ b/krebs/default.nix
@@ -36,6 +36,7 @@ let out = {
     { system ? current-host-name
     , target ? system
     }@args: let
+      config = get-config system;
     in ''
       #! /bin/sh
       # ${current-date} ${current-user-name}@${current-host-name}
@@ -47,6 +48,9 @@ let out = {
         ${builtins.readFile ./4lib/infest/install-nix.sh}
       ''}
 
+      # Prepare target source via bind-mounting
+
+
       (${nixos-install args})
 
       ${rootssh target ''
@@ -98,7 +102,7 @@ let out = {
       #! /bin/sh
       # ${current-date} ${current-user-name}@${current-host-name}
       # krebs.nixos-install
-      (${populate args})
+      (${populate (args // { root = "/mnt"; })})
 
       ${rootssh target ''
         export PATH; PATH=/root/.nix-profile/bin:$PATH
@@ -205,6 +209,7 @@ let out = {
   populate =
     { system ? current-host-name
     , target ? system
+    , root ? ""
     }@args:
     let out = ''
         #! /bin/sh
@@ -217,6 +222,7 @@ let out = {
             ["dir" "git"])}
       '';
 
+
       config = get-config system;
 
       current-host = config.krebs.hosts.${current-host-name};
@@ -225,17 +231,18 @@ let out = {
       methods.dir = config:
         let
           can-push = config.host.name == current-host.name;
+          target-path = root + config.target-path;
           push-method = ''
             rsync \
               --exclude .git \
               --exclude .graveyard \
               --exclude old \
               --exclude tmp \
-              --rsync-path='mkdir -p ${config.target-path} && rsync' \
+              --rsync-path='mkdir -p ${target-path} && rsync' \
               --delete-excluded \
               -vrLptgoD \
               ${config.path}/ \
-              root@${target}:${config.target-path}
+              root@${target}:${target-path}
           '';
         in
         if can-push then push-method else
@@ -244,9 +251,10 @@ let out = {
         throw "No way to push ${dir} from ${current-host.name} to ${target}";
 
       methods.git = config:
-        rootssh target ''
-          mkdir -p ${config.target-path}
-          cd ${config.target-path}
+        let target-path = root + config.target-path;
+        in rootssh target ''
+          mkdir -p ${target-path}
+          cd ${target-path}
           if ! test -e .git; then
             git init
           fi
diff --git a/lass/1systems/mors.nix b/lass/1systems/mors.nix
index 4ba9df6f9..61f57f1f9 100644
--- a/lass/1systems/mors.nix
+++ b/lass/1systems/mors.nix
@@ -38,6 +38,10 @@
         ../3modules/wordpress_nginx.nix
       ];
       lass.wordpress."testserver.de" = {
+        multiSite = {
+          "1" = "testserver.de";
+          "2" = "bla.testserver.de";
+        };
       };
 
       services.mysql = {
@@ -52,6 +56,27 @@
         { predicate = "-i retiolum -p tcp --dport 80"; target = "ACCEPT"; precedence = 9998; }
       ];
     }
+    {
+      #owncloud-test
+      #imports = singleton (sitesGenerators.createWordpress "testserver.de");
+      imports = [
+        ../3modules/owncloud_nginx.nix
+      ];
+      lass.owncloud."owncloud-test.de" = {
+      };
+
+      #services.mysql = {
+      #  enable = true;
+      #  package = pkgs.mariadb;
+      #  rootPassword = "<secrets>/mysql_rootPassword";
+      #};
+      networking.extraHosts = ''
+        10.243.0.2 owncloud-test.de
+      '';
+      krebs.iptables.tables.filter.INPUT.rules = [
+        { predicate = "-i retiolum -p tcp --dport 80"; target = "ACCEPT"; precedence = 9998; }
+      ];
+    }
   ];
 
   krebs.build.host = config.krebs.hosts.mors;
@@ -59,11 +84,12 @@
   networking.wireless.enable = true;
 
   networking.extraHosts = ''
-    10.243.206.102 habsys.de
-    10.243.206.102 pixelpocket.de
-    10.243.206.102 karlaskop.de
-    10.243.206.102 ubikmedia.de
-    10.243.206.102 apanowicz.de
+    213.239.205.240 wohnprojekt-rhh.de
+    213.239.205.240 karlaskop.de
+    213.239.205.240 makeup.apanowicz.de
+    213.239.205.240 pixelpocket.de
+    213.239.205.240 reich-gebaeudereinigung.de
+    213.239.205.240 o.ubikmedia.de
   '';
 
   hardware.enableAllFirmware = true;
@@ -184,7 +210,6 @@
     cac
     sshpass
     get
-    genid
     teamspeak_client
     hashPassword
   ];
diff --git a/lass/2configs/base.nix b/lass/2configs/base.nix
index 40f4e12c7..66e12b262 100644
--- a/lass/2configs/base.nix
+++ b/lass/2configs/base.nix
@@ -50,7 +50,7 @@ with lib;
       source = {
         git.nixpkgs = {
           url = https://github.com/Lassulus/nixpkgs;
-          rev = "363c8430f1efad8b03d5feae6b3a4f2fe7b29251";
+          rev = "93d8671e2c6d1d25f126ed30e5e6f16764330119";
         };
         dir.secrets = {
           host = config.krebs.hosts.mors;
diff --git a/lass/2configs/baseX.nix b/lass/2configs/baseX.nix
index 4e46c18d2..0596682df 100644
--- a/lass/2configs/baseX.nix
+++ b/lass/2configs/baseX.nix
@@ -31,10 +31,15 @@ in {
 
   environment.systemPackages = with pkgs; [
 
-    powertop
-    sxiv
+    gitAndTools.qgit
+    mpv
     much
+    pavucontrol
+    powertop
     push
+    slock
+    sxiv
+    xsel
     zathura
 
   #window manager stuff
diff --git a/lass/2configs/libvirt.nix b/lass/2configs/libvirt.nix
index 368722e77..7520a0e36 100644
--- a/lass/2configs/libvirt.nix
+++ b/lass/2configs/libvirt.nix
@@ -1,4 +1,4 @@
-{ config, pkgs, ... }:
+{ config, lib, pkgs, ... }:
 
 let
   mainUser = config.users.extraUsers.mainUser;
@@ -8,7 +8,7 @@ in {
 
   users.extraUsers = {
     libvirt = {
-      uid = 358821352; # genid libvirt
+      uid = lib.genid "libvirt";
       description = "user for running libvirt stuff";
       home = "/home/libvirt";
       useDefaultShell = true;
diff --git a/lass/2configs/skype.nix b/lass/2configs/skype.nix
index 6a226441b..d62a18a52 100644
--- a/lass/2configs/skype.nix
+++ b/lass/2configs/skype.nix
@@ -1,4 +1,4 @@
-{ config, pkgs, ... }:
+{ config, lib, pkgs, ... }:
 
 let
   mainUser = config.users.extraUsers.mainUser;
@@ -7,7 +7,7 @@ in {
   users.extraUsers = {
     skype = {
       name = "skype";
-      uid = 2259819492; #genid skype
+      uid = lib.genid "skype";
       description = "user for running skype";
       home = "/home/skype";
       useDefaultShell = true;
diff --git a/lass/2configs/weechat.nix b/lass/2configs/weechat.nix
index 18007ed61..6a257f0bb 100644
--- a/lass/2configs/weechat.nix
+++ b/lass/2configs/weechat.nix
@@ -8,7 +8,7 @@
 
   users.extraUsers.chat = {
     home = "/home/chat";
-    uid = 986764891; # genid chat
+    uid = lib.genid "chat";
     useDefaultShell = true;
     createHome = true;
     openssh.authorizedKeys.keys = [
diff --git a/lass/2configs/xserver/default.nix b/lass/2configs/xserver/default.nix
index da337f6a7..04d14c7ce 100644
--- a/lass/2configs/xserver/default.nix
+++ b/lass/2configs/xserver/default.nix
@@ -7,7 +7,6 @@ let
   user = config.users.users.mainUser;
 
   out = {
-
     services.xserver = {
       display = 11;
       tty = 11;
@@ -41,16 +40,6 @@ let
       };
     };
 
-    environment.systemPackages = [
-      pkgs.gitAndTools.qgit
-      pkgs.mpv
-      pkgs.pavucontrol
-      pkgs.slock
-      pkgs.sxiv
-      pkgs.xsel
-      pkgs.zathura
-    ];
-
     security.setuidPrograms = [
       "slock"
     ];
@@ -106,9 +95,6 @@ let
     set -efu
     export PATH; PATH=${makeSearchPath "bin" ([
       pkgs.rxvt_unicode
-      pkgs.i3lock
-      pkgs.haskellPackages.yeganesh
-      pkgs.dmenu
     ] ++ config.environment.systemPackages)}:/var/setuid-wrappers
     settle() {(
       # Use PATH for a clean journal
diff --git a/lass/3modules/newsbot-js.nix b/lass/3modules/newsbot-js.nix
index 6d87d256d..5e340b26f 100644
--- a/lass/3modules/newsbot-js.nix
+++ b/lass/3modules/newsbot-js.nix
@@ -51,7 +51,7 @@ let
   imp = {
     users.extraUsers.newsbot-js = {
       name = "newsbot-js";
-      uid = 1616759810; #genid newsbot-js
+      uid = genid "newsbot-js";
       description = "newsbot-js user";
       home = "/var/empty";
     };
diff --git a/lass/3modules/owncloud_nginx.nix b/lass/3modules/owncloud_nginx.nix
index a0db87b0b..0cb11846c 100644
--- a/lass/3modules/owncloud_nginx.nix
+++ b/lass/3modules/owncloud_nginx.nix
@@ -207,7 +207,7 @@ let
     #  };
     #});
     users.users.nobody_oc = {
-      uid = 1651469147; # genid nobody_oc
+      uid = genid "nobody_oc";
       useDefaultShell = true;
     };
   };
diff --git a/lass/3modules/wordpress_nginx.nix b/lass/3modules/wordpress_nginx.nix
index 2f31f6e02..974aacd83 100644
--- a/lass/3modules/wordpress_nginx.nix
+++ b/lass/3modules/wordpress_nginx.nix
@@ -229,7 +229,7 @@ let
       };
     });
     users.users.nobody2 = mkDefault {
-      uid = mkDefault 125816384; # genid nobody2
+      uid = mkDefault (genid "nobody2");
       useDefaultShell = mkDefault true;
     };
   };
diff --git a/lass/5pkgs/newsbot-js/default.nix b/lass/5pkgs/newsbot-js/default.nix
index ace2a976f..cabd7422c 100644
--- a/lass/5pkgs/newsbot-js/default.nix
+++ b/lass/5pkgs/newsbot-js/default.nix
@@ -26,8 +26,8 @@ in nodePackages.buildNodePackage {
 
   src = fetchgit {
     url = "http://cgit.echelon/newsbot-js/";
-    rev = "b22729670236bfa6491207d57c5d7565137625ca";
-    sha256 = "8ff00de56d85543399776c82d41d92ccc68000e5dce0f008d926748e188f3c69";
+    rev = "802b172d0eed6c9625a9cb5db408f5cc8c01784e";
+    sha256 = "794fc7845aca311f7cf7b6bdc109b5a25d0e2299322bc6612edadc477b2536e2";
   };
 
   phases = [
diff --git a/lass/5pkgs/xmonad-lass/Main.hs b/lass/5pkgs/xmonad-lass/Main.hs
index ce5afe33a..faaa00aab 100644
--- a/lass/5pkgs/xmonad-lass/Main.hs
+++ b/lass/5pkgs/xmonad-lass/Main.hs
@@ -125,6 +125,8 @@ myKeyMap =
     --, ("M4-r", spawn "exe=$(yeganesh -x) && eval \"exec $exe\"")
     , ("<XF86AudioRaiseVolume>", spawn "pactl -- set-sink-volume 0 +4%")
     , ("<XF86AudioLowerVolume>", spawn "pactl -- set-sink-volume 0 -4%")
+    , ("<XF86AudioMute>", spawn "pactl -- set-sink-mute 0 toggle")
+    , ("<XF86AudioMicMute>", spawn "pactl -- set-source-mute 1 toggle")
     , ("<XF86Launch1>", gridselectWorkspace myWSConfig W.view)
 
     , ("M4-a", focusUrgent)
diff --git a/makefu/1systems/filepimp.nix b/makefu/1systems/filepimp.nix
index 66ea2ce90..2d008cee6 100644
--- a/makefu/1systems/filepimp.nix
+++ b/makefu/1systems/filepimp.nix
@@ -9,28 +9,35 @@
     [ # Include the results of the hardware scan.
       ../2configs/fs/single-partition-ext4.nix
       ../2configs/tinc-basic-retiolum.nix
+      ../2configs/smart-monitor.nix
     ];
   krebs.build.host = config.krebs.hosts.filepimp;
-
+  services.smartd.devices = [
+    { device = "/dev/sda"; }
+    { device = "/dev/sdb"; }
+    { device = "/dev/sdc"; }
+    { device = "/dev/sdd"; }
+    { device = "/dev/sde"; }
+  ];
   # AMD N54L
   boot = {
-    loader.grub.device = "/dev/sda";
+    loader.grub.device = "/dev/sde";
 
     initrd.availableKernelModules = [
-      "usb_storage"
       "ahci"
-      "xhci_hcd"
-      "ata_piix"
-      "uhci_hcd"
+      "ohci_pci"
       "ehci_pci"
+      "pata_atiixp"
+      "usb_storage"
+      "usbhid"
     ];
 
-    kernelModules = [ ];
+    kernelModules = [ "kvm-amd" ];
     extraModulePackages = [ ];
   };
-
   hardware.enableAllFirmware = true;
   hardware.cpu.amd.updateMicrocode = true;
 
-  networking.firewall.allowPing = true;
+  zramSwap.enable = true;
+  zramSwap.numDevices = 2;
 }
diff --git a/makefu/1systems/gum.nix b/makefu/1systems/gum.nix
index 417a020fa..ac7524506 100644
--- a/makefu/1systems/gum.nix
+++ b/makefu/1systems/gum.nix
@@ -6,18 +6,22 @@ let
   internal-ip = head config.krebs.build.host.nets.retiolum.addrs4;
 in {
   imports = [
-      # TODO: copy this config or move to krebs
       ../2configs/tinc-basic-retiolum.nix
       ../2configs/headless.nix
       ../2configs/fs/simple-swap.nix
       ../2configs/fs/single-partition-ext4.nix
+      ../2configs/smart-monitor.nix
       # ../2configs/iodined.nix
       ../2configs/git/cgit-retiolum.nix
       ../2configs/mattermost-docker.nix
       ../2configs/nginx/euer.test.nix
+
+      ../2configs/exim-retiolum.nix
+      ../2configs/urlwatch.nix
+
   ];
 
-
+  services.smartd.devices = [ { device = "/dev/sda";} ];
   nixpkgs.config.packageOverrides = pkgs: { tinc = pkgs.tinc_pre; };
 
   ###### stable
@@ -28,6 +32,9 @@ in {
     ListenAddress = ${external-ip} 655
     ListenAddress = ${external-ip} 21031
   '';
+  krebs.nginx.servers.cgit.server-names = [
+    "cgit.euer.krebsco.de"
+  ];
 
   # Chat
   environment.systemPackages = with pkgs;[
diff --git a/makefu/1systems/omo.nix b/makefu/1systems/omo.nix
index 6ae79398a..552af4e4f 100644
--- a/makefu/1systems/omo.nix
+++ b/makefu/1systems/omo.nix
@@ -2,36 +2,110 @@
 # your system.  Help is available in the configuration.nix(5) man page
 # and in the NixOS manual (accessible by running ‘nixos-help’).
 
-{ config, pkgs, ... }:
-
-{
+{ config, pkgs, lib, ... }:
+let
+  byid = dev: "/dev/disk/by-id/" + dev;
+  keyFile = "/dev/disk/by-id/usb-Verbatim_STORE_N_GO_070B3CEE0B223954-0:0";
+  rootDisk = byid "ata-INTEL_SSDSA2M080G2GC_CVPO003402PB080BGN";
+  homePartition = byid "ata-INTEL_SSDSA2M080G2GC_CVPO003402PB080BGN-part3";
+  # cryptsetup luksFormat $dev --cipher aes-xts-plain64 -s 512 -h sha512
+  # cryptsetup luksAddKey $dev tmpkey
+  # cryptsetup luksOpen $dev crypt0
+  # mkfs.xfs /dev/mapper/crypt0 -L crypt0
+  cryptDisk0 = byid "ata-ST2000DM001-1CH164_Z240XTT6";
+  cryptDisk1 = byid "ata-TP02000GB_TPW151006050068";
+  cryptDisk2 = byid "ata-WDC_WD20EARS-00MVWB0_WD-WCAZA5548487";
+  # all physical disks
+  allDisks = [ rootDisk cryptDisk0 cryptDisk1 cryptDisk2 ];
+in {
   imports =
-    [ # Include the results of the hardware scan.
+    [
+      # TODO: unlock home partition via ssh
       ../2configs/fs/single-partition-ext4.nix
       ../2configs/tinc-basic-retiolum.nix
+      ../2configs/zsh-user.nix
       ../2configs/exim-retiolum.nix
+      ../2configs/smart-monitor.nix
+      ../2configs/mail-client.nix
+      ../2configs/share-user-sftp.nix
+      ../2configs/nginx/omo-share.nix
+      ../3modules
     ];
+  # services.openssh.allowSFTP = false;
   krebs.build.host = config.krebs.hosts.omo;
+  krebs.build.source.git.nixpkgs.rev = "d0e3cca04edd5d1b3d61f188b4a5f61f35cdf1ce";
+
+  # copy config from <secrets/sabnzbd.ini> to /var/lib/sabnzbd/
+  services.sabnzbd.enable = true;
+  systemd.services.sabnzbd.environment.SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
+
+  # HDD Array stuff
+  services.smartd.devices = builtins.map (x: { device = x; }) allDisks;
+
+  makefu.snapraid = let
+    toMapper = id: "/media/crypt${builtins.toString id}";
+  in {
+    enable = true;
+    disks = map toMapper [ 0 1 ];
+    parity = toMapper 2;
+  };
+  fileSystems = let
+    cryptMount = name:
+      { "/media/${name}" = { device = "/dev/mapper/${name}"; fsType = "xfs"; };};
+  in {
+    "/home" = {
+      device = "/dev/mapper/home";
+      fsType = "ext4";
+    };
+  } // cryptMount "crypt0"
+    // cryptMount "crypt1"
+    // cryptMount "crypt2";
+
+  powerManagement.powerUpCommands = lib.concatStrings (map (disk: ''
+      ${pkgs.hdparm}/sbin/hdparm -S 100 ${disk}
+      ${pkgs.hdparm}/sbin/hdparm -B 127 ${disk}
+      ${pkgs.hdparm}/sbin/hdparm -y ${disk}
+    '') allDisks);
 
-  # AMD E350
   boot = {
-    loader.grub.device = "/dev/sda";
+    initrd.luks = {
+      devices = let
+        usbkey = name: device: {
+          inherit name device keyFile;
+          keyFileSize = 4096;
+        };
+      in [
+        (usbkey "home" homePartition)
+        (usbkey "crypt0" cryptDisk0)
+        (usbkey "crypt1" cryptDisk1)
+        (usbkey "crypt2" cryptDisk2)
+      ];
+    };
+    loader.grub.device = rootDisk;
 
     initrd.availableKernelModules = [
-      "usb_storage"
       "ahci"
-      "xhci_hcd"
-      "ata_piix"
-      "uhci_hcd"
+      "ohci_pci"
       "ehci_pci"
+      "pata_atiixp"
+      "firewire_ohci"
+      "usb_storage"
+      "usbhid"
     ];
 
-    kernelModules = [ ];
+    kernelModules = [ "kvm-amd" ];
     extraModulePackages = [ ];
   };
 
+  networking.firewall.allowedUDPPorts = [ 655 ];
+  # 8080: sabnzbd
+  networking.firewall.allowedTCPPorts = [ 80 655 8080 ];
+
   hardware.enableAllFirmware = true;
   hardware.cpu.amd.updateMicrocode = true;
 
-  networking.firewall.allowPing = true;
+  zramSwap.enable = true;
+  zramSwap.numDevices = 2;
+
+
 }
diff --git a/makefu/1systems/pnp.nix b/makefu/1systems/pnp.nix
index 161bfa3e9..51c124bbe 100644
--- a/makefu/1systems/pnp.nix
+++ b/makefu/1systems/pnp.nix
@@ -1,62 +1,51 @@
-# Edit this configuration file to define what should be installed on
-# your system.  Help is available in the configuration.nix(5) man page
-# and in the NixOS manual (accessible by running ‘nixos-help’).
-
+# Usage:
+#  NIX_PATH=secrets=/home/makefu/secrets/wry:nixpkgs=/var/src/nixpkgs  nix-build -A users.makefu.pnp.config.system.build.vm
+#  result/bin/run-pnp-vm -virtfs local,path=/home/makefu/secrets/pnp,security_model=none,mount_tag=secrets
 { config, pkgs, ... }:
 
 {
   imports =
-    [ # Include the results of the hardware scan.
-      # Base
+    [
       ../2configs/tinc-basic-retiolum.nix
       ../2configs/headless.nix
+      ../../krebs/3modules/Reaktor.nix
 
-      # HW/FS
-
-      # enables virtio kernel modules in initrd
+      # these will be overwritten by qemu-vm.nix but will be used if the system
+      # is directly deployed
       <nixpkgs/nixos/modules/profiles/qemu-guest.nix>
       ../2configs/fs/vm-single-partition.nix
 
-      # Services
-      ../2configs/git/cgit-retiolum.nix
-
-      ## Reaktor
-      ## \/ are only plugins, must enable Reaktor explicitly
-      ../2configs/Reaktor/stockholmLentil.nix
-      ../2configs/Reaktor/simpleExtend.nix
-      ../2configs/Reaktor/random-emoji.nix
-      ../2configs/Reaktor/titlebot.nix
-      ../2configs/Reaktor/shack-correct.nix
-
-      ../2configs/exim-retiolum.nix
-      ../2configs/urlwatch.nix
-
-      # ../2configs/graphite-standalone.nix
+      # config.system.build.vm
+      <nixpkgs/nixos/modules/virtualisation/qemu-vm.nix>
     ];
-  krebs.urlwatch.verbose = true;
 
-  krebs.Reaktor.enable = true;
-  krebs.Reaktor.debug = true;
-  krebs.Reaktor.nickname = "Reaktor|bot";
-  krebs.Reaktor.extraEnviron = {
-    REAKTOR_CHANNELS = "#krebs,#binaergewitter,#shackspace";
+  virtualisation.graphics = false;
+  # also export secrets, see Usage above
+  fileSystems = pkgs.lib.mkVMOverride {
+    "${builtins.toString <secrets>}" =
+      { device = "secrets";
+        fsType = "9p";
+        options = "trans=virtio,version=9p2000.L,cache=loose";
+        neededForBoot = true;
+      };
+  };
+
+  krebs.Reaktor = {
+    enable = true;
+    debug = true;
+    extraEnviron = {
+      REAKTOR_HOST = "cd.retiolum";
+    };
+    plugins = with pkgs.ReaktorPlugins; [ stockholm-issue nixos-version sed-plugin ];
+    channels = [ "#retiolum" ];
   };
 
   krebs.build.host = config.krebs.hosts.pnp;
 
   nixpkgs.config.packageOverrides = pkgs: { tinc = pkgs.tinc_pre; };
 
-
   networking.firewall.allowedTCPPorts = [
-  # nginx runs on 80
-  80
-  # graphite-web runs on 8080, carbon cache runs on 2003 tcp and udp
-  # 8080 2003
-
-  # smtp
   25
   ];
 
-  # networking.firewall.allowedUDPPorts = [ 2003 ];
-
 }
diff --git a/makefu/1systems/pornocauster.nix b/makefu/1systems/pornocauster.nix
index 28b77d330..d7fa8edc5 100644
--- a/makefu/1systems/pornocauster.nix
+++ b/makefu/1systems/pornocauster.nix
@@ -26,6 +26,7 @@
       # services
       ../2configs/git/brain-retiolum.nix
       ../2configs/tor.nix
+      # ../2configs/buildbot-standalone.nix
 
       # hardware specifics are in here
       ../2configs/hw/tp-x220.nix
@@ -34,16 +35,18 @@
       # ../2configs/mediawiki.nix
       #../2configs/wordpress.nix
     ];
+  hardware.sane.enable = true;
+  hardware.sane.extraBackends = [ pkgs.samsungUnifiedLinuxDriver ];
   nixpkgs.config.packageOverrides = pkgs: {
     tinc = pkgs.tinc_pre;
-    buildbot = let
-      pkgs1509 = import (fetchTarball https://github.com/NixOS/nixpkgs-channels/archive/nixos-unstable.tar.gz) {};
-      in pkgs1509.buildbot;
   };
-  makefu.buildbot.master.enable = true;
 
-  #krebs.Reaktor.enable = true;
-  #krebs.Reaktor.nickname = "makefu|r";
+  krebs.Reaktor = {
+    enable = false;
+    nickname = "makefu|r";
+    plugins = with pkgs.ReaktorPlugins; [ nixos-version random-emoji ];
+  };
+
   # nix.binaryCaches = [ "http://acng.shack/nixos" "https://cache.nixos.org" ];
 
   environment.systemPackages = with pkgs;[
@@ -58,6 +61,7 @@
   hardware.pulseaudio.configFile = pkgs.writeText "pulse-default-pa" ''
     ${builtins.readFile "${config.hardware.pulseaudio.package}/etc/pulse/default.pa"}
     load-module module-alsa-sink device=hw:0,3 sink_properties=device.description="HDMIOutput" sink_name="HDMI"'';
+  networking.firewall.enable = false;
   networking.firewall.allowedTCPPorts = [
     25
   ];
diff --git a/makefu/1systems/vbob.nix b/makefu/1systems/vbob.nix
index a24cefd0d..b8c02cb67 100644
--- a/makefu/1systems/vbob.nix
+++ b/makefu/1systems/vbob.nix
@@ -59,7 +59,6 @@ in {
     buildbot
     buildbot-slave
     get
-    genid
   ];
 
   networking.firewall.allowedTCPPorts = [
diff --git a/makefu/1systems/wry.nix b/makefu/1systems/wry.nix
index cd2b3f657..f022311c9 100644
--- a/makefu/1systems/wry.nix
+++ b/makefu/1systems/wry.nix
@@ -18,8 +18,6 @@ in {
 
       ../2configs/iodined.nix
 
-      # Reaktor
-      ../2configs/Reaktor/simpleExtend.nix
 
       # other nginx
       ../2configs/nginx/euer.wiki.nix
@@ -29,9 +27,21 @@ in {
       # collectd
       ../2configs/collectd/collectd-base.nix
   ];
+
   krebs.build.host = config.krebs.hosts.wry;
 
-  krebs.Reaktor.enable = true;
+  krebs.Reaktor = {
+    nickname = "Reaktor|bot";
+    channels = [ "#krebs" "#shackspace" "#binaergewitter" ];
+    enable = true;
+    plugins = with pkgs.ReaktorPlugins;[
+                               titlebot
+                               # stockholm-issue
+                               nixos-version
+                               shack-correct
+                               sed-plugin
+                               random-emoji ];
+  };
 
   # bepasty to listen only on the correct interfaces
   krebs.bepasty.servers.internal.nginx.listen  = [ "${internal-ip}:80" ];
@@ -59,11 +69,11 @@ in {
   };
 
   networking = {
-  firewall = {
+    firewall = {
       allowPing = true;
       logRefusedConnections = false;
       allowedTCPPorts = [ 53 80 443 ];
-      allowedUDPPorts = [ 655 ];
+      allowedUDPPorts = [ 655 53 ];
     };
     interfaces.enp2s1.ip4 = [{
       address = external-ip;
diff --git a/makefu/2configs/Reaktor/full.nix b/makefu/2configs/Reaktor/full.nix
deleted file mode 100644
index 50620890f..000000000
--- a/makefu/2configs/Reaktor/full.nix
+++ /dev/null
@@ -1,18 +0,0 @@
-_:
-{
-  # implementation of the complete Reaktor bot
-  imports = [
-      #./stockholmLentil.nix
-      ./simpleExtend.nix
-      ./random-emoji.nix
-      ./titlebot.nix
-      ./shack-correct.nix
-      ./sed-plugin.nix
-  ];
-  krebs.Reaktor.nickname = "Reaktor|bot";
-  krebs.Reaktor.enable = true;
-
-  krebs.Reaktor.extraEnviron = {
-    REAKTOR_CHANNELS = "#krebs,#binaergewitter,#shackspace";
-  };
-}
diff --git a/makefu/2configs/Reaktor/random-emoji.nix b/makefu/2configs/Reaktor/random-emoji.nix
deleted file mode 100644
index 3113a826b..000000000
--- a/makefu/2configs/Reaktor/random-emoji.nix
+++ /dev/null
@@ -1,26 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with pkgs;
-let
-  rpkg = pkgs.substituteAll( {
-    name="random-emoji";
-    dir= "bin";
-    isExecutable=true;
-    src= ./random-emoji.sh;
-    });
-  rpkg-path = lib.makeSearchPath "bin" (with pkgs; [
-                        coreutils
-                        gnused
-                        gnugrep
-                        xmlstarlet
-                        curl]);
-in {
-  # TODO: make origin a variable, <- module is generic enough to handle different origins, not only stockholm
-  krebs.Reaktor.extraConfig = ''
-  public_commands.insert(0,{
-    'capname' : "emoji",
-    'pattern' : indirect_pattern.format("emoji"),
-    'argv'    : ["${rpkg}/bin/random-emoji"],
-    'env'     : { 'PATH':'${rpkg-path}' } })
-  '';
-}
diff --git a/makefu/2configs/Reaktor/sed-plugin.nix b/makefu/2configs/Reaktor/sed-plugin.nix
deleted file mode 100644
index a451e0d3e..000000000
--- a/makefu/2configs/Reaktor/sed-plugin.nix
+++ /dev/null
@@ -1,18 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with pkgs;
-let
-  script =  ./sed-plugin.py;
-in {
-  #TODO: this will eat up the last regex, fix Reaktor
-  krebs.Reaktor.extraConfig = ''
-  public_commands.append({
-    'capname' : "sed-plugin",
-    # only support s///gi
-    'pattern' : '^(?P<args>.*)$$',
-    'argv'    : ["${pkgs.python3}/bin/python3","${script}"],
-    'env'     : { 'state_dir' : workdir,
-                  'PATH':'${lib.makeSearchPath "bin" [pkgs.gnused]}' }})
-  '';
-}
-
diff --git a/makefu/2configs/Reaktor/shack-correct.nix b/makefu/2configs/Reaktor/shack-correct.nix
deleted file mode 100644
index 8f30807f1..000000000
--- a/makefu/2configs/Reaktor/shack-correct.nix
+++ /dev/null
@@ -1,20 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with pkgs;
-let
-  script = pkgs.substituteAll ( {
-    name="shack-correct";
-    isExecutable=true;
-    dir = "";
-    src = ./shack-correct.sh;
-    });
-in {
-  krebs.Reaktor.extraConfig = ''
-  public_commands.insert(0,{
-    'capname' : "shack-correct",
-    'pattern' : '^(?P<args>.*Shack.*)$$',
-    'argv'    : ["${script}"],
-    'env'     : {  }})
-  '';
-}
-
diff --git a/makefu/2configs/Reaktor/simpleExtend.nix b/makefu/2configs/Reaktor/simpleExtend.nix
deleted file mode 100644
index 95175a4e0..000000000
--- a/makefu/2configs/Reaktor/simpleExtend.nix
+++ /dev/null
@@ -1,19 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with pkgs;
-let
-  nixos-version-script = pkgs.writeScript "nix-version" ''
-  #! /bin/sh
-  . /etc/os-release
-  echo "$PRETTY_NAME"
-  '';
-in {
-  krebs.Reaktor.extraConfig = ''
-  public_commands.insert(0,{
-    'capname' : "nixos-version",
-    'pattern' : indirect_pattern.format("nixos-version"),
-    'argv'    : ["${nixos-version-script}"],
-    'env'     : { 'state_dir': workdir } })
-  '';
-}
-
diff --git a/makefu/2configs/Reaktor/stockholmLentil.nix b/makefu/2configs/Reaktor/stockholmLentil.nix
deleted file mode 100644
index 21f0305fb..000000000
--- a/makefu/2configs/Reaktor/stockholmLentil.nix
+++ /dev/null
@@ -1,27 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with pkgs;
-let
-  random-issue = pkgs.substituteAll( {
-    name="random-issue";
-    dir= "bin";
-    isExecutable=true;
-    src= ./random-issue.sh;
-    });
-  random-issue-path = lib.makeSearchPath "bin" (with pkgs; [
-                        coreutils
-                        git
-                        gnused
-                        lentil]);
-in {
-  # TODO: make origin a variable, <- module is generic enough to handle different origins, not only stockholm
-  krebs.Reaktor.extraConfig = ''
-  public_commands.insert(0,{
-    'capname' : "stockholm-issue",
-    'pattern' : indirect_pattern.format("stockholm-issue"),
-    'argv'    : ["${random-issue}/bin/random-issue"],
-    'env'     : { 'state_dir': workdir,
-                  'PATH':'${random-issue-path}',
-                  'origin':'http://cgit.pnp/stockholm' } })
-  '';
-}
diff --git a/makefu/2configs/Reaktor/titlebot.nix b/makefu/2configs/Reaktor/titlebot.nix
deleted file mode 100644
index 9ef02548b..000000000
--- a/makefu/2configs/Reaktor/titlebot.nix
+++ /dev/null
@@ -1,38 +0,0 @@
-{ stdenv,config, lib, pkgs, ... }:
-
-with pkgs;
-let
-  pypkgs = pkgs.python3Packages;
-  titlebot_cmds =  pypkgs.buildPythonPackage {
-    name = "titlebot_cmds";
-    propagatedBuildInputs =  with pypkgs; [ setuptools ];
-    src = fetchurl {
-      # https://github.com/makefu/reaktor-titlebot tag 2.1.0
-      url = "https://github.com/makefu/reaktor-titlebot/archive/2.1.0.tar.gz";
-      sha256 = "0wvf09wmk8b52f9j65qrw81nwrhs9pfhijwrlkzp5l7l2q8cjkp6";
-      };
-    };
-  pub_cmds = ["up" "help" "list" "top" "highest" "undo" ];
-  priv_cmds = [ "clear" ];
-in {
-  # TODO: write identify file in
-  #     {config.users.extraUsers.Reaktor.home}/state/admin.lst
-  krebs.Reaktor.extraConfig = ''
-  def titlebot_cmd(cmd):
-    return {
-      'capname': cmd,
-      'env': {
-        'TITLEDB':
-          '${config.users.extraUsers.Reaktor.home}/suggestions.json'
-        },
-      'pattern': '^\\.' + cmd + '\\s*(?:\\s+(?P<args>.*))?$$',
-      'argv': [ '${titlebot_cmds}/bin/' + cmd ] }
-  # TODO: for each element in ${titlebot_cmds}/bin/*
-  public_commands.insert(0,titlebot_cmd('up'))
-  public_commands.insert(0,titlebot_cmd('help'))
-  public_commands.insert(0,titlebot_cmd('list'))
-  public_commands.insert(0,titlebot_cmd('top'))
-  public_commands.insert(0,titlebot_cmd('new'))
-  commands.insert(0,titlebot_cmd('clear'))
-  '';
-}
diff --git a/makefu/2configs/default.nix b/makefu/2configs/default.nix
index a0b49edaf..ec1100582 100644
--- a/makefu/2configs/default.nix
+++ b/makefu/2configs/default.nix
@@ -13,7 +13,7 @@ with lib;
     ./vim.nix
   ];
 
-
+  nixpkgs.config.allowUnfreePredicate =  (pkg: pkgs.lib.hasPrefix "unrar-" pkg.name);
   krebs = {
     enable = true;
     search-domain = "retiolum";
@@ -23,8 +23,8 @@ with lib;
       source = {
         git.nixpkgs = {
           #url = https://github.com/NixOS/nixpkgs;
-          url = mkDefault https://github.com/makefu/nixpkgs;
-          rev = mkDefault "3fd2c24685f604edc925f73ed56600b8c66236b3"; # nixos-15.09 + cherry-picking
+          url = mkDefault https://github.com/nixos/nixpkgs;
+          rev = mkDefault "93d8671e2c6d1d25f126ed30e5e6f16764330119"; # unstable @ 2015-01-03, tested on filepimp
           target-path = "/var/src/nixpkgs";
         };
 
@@ -65,7 +65,12 @@ with lib;
   time.timeZone = "Europe/Berlin";
   #nix.maxJobs = 1;
 
-  programs.ssh.startAgent = false;
+  programs.ssh = {
+    startAgent = false;
+    extraConfig = ''
+      UseRoaming no
+    '';
+  };
   services.openssh.enable = true;
   nix.useChroot = true;
 
diff --git a/makefu/2configs/hw/tp-x2x0.nix b/makefu/2configs/hw/tp-x2x0.nix
index 047895ce6..ebc72a06e 100644
--- a/makefu/2configs/hw/tp-x2x0.nix
+++ b/makefu/2configs/hw/tp-x2x0.nix
@@ -24,5 +24,12 @@ with lib;
   services.tlp.enable = true;
   services.tlp.extraConfig = ''
   START_CHARGE_THRESH_BAT0=80
+
+  CPU_SCALING_GOVERNOR_ON_AC=performance
+  CPU_SCALING_GOVERNOR_ON_BAT=ondemand
+  CPU_MIN_PERF_ON_AC=0
+  CPU_MAX_PERF_ON_AC=100
+  CPU_MIN_PERF_ON_BAT=0
+  CPU_MAX_PERF_ON_BAT=30
   '';
 }
diff --git a/makefu/2configs/mail-client.nix b/makefu/2configs/mail-client.nix
index a6ae33d2f..bda21e9d0 100644
--- a/makefu/2configs/mail-client.nix
+++ b/makefu/2configs/mail-client.nix
@@ -7,6 +7,8 @@ with lib;
     mutt-kz
     notmuch
     offlineimap
+    imapfilter
+    gnupg
   ];
 
 }
diff --git a/makefu/2configs/nginx/omo-share.nix b/makefu/2configs/nginx/omo-share.nix
new file mode 100644
index 000000000..ce85e0442
--- /dev/null
+++ b/makefu/2configs/nginx/omo-share.nix
@@ -0,0 +1,34 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+  hostname = config.krebs.build.host.name;
+  # TODO local-ip from the nets config
+  local-ip = "192.168.1.11";
+  # local-ip = head config.krebs.build.host.nets.retiolum.addrs4;
+in {
+  krebs.nginx = {
+    enable = mkDefault true;
+    servers = {
+      omo-share = {
+        listen = [ "${local-ip}:80" ];
+        locations = singleton (nameValuePair "/" ''
+          autoindex on;
+          root /media;
+          limit_rate_after 100m;
+          limit_rate 5m;
+          mp4_buffer_size     4M;
+          mp4_max_buffer_size 10M;
+          allow all;
+          access_log off;
+          keepalive_timeout  65;
+          keepalive_requests 200;
+          reset_timedout_connection on;
+          sendfile on;
+          tcp_nopush on;
+          gzip off;
+        '');
+      };
+    };
+  };
+}
diff --git a/makefu/2configs/share-user-sftp.nix b/makefu/2configs/share-user-sftp.nix
new file mode 100644
index 000000000..2c93143ec
--- /dev/null
+++ b/makefu/2configs/share-user-sftp.nix
@@ -0,0 +1,21 @@
+{ config, ... }:
+
+{
+  users.users = {
+    share = {
+      uid = 9002;
+      home = "/var/empty";
+      openssh.authorizedKeys.keys = [ config.krebs.users.makefu.pubkey ];
+    };
+  };
+  # we will use internal-sftp to make uncomplicated Chroot work
+  services.openssh.extraConfig = ''
+    Match User share
+      ChrootDirectory /media
+      ForceCommand internal-sftp
+      AllowTcpForwarding no
+      PermitTunnel no
+      X11Forwarding no
+    Match All
+  '';
+}
diff --git a/makefu/2configs/smart-monitor.nix b/makefu/2configs/smart-monitor.nix
new file mode 100644
index 000000000..daf3aad01
--- /dev/null
+++ b/makefu/2configs/smart-monitor.nix
@@ -0,0 +1,18 @@
+{ config, lib, ... }:
+{
+  krebs.exim-retiolum.enable = lib.mkDefault true;
+  services.smartd = {
+    enable = true;
+    autodetect = false;
+    notifications = {
+      mail = {
+        enable = true;
+        recipient = config.krebs.users.makefu.mail;
+      };
+    };
+    # short daily, long weekly, check on boot
+    defaults.monitored = "-a -o on -s (S/../.././02|L/../../7/04)";
+
+    devices = lib.mkDefault [ ];
+  };
+}
diff --git a/makefu/2configs/urlwatch.nix b/makefu/2configs/urlwatch.nix
index cd05f0114..a83279ba2 100644
--- a/makefu/2configs/urlwatch.nix
+++ b/makefu/2configs/urlwatch.nix
@@ -1,6 +1,22 @@
-{ config, ... }:
+{ config, lib, ... }:
 
 {
+  nixpkgs.config.packageOverrides = pkgs: {
+    urlwatch = with pkgs.pythonPackages; buildPythonPackage rec {
+      name = "urlwatch-1.18";
+
+      propagatedBuildInputs =  [ futures ];
+
+      src = pkgs.fetchurl {
+        url = "http://thp.io/2008/urlwatch/${name}.tar.gz";
+        sha256 = "090qfgx249ks7103sap6w47f8302ix2k46wxhfssxwsqcqdl25vb";
+      };
+
+      postFixup = ''
+        wrapProgram "$out/bin/urlwatch" --prefix "PYTHONPATH" : "$PYTHONPATH"
+      '';
+    };
+  };
   krebs.urlwatch = {
     enable = true;
     mailto = config.krebs.users.makefu.mail;
@@ -12,7 +28,7 @@
       http://git.sysphere.org/vicious/log/?qt=grep&q=Next+release
       https://pypi.python.org/simple/bepasty/
       https://pypi.python.org/simple/xstatic/
-
+      http://guest:derpi@cvs2svn.tigris.org/svn/cvs2svn/tags/
     ];
   };
 }
diff --git a/makefu/2configs/vim.nix b/makefu/2configs/vim.nix
index 02a46d22a..227d73c81 100644
--- a/makefu/2configs/vim.nix
+++ b/makefu/2configs/vim.nix
@@ -122,7 +122,7 @@ in {
       vimrcConfig.vam.knownPlugins = pkgs.vimPlugins // customPlugins;
       vimrcConfig.vam.pluginDictionaries = [
         { names = [ "undotree"
-          "YouCompleteMe"
+          # "YouCompleteMe"
           "vim-better-whitespace" ]; }
         { names = [ "vim-addon-nix" ]; ft_regex = "^nix\$"; }
       ];
diff --git a/makefu/2configs/virtualization.nix b/makefu/2configs/virtualization.nix
index b3f8c8284..b90467ab8 100644
--- a/makefu/2configs/virtualization.nix
+++ b/makefu/2configs/virtualization.nix
@@ -5,4 +5,5 @@ let
 in {
   virtualisation.libvirtd.enable = true;
   users.extraUsers.${mainUser.name}.extraGroups = [ "libvirtd" ];
+  networking.firewall.checkReversePath = false; # TODO: unsolved issue in nixpkgs:#9067 [bug]
 }
diff --git a/makefu/2configs/wwan.nix b/makefu/2configs/wwan.nix
index 29a610ac6..1e76cd28a 100644
--- a/makefu/2configs/wwan.nix
+++ b/makefu/2configs/wwan.nix
@@ -1,33 +1,9 @@
-{ config, lib, pkgs, ... }:
+_:
 
-#usage: $ wvdial
-
-let
-  mainUser = config.krebs.build.user;
-in {
-  environment.systemPackages = with pkgs;[
-    wvdial
-  ];
-
-  environment.shellAliases = {
-    umts = "sudo wvdial netzclub";
+{
+  imports = [ ../3modules ];
+  makefu.umts = {
+    enable = true;
+    modem-device = "/dev/serial/by-id/usb-Lenovo_H5321_gw_2D5A51BA0D3C3A90-if01";
   };
-
-  # configure for NETZCLUB
-  environment.wvdial.dialerDefaults = ''
-    Phone = *99***1#
-    Dial Command = ATDT
-    Modem = /dev/ttyACM0
-    Baud = 460800
-    Init1 = AT+CGDCONT=1,"IP","pinternet.interkom.de","",0,0
-    Init2 = ATZ
-    Init3 = ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0
-    ISDN = 0
-    Modem Type = Analog Modem
-    Username = netzclub
-    Password = netzclub
-    Stupid Mode = 1
-    Idle Seconds = 0'';
-
-  users.extraUsers.${mainUser.name}.extraGroups = [ "dialout" ];
 }
diff --git a/makefu/2configs/zsh-user.nix b/makefu/2configs/zsh-user.nix
index 1b1762418..f79f258f3 100644
--- a/makefu/2configs/zsh-user.nix
+++ b/makefu/2configs/zsh-user.nix
@@ -19,8 +19,7 @@ in
       bindkey -e
       # shift-tab
       bindkey '^[[Z' reverse-menu-complete
-
-      autoload -U compinit && compinit
+      bindkey "\e[3~" delete-char
       zstyle ':completion:*' menu select
 
       # load gpg-agent
diff --git a/makefu/3modules/buildbot/master.nix b/makefu/3modules/buildbot/master.nix
deleted file mode 100644
index 58e2f8175..000000000
--- a/makefu/3modules/buildbot/master.nix
+++ /dev/null
@@ -1,263 +0,0 @@
-{ config, pkgs, lib, ... }:
-
-with lib;
-let
-  buildbot = pkgs.buildbot;
-  buildbot-master-config = pkgs.writeText "buildbot-master.cfg" ''
-    # -*- python -*-
-    from buildbot.plugins import *
-    import re
-
-    c = BuildmasterConfig = {}
-
-    c['slaves'] = []
-    # TODO: template potential buildslaves
-    # TODO: set password?
-    slavenames= [ 'testslave' ]
-    for i in slavenames:
-      c['slaves'].append(buildslave.BuildSlave(i, "krebspass"))
-
-    c['protocols'] = {'pb': {'port': 9989}}
-
-    ####### Build Inputs
-    stockholm_repo = 'http://cgit.gum/stockholm'
-    c['change_source'] = []
-    c['change_source'].append(changes.GitPoller(
-            stockholm_repo,
-            workdir='stockholm-poller', branch='master',
-            project='stockholm',
-            pollinterval=120))
-
-    ####### Build Scheduler
-    # TODO: configure scheduler
-    c['schedulers'] = []
-
-    # test the master real quick
-    fast = schedulers.SingleBranchScheduler(
-                                change_filter=util.ChangeFilter(branch="master"),
-                                name="fast-master-test",
-                                builderNames=["fast-tests"])
-
-    force = schedulers.ForceScheduler(
-                                name="force",
-                                builderNames=["full-tests"])
-
-    # files everyone depends on or are part of the share branch
-    def shared_files(change):
-      r =re.compile("^((krebs|share)/.*|Makefile|default.nix)")
-      for file in change.files:
-        if r.match(file):
-          return True
-      return False
-
-    full = schedulers.SingleBranchScheduler(
-                                change_filter=util.ChangeFilter(branch="master"),
-                                fileIsImportant=shared_files,
-                                name="full-master-test",
-                                builderNames=["full-tests"])
-    c['schedulers'] = [ fast, force, full ]
-    ###### The actual build
-    # couple of fast steps:
-    f = util.BuildFactory()
-    ## fetch repo
-    grab_repo = steps.Git(repourl=stockholm_repo, mode='incremental')
-    f.addStep(grab_repo)
-
-    # the dependencies which are used by the test script
-    deps = [ "gnumake", "jq" ]
-    nixshell = ["nix-shell", "-p" ] + deps + [ "--run" ]
-    def addShell(f,**kwargs):
-      f.addStep(steps.ShellCommand(**kwargs))
-
-    addShell(f,name="centos7-eval",env={"LOGNAME": "shared",
-                  "get" : "krebs.deploy",
-                  "filter" : "json"
-                 },
-             command=nixshell + ["make -s eval system=test-centos7"])
-
-    addShell(f,name="wolf-eval",env={"LOGNAME": "shared",
-                  "get" : "krebs.deploy",
-                  "filter" : "json"
-                 },
-             command=nixshell + ["make -s eval system=wolf"])
-
-    c['builders'] = []
-    c['builders'].append(
-        util.BuilderConfig(name="fast-tests",
-          slavenames=slavenames,
-          factory=f))
-
-    # TODO slow build
-    c['builders'].append(
-        util.BuilderConfig(name="full-tests",
-          slavenames=slavenames,
-          factory=f))
-
-    ####### Status of Builds
-    c['status'] = []
-
-    from buildbot.status import html
-    from buildbot.status.web import authz, auth
-    # TODO: configure if http is wanted
-    authz_cfg=authz.Authz(
-        # TODO: configure user/pw
-        auth=auth.BasicAuth([("krebs","bob")]),
-        gracefulShutdown = False,
-        forceBuild = 'auth',
-        forceAllBuilds = 'auth',
-        pingBuilder = False,
-        stopBuild = False,
-        stopAllBuilds = False,
-        cancelPendingBuild = False,
-    )
-    # TODO: configure nginx
-    c['status'].append(html.WebStatus(http_port=8010, authz=authz_cfg))
-
-    from buildbot.status import words
-    ${optionalString (cfg.irc.enable) ''
-      irc = words.IRC("${cfg.irc.server}", "krebsbuild",
-                      # TODO: multiple channels
-                      channels=["${cfg.irc.channel}"],
-                      notify_events={
-                        #'success': 1,
-                        #'failure': 1,
-                        'exception': 1,
-                        'successToFailure': 1,
-                        'failureToSuccess': 1,
-                      }${optionalString cfg.irc.allowForce ",allowForce=True"})
-      c['status'].append(irc)
-      ''}
-
-    ####### PROJECT IDENTITY
-    c['title'] = "Stockholm"
-    c['titleURL'] = "http://krebsco.de"
-
-    #c['buildbotURL'] = "http://buildbot.krebsco.de/"
-    # TODO: configure url
-    c['buildbotURL'] = "http://vbob:8010/"
-
-    ####### DB URL
-    c['db'] = {
-        'db_url' : "sqlite:///state.sqlite",
-    }
-    ${cfg.extraConfig}
-    '';
-
-  cfg = config.makefu.buildbot.master;
-
-  api = {
-    enable = mkEnableOption "Buildbot Master";
-    workDir = mkOption {
-      default = "/var/lib/buildbot/master";
-      type = types.str;
-      description = ''
-        Path to build bot master directory.
-        Will be created on startup.
-      '';
-    };
-    irc = mkOption {
-      default = {};
-      type = types.submodule ({ config, ... }: {
-        options = {
-          enable = mkEnableOption "Buildbot Master IRC Status";
-          channel = mkOption {
-            default = "nix-buildbot-meetup";
-            type = types.str;
-            description = ''
-              irc channel the bot should connect to
-            '';
-          };
-          allowForce = mkOption {
-            default = false;
-            type = types.bool;
-            description = ''
-              Determines if builds can be forced via IRC
-            '';
-          };
-          nick = mkOption {
-            default = "nix-buildbot";
-            type = types.str;
-            description = ''
-              nickname for IRC
-            '';
-          };
-          server = mkOption {
-            default = "irc.freenode.net";
-            type = types.str;
-            description = ''
-              Buildbot Status IRC Server to connect to
-            '';
-          };
-        };
-      });
-    };
-
-    extraConfig = mkOption {
-      default = "";
-      type = types.lines;
-      description = ''
-        extra config appended to the generated master.cfg
-      '';
-    };
-  };
-
-  imp = {
-
-    users.extraUsers.buildbotMaster = {
-      uid = 672626386; #genid buildbotMaster
-      description = "Buildbot Master";
-      home = cfg.workDir;
-      createHome = false;
-    };
-
-    users.extraGroups.buildbotMaster = {
-      gid = 672626386;
-    };
-
-    systemd.services.buildbotMaster = {
-      description = "Buildbot Master";
-      after = [ "network.target" ];
-      wantedBy = [ "multi-user.target" ];
-      path = [ pkgs.git ];
-      serviceConfig = let
-        workdir="${lib.shell.escape cfg.workDir}";
-        # TODO: check if git is the only dep
-      in {
-        PermissionsStartOnly = true;
-        Type = "forking";
-        PIDFile = "${workdir}/twistd.pid";
-        # TODO: maybe also prepare buildbot.tac?
-        ExecStartPre = pkgs.writeScript "buildbot-master-init" ''
-          #!/bin/sh
-          set -efux
-          if [ ! -e ${workdir} ];then
-            mkdir -p ${workdir}
-            ${buildbot}/bin/buildbot create-master -r -l 10 -f ${workdir}
-          fi
-          # always override the master.cfg
-          cp ${buildbot-master-config} ${workdir}/master.cfg
-          # sanity
-          ${buildbot}/bin/buildbot checkconfig ${workdir}
-
-          # TODO: maybe upgrade? not sure about this
-          #       normally we should write buildbot.tac by our own
-          # ${buildbot}/bin/buildbot upgrade-master ${workdir}
-
-          chmod 700 -R ${workdir}
-          chown buildbotMaster:buildbotMaster -R ${workdir}
-        '';
-        ExecStart = "${buildbot}/bin/buildbot start ${workdir}";
-        ExecStop = "${buildbot}/bin/buildbot stop ${workdir}";
-        ExecReload = "${buildbot}/bin/buildbot reconfig ${workdir}";
-        PrivateTmp = "true";
-        User = "buildbotMaster";
-        Restart = "always";
-        RestartSec = "10";
-      };
-    };
-  };
-in
-{
-  options.makefu.buildbot.master = api;
-  config = mkIf cfg.enable imp;
-}
diff --git a/makefu/3modules/default.nix b/makefu/3modules/default.nix
index ffbf54cc0..f007a8418 100644
--- a/makefu/3modules/default.nix
+++ b/makefu/3modules/default.nix
@@ -2,8 +2,8 @@ _:
 
 {
   imports = [
-    ./buildbot/master.nix
-    ./buildbot/slave.nix
+    ./snapraid.nix
+    ./umts.nix
   ];
 }
 
diff --git a/makefu/3modules/snapraid.nix b/makefu/3modules/snapraid.nix
new file mode 100644
index 000000000..fbdf50219
--- /dev/null
+++ b/makefu/3modules/snapraid.nix
@@ -0,0 +1,125 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  # returns dirname without / , used as disk name
+  dname = dir: replaceChars ["/"] [""] (head (reverseList (splitString "/" dir)));
+  snapraid-conf = ''
+    # Disks
+    ${concatMapStringsSep "\n" (d: "disk ${dname d} ${d}")  cfg.disks}
+    # Parity
+    ${optionalString (cfg.parity != "") "parity ${cfg.parity}/snapraid.parity"}
+
+    # content on Disks
+    ${optionalString cfg.contentOnDisks
+      concatMapStringsSep "\n" (d: "content ${d}/snapraid.content")  cfg.disks}
+
+    # content on Parity
+    ${optionalString (cfg.contentOnParity && cfg.parity != "")
+      "content ${cfg.parity}/snapraid.content"}
+    # Default content file
+    content ${cfg.defaultContentFile}
+
+    # Extra Configuration
+    ${cfg.extraConfig}
+  '';
+  cfg = config.makefu.snapraid;
+
+  out = {
+    options.makefu.snapraid = api;
+    config = mkIf cfg.enable imp;
+  };
+
+  api = {
+    enable = mkEnableOption "snapraid";
+
+    timerConfig = mkOption {
+      type = types.unspecified;
+      description = ''
+        Start snapraid service
+      '';
+      default = {
+        OnCalendar = "daily";
+      };
+    };
+    disks = mkOption {
+      type = with types;listOf str;
+      description = ''
+        Disks to protect. Each disk is a path to the mounted directory of the
+        disk.
+      '';
+    };
+    parity = mkOption {
+      type = types.str;
+      description = ''
+        Folder to store parity file.
+        Set to empty string if you want to configure the parity yourself in
+        extraConfig.
+
+        All extra parity files (2,3,z, etc...) should be configured via
+        extraConfig.
+      '';
+    };
+    contentOnDisks = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Store Content file on each Disk to protect.
+        Set this to false if you do not want this behavior to apply.
+      '';
+    };
+    contentOnParity = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Store Content file on parity Disk.
+        Set this to false if you do not want this behavior to apply.
+      '';
+    };
+    defaultContentFile = mkOption {
+      type = types.str;
+      default = "/var/cache/snapraid.content";
+      description = ''
+        Path to default content file
+        Set to empty string if this content file should be written.
+      '';
+    };
+    extraConfig = mkOption {
+      type = types.string;
+      default = "";
+      description = ''
+        Extra configuration to be appended to the snapraid conf file.
+        You can configure extra Parity files as well as extra content files.
+        See `man snapraid` for additional configuration
+      '';
+    };
+  };
+
+  imp = {
+    environment.systemPackages = [
+      # for scrubbing,fixing
+      pkgs.snapraid
+    ];
+    environment.etc."snapraid.conf".text = snapraid-conf;
+    systemd.timers.snapraid-sync = {
+      description = "snapraid sync timer";
+      wantedBy = [ "timers.target" ];
+      timerConfig = cfg.timerConfig;
+    };
+    systemd.services.snapraid-sync = {
+      description = "Snapraid sync service";
+      after = [ "network.target" "local-fs.target" ];
+
+      serviceConfig = {
+        Type = "simple";
+        ExecStartPre = pkgs.writeScript "Snapraid-sync-init" ''
+          #! /bin/sh
+          ${optionalString (cfg.defaultContentFile != "")
+            "mkdir -p $(dirname ${cfg.defaultContentFile})"}
+        '';
+        ExecStart = "${pkgs.snapraid}/bin/snapraid sync";
+      };
+    };
+  };
+in out
diff --git a/makefu/3modules/umts.nix b/makefu/3modules/umts.nix
new file mode 100644
index 000000000..d7be45f62
--- /dev/null
+++ b/makefu/3modules/umts.nix
@@ -0,0 +1,76 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  # TODO: currently it is only netzclub
+  umts-bin = pkgs.writeScriptBin "umts" ''
+    #!/bin/sh
+    set -euf
+    systemctl start umts
+    trap "systemctl stop umts;trap - INT TERM EXIT;exit" INT TERM EXIT
+    echo nameserver 8.8.8.8 | tee -a /etc/resolv.conf
+    journalctl -xfu umts
+  '';
+
+  wvdial-defaults = ''
+    Phone = *99***1#
+    Dial Command = ATDT
+    Modem = ${cfg.modem-device}
+    Baud = 460800
+    Init1 = AT+CGDCONT=1,"IP","pinternet.interkom.de","",0,0
+    Init2 = ATZ
+    Init3 = ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0
+    ISDN = 0
+    Modem Type = Analog Modem
+    Username = netzclub
+    Password = netzclub
+    Stupid Mode = 1
+    Idle Seconds = 0'';
+
+  cfg = config.makefu.umts;
+
+  out = {
+    options.makefu.umts = api;
+    config = mkIf cfg.enable imp;
+  };
+
+  api = {
+    enable = mkEnableOption "umts";
+
+    modem-device = mkOption {
+      default = "/dev/ttyUSB0";
+      type = types.str;
+      description = ''
+        path to modem device, use <filename>/dev/serial/by-id/...</filename>
+        to avoid race conditions.
+      '';
+    };
+  };
+
+  imp = {
+    environment.shellAliases = {
+      umts = "sudo ${umts-bin}/bin/umts";
+    };
+    environment.systemPackages = [ ];
+
+    environment.wvdial.dialerDefaults = wvdial-defaults;
+
+    systemd.targets.network-umts = {
+      description = "System is running on UMTS";
+      unitConfig.StopWhenUnneeded = true;
+    };
+
+    systemd.services.umts = {
+      description = "UMTS wvdial Service";
+      before = [ "network-umts.target" ];
+
+      serviceConfig = {
+        Type = "simple";
+        Restart = "always";
+        RestartSec = "4s";
+        ExecStart = "${pkgs.wvdial}/bin/wvdial -n";
+      };
+    };
+  };
+in out
diff --git a/shared/1systems/test-all-krebs-modules.nix b/shared/1systems/test-all-krebs-modules.nix
new file mode 100644
index 000000000..b98004dfe
--- /dev/null
+++ b/shared/1systems/test-all-krebs-modules.nix
@@ -0,0 +1,45 @@
+{ config, pkgs, lib, ... }:
+let
+  en = { enable = true;};
+in {
+  krebs = {
+    enable = true;
+    build.user = config.krebs.users.shared;
+    build.host = config.krebs.hosts.test-all-krebs-modules;
+    Reaktor.enable = true;
+    apt-cacher-ng.enable = true;
+    backup.enable = true;
+    bepasty.enable = true;
+    buildbot.master.enable = true;
+    buildbot.slave = {
+      enable = true;
+      username = "lol";
+      password = "wut";
+    };
+    exim-retiolum.enable = true;
+    exim-smarthost = {
+      enable = true;
+      system-aliases = [ { from = "dick"; to = "butt"; } ];
+    };
+    go.enable = true;
+    iptables = {
+      enable = true;
+      tables = {};
+    };
+    nginx.enable = true;
+    realwallpaper.enable = true;
+    retiolum.enable = true;
+    retiolum-bootstrap.enable = true;
+    tinc_graphs.enable = true;
+    urlwatch.enable = true;
+    fetchWallpaper = {
+      enable = true;
+      url ="localhost";
+    };
+  };
+  # just get the system running
+  boot.loader.grub.devices = ["/dev/sda"];
+  fileSystems."/" = {
+    device = "/dev/lol";
+  };
+}
diff --git a/shared/1systems/test-failing.nix b/shared/1systems/test-failing.nix
new file mode 100644
index 000000000..81a9e48d6
--- /dev/null
+++ b/shared/1systems/test-failing.nix
@@ -0,0 +1,6 @@
+{ config, pkgs, ... }:
+
+{
+  programs.ssh.startAgent = true;
+  programs.ssh.startAgent = false;
+}
diff --git a/shared/1systems/test-minimal-deploy.nix b/shared/1systems/test-minimal-deploy.nix
new file mode 100644
index 000000000..309e28950
--- /dev/null
+++ b/shared/1systems/test-minimal-deploy.nix
@@ -0,0 +1,13 @@
+{ config, pkgs, lib, ... }:
+{
+  krebs = {
+    enable = true;
+    build.user = config.krebs.users.shared;
+    build.host = config.krebs.hosts.test-all-krebs-modules;
+  };
+  # just get the system to eval in nixos without errors
+  boot.loader.grub.devices = ["/dev/sda"];
+  fileSystems."/" = {
+    device = "/dev/lol";
+  };
+}
diff --git a/shared/1systems/wolf.nix b/shared/1systems/wolf.nix
index 2c51ac8fe..f05356f0f 100644
--- a/shared/1systems/wolf.nix
+++ b/shared/1systems/wolf.nix
@@ -11,7 +11,7 @@ in
     ../2configs/collectd-base.nix
     ../2configs/shack-nix-cacher.nix
     ../2configs/shack-drivedroid.nix
-    ../2configs/cac-ci.nix
+    ../2configs/buildbot-standalone.nix
     ../2configs/graphite.nix
   ];
   # use your own binary cache, fallback use cache.nixos.org (which is used by
@@ -33,8 +33,6 @@ in
   # uninteresting stuff
   #####################
   krebs.build.host = config.krebs.hosts.wolf;
-  # TODO rename shared user to "krebs"
-  krebs.build.user = config.krebs.users.shared;
   krebs.build.target = "wolf";
 
   boot.kernel.sysctl = {
diff --git a/shared/2configs/base.nix b/shared/2configs/base.nix
index c36061e38..4d509d7a6 100644
--- a/shared/2configs/base.nix
+++ b/shared/2configs/base.nix
@@ -14,11 +14,12 @@ with lib;
   };
 
   # TODO rename shared user to "krebs"
-  krebs.build.user = config.krebs.users.shared;
+  krebs.build.user = mkDefault config.krebs.users.shared;
   krebs.build.source = {
     git.nixpkgs = {
       url = https://github.com/NixOS/nixpkgs;
       rev = "6d31e9b81dcd4ab927bb3dc91b612dd5abfa2f80";
+      target-path = "/var/src/nixpkgs";
     };
     dir.secrets = {
       host = config.krebs.current.host;
@@ -27,6 +28,7 @@ with lib;
     dir.stockholm = {
       host = config.krebs.current.host;
       path = mkDefault "${getEnv "HOME"}/stockholm";
+      target-path = "/var/src/stockholm";
     };
   };
 
diff --git a/shared/2configs/buildbot-standalone.nix b/shared/2configs/buildbot-standalone.nix
new file mode 100644
index 000000000..3275189a5
--- /dev/null
+++ b/shared/2configs/buildbot-standalone.nix
@@ -0,0 +1,155 @@
+{ lib, config, pkgs, ... }:
+let
+    pkgs-unst = import (fetchTarball https://github.com/NixOS/nixpkgs-channels/archive/nixos-unstable.tar.gz) {};
+in {
+  nixpkgs.config.packageOverrides = pkgs: {
+    buildbot = pkgs-unst.buildbot;
+    buildbot-slave = pkgs-unst.buildbot-slave;
+  };
+  networking.firewall.allowedTCPPorts = [ 8010 9989 ];
+  krebs.buildbot.master = {
+    secrets = [ "retiolum-ci.rsa_key.priv" "cac.json" ];
+    slaves = {
+      testslave =  "krebspass";
+    };
+    change_source.stockholm = ''
+  stockholm_repo = 'http://cgit.gum/stockholm'
+  cs.append(changes.GitPoller(
+          stockholm_repo,
+          workdir='stockholm-poller', branch='master',
+          project='stockholm',
+          pollinterval=120))
+    '';
+    scheduler = {
+        force-scheduler = ''
+  sched.append(schedulers.ForceScheduler(
+                              name="force",
+                              builderNames=["full-tests"]))
+        '';
+        fast-tests-scheduler = ''
+  # test the master real quick
+  sched.append(schedulers.SingleBranchScheduler(
+                              change_filter=util.ChangeFilter(branch="master"),
+                              treeStableTimer=10, #only test the latest push
+                              name="fast-master-test",
+                              builderNames=["fast-tests"]))
+        '';
+        test-cac-infest-master = ''
+  # files everyone depends on or are part of the share branch
+  def shared_files(change):
+    r =re.compile("^((krebs|shared)/.*|Makefile|default.nix)")
+    for file in change.files:
+      if r.match(file):
+        return True
+    return False
+
+  sched.append(schedulers.SingleBranchScheduler(
+                              change_filter=util.ChangeFilter(branch="master"),
+                              fileIsImportant=shared_files,
+                              treeStableTimer=60*60, # master was stable for the last hour
+                              name="full-master-test",
+                              builderNames=["full-tests"]))
+        '';
+    };
+    builder_pre = ''
+  # prepare grab_repo step for stockholm
+  stockholm_repo = "http://cgit.gum.retiolum/stockholm"
+  grab_repo = steps.Git(repourl=stockholm_repo, mode='incremental')
+
+  env = {"LOGNAME": "shared", "NIX_REMOTE": "daemon"}
+
+  # prepare nix-shell
+  # the dependencies which are used by the test script
+  deps = [ "gnumake", "jq","nix","rsync",
+            "(import <stockholm> {}).pkgs.test.infest-cac-centos7" ]
+  # TODO: --pure , prepare ENV in nix-shell command:
+  #                   SSL_CERT_FILE,LOGNAME,NIX_REMOTE
+  nixshell = ["nix-shell", "-I", "stockholm=.", "-p" ] + deps + [ "--run" ]
+
+  # prepare addShell function
+  def addShell(factory,**kwargs):
+    factory.addStep(steps.ShellCommand(**kwargs))
+    '';
+    builder = {
+      fast-tests = ''
+  f = util.BuildFactory()
+  f.addStep(grab_repo)
+  addShell(f,name="deploy-eval-centos7",env=env,
+            command=nixshell + ["make -s eval get=krebs.deploy filter=json system=test-centos7"])
+
+  addShell(f,name="deploy-eval-wolf",env=env,
+            command=nixshell + ["make -s eval get=krebs.deploy filter=json system=wolf"])
+
+  addShell(f,name="deploy-eval-cross-check",env=env,
+            command=nixshell + ["! make eval get=krebs.deploy filter=json system=test-failing"])
+
+  addShell(f,name="instantiate-test-all-modules",env=env,
+            command=nixshell + \
+                      ["touch retiolum.rsa_key.priv; \
+                        nix-instantiate --eval -A \
+                            users.shared.test-all-krebs-modules.system \
+                            -I stockholm=. \
+                            -I secrets=. '<stockholm>' \
+                            --argstr current-date lol \
+                            --argstr current-user-name shared \
+                            --argstr current-host-name lol \
+                            --strict --json"])
+
+  addShell(f,name="instantiate-test-minimal-deploy",env=env,
+            command=nixshell + \
+                      ["nix-instantiate --eval -A \
+                            users.shared.test-minimal-deploy.system \
+                            -I stockholm=. \
+                            -I secrets=. '<stockholm>' \
+                            --argstr current-date lol \
+                            --argstr current-user-name shared \
+                            --argstr current-host-name lol \
+                            --strict --json"])
+
+  bu.append(util.BuilderConfig(name="fast-tests",
+        slavenames=slavenames,
+        factory=f))
+      '';
+      slow-tests = ''
+  s = util.BuildFactory()
+  s.addStep(grab_repo)
+
+  # slave needs 2 files:
+  # * cac.json
+  # * retiolum
+  s.addStep(steps.FileDownload(mastersrc="${config.krebs.buildbot.master.workDir}/cac.json", slavedest="cac.json"))
+  s.addStep(steps.FileDownload(mastersrc="${config.krebs.buildbot.master.workDir}/retiolum-ci.rsa_key.priv", slavedest="retiolum.rsa_key.priv"))
+
+  addShell(s, name="infest-cac-centos7",env=env,
+              sigtermTime=60,           # SIGTERM 1 minute before SIGKILL
+              timeout=10800,             # 3h
+              command=nixshell + ["infest-cac-centos7"])
+
+  bu.append(util.BuilderConfig(name="full-tests",
+        slavenames=slavenames,
+        factory=s))
+      '';
+    };
+    enable = true;
+    web = {
+      enable = true;
+    };
+    irc = {
+      enable = true;
+      nick = "shared-buildbot";
+      server = "cd.retiolum";
+      channels = [ "retiolum" ];
+      allowForce = true;
+    };
+  };
+
+  krebs.buildbot.slave = {
+    enable = true;
+    masterhost = "localhost";
+    username = "testslave";
+    password = "krebspass";
+    packages = with pkgs;[ git nix ];
+    # all nix commands will need a working nixpkgs installation
+    extraEnviron = { NIX_PATH="nixpkgs=${toString <nixpkgs>}"; };
+  };
+}
diff --git a/shared/2configs/cac-ci.nix b/shared/2configs/cac-ci.nix
deleted file mode 100644
index 06cce2746..000000000
--- a/shared/2configs/cac-ci.nix
+++ /dev/null
@@ -1,11 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-{
-  environment.systemPackages = with pkgs;[
-    get
-    cac
-    cacpanel
-    jq
-  ];
-}
diff --git a/tv/1systems/wu.nix b/tv/1systems/wu.nix
index cd3139754..54ceb7783 100644
--- a/tv/1systems/wu.nix
+++ b/tv/1systems/wu.nix
@@ -16,7 +16,6 @@ with lib;
       environment.systemPackages = with pkgs; [
 
         # stockholm
-        genid
         gnumake
         hashPassword
         lentil
@@ -234,7 +233,12 @@ with lib;
     KERNEL=="hpet", GROUP="audio"
   '';
 
-  services.bitlbee.enable = true;
+  services.bitlbee = {
+    enable = true;
+    plugins = [
+      pkgs.bitlbee-facebook
+    ];
+  };
   services.tor.client.enable = true;
   services.tor.enable = true;
   services.virtualboxHost.enable = true;
diff --git a/tv/1systems/xu.nix b/tv/1systems/xu.nix
index eac36fafb..1f3e010a4 100644
--- a/tv/1systems/xu.nix
+++ b/tv/1systems/xu.nix
@@ -19,7 +19,6 @@ with lib;
       environment.systemPackages = with pkgs; [
 
         # stockholm
-        genid
         gnumake
         hashPassword
         lentil
diff --git a/tv/2configs/backup.nix b/tv/2configs/backup.nix
new file mode 100644
index 000000000..51d3bb8a7
--- /dev/null
+++ b/tv/2configs/backup.nix
@@ -0,0 +1,42 @@
+{ config, lib, ... }:
+with lib;
+{
+  krebs.backup.plans = addNames {
+    xu-test-cd = {
+      method = "push";
+
+      src = { host = config.krebs.hosts.xu; path = "/tmp/xu-test"; };
+      dst = { host = config.krebs.hosts.cd; path = "/tmp/backups/xu-test"; };
+
+      #startAt = "0,6,12,18:00";
+      startAt = "minutely";
+      snapshots = {
+        minutely = { format = "%Y-%m-%dT%H:%M"; retain =  5; };
+        hourly   = { format = "%Y-%m-%dT%H";    retain =  4; };
+        daily    = { format = "%Y-%m-%d";       retain =  7; };
+        weekly   = { format = "%YW%W";          retain =  4; };
+        monthly  = { format = "%Y-%m";          retain = 12; };
+        yearly   = { format = "%Y";                          };
+      };
+    };
+    #xu-test-wu = {
+    #  method = "push";
+    #  dst = { user = tv; host = wu; path = "/krebs/backup/xu-test"; };
+    #};
+    cd-test-xu = {
+      method = "pull";
+      src = { host = config.krebs.hosts.cd; path = "/tmp/cd-test"; };
+      dst = { host = config.krebs.hosts.xu; path = "/tmp/backups/cd-test"; };
+      startAt = "minutely";
+      snapshots = {
+        minutely = { format = "%Y-%m-%dT%H:%M"; retain =  5; };
+        hourly   = { format = "%Y-%m-%dT%H";    retain =  4; };
+        daily    = { format = "%Y-%m-%d";       retain =  7; };
+        weekly   = { format = "%YW%W";          retain =  4; };
+        monthly  = { format = "%Y-%m";          retain = 12; };
+        yearly   = { format = "%Y";                          };
+      };
+    };
+
+  };
+}
diff --git a/tv/2configs/charybdis.nix b/tv/2configs/charybdis.nix
index 80c6f7c4a..f9ab3da68 100644
--- a/tv/2configs/charybdis.nix
+++ b/tv/2configs/charybdis.nix
@@ -72,9 +72,9 @@ let
     };
   };
 
-  user = {
+  user = rec {
     name = "charybdis";
-    uid = 3748224544; # genid charybdis
+    uid = genid name;
   };
 
   configFile = toFile "charybdis-ircd.conf" ''
diff --git a/tv/2configs/default.nix b/tv/2configs/default.nix
index 3400c13b6..c300633bb 100644
--- a/tv/2configs/default.nix
+++ b/tv/2configs/default.nix
@@ -28,6 +28,7 @@ with lib;
 
   imports = [
     <secrets>
+    ./backup.nix
     ./vim.nix
     {
       # stockholm dependencies
diff --git a/tv/2configs/pulse.nix b/tv/2configs/pulse.nix
index 0ddc52789..3db3532d5 100644
--- a/tv/2configs/pulse.nix
+++ b/tv/2configs/pulse.nix
@@ -69,12 +69,10 @@ in
     };
   };
 
-  users = let
-    id = 3768151709; # genid pulse
-  in {
-    groups.pulse.gid = id;
+  users = {
+    groups.pulse.gid = config.users.users.pulse.uid;
     users.pulse = {
-      uid = id;
+      uid = genid "pulse";
       group = "pulse";
       extraGroups = [ "audio" ];
       home = "${runDir}/home";
diff --git a/tv/2configs/vim.nix b/tv/2configs/vim.nix
index 0822fb5bf..0537fa7d8 100644
--- a/tv/2configs/vim.nix
+++ b/tv/2configs/vim.nix
@@ -4,7 +4,7 @@ with lib;
 let
   out = {
     environment.systemPackages = [
-      pkgs.vim
+      vim
     ];
 
     # Nano really is just a stupid name for Vim.
@@ -22,14 +22,38 @@ let
     "${pkgs.vimPlugins.undotree}/share/vim-plugins/undotree"
   ];
 
+  dirs = {
+    backupdir = "$HOME/.cache/vim/backup";
+    swapdir   = "$HOME/.cache/vim/swap";
+    undodir   = "$HOME/.cache/vim/undo";
+  };
+  files = {
+    viminfo   = "$HOME/.cache/vim/info";
+  };
+
+  mkdirs = let
+    dirOf = s: let out = concatStringsSep "/" (init (splitString "/" s));
+               in assert out != ""; out;
+    alldirs = attrValues dirs ++ map dirOf (attrValues files);
+  in unique (sort lessThan alldirs);
+
+  vim = pkgs.writeScriptBin "vim" ''
+    #! ${pkgs.dash}/bin/dash
+    set -f
+    umask 0077
+    ${concatStringsSep "\n" (map (x: "mkdir -p ${x}") mkdirs)}
+    umask 0022
+    exec ${pkgs.vim}/bin/vim "$@"
+  '';
+
   vimrc = pkgs.writeText "vimrc" ''
     set nocompatible
 
     set autoindent
     set backspace=indent,eol,start
     set backup
-    set backupdir=$HOME/.vim/backup/
-    set directory=$HOME/.vim/cache//
+    set backupdir=${dirs.backupdir}/
+    set directory=${dirs.swapdir}//
     set hlsearch
     set incsearch
     set mouse=a
@@ -40,11 +64,11 @@ let
     set showcmd
     set showmatch
     set ttimeoutlen=0
-    set undodir=$HOME/.vim/undo
+    set undodir=${dirs.undodir}
     set undofile
     set undolevels=1000000
     set undoreload=1000000
-    set viminfo='20,<1000,s100,h,n$HOME/.vim/cache/info
+    set viminfo='20,<1000,s100,h,n${files.viminfo}
     set visualbell
     set wildignore+=*.o,*.class,*.hi,*.dyn_hi,*.dyn_o
     set wildmenu
diff --git a/tv/2configs/xserver/default.nix b/tv/2configs/xserver/default.nix
index f56da7dcc..facde4e76 100644
--- a/tv/2configs/xserver/default.nix
+++ b/tv/2configs/xserver/default.nix
@@ -48,7 +48,7 @@ let
       "slock"
     ];
 
-    systemd.services.display-manager = mkForce {};
+    systemd.services.display-manager.enable = false;
 
     services.xserver.enable = true;
 
diff --git a/tv/3modules/consul.nix b/tv/3modules/consul.nix
index ccdee07f5..5c955fdb5 100644
--- a/tv/3modules/consul.nix
+++ b/tv/3modules/consul.nix
@@ -109,9 +109,9 @@ let
     };
   };
 
-  user = {
+  user = rec {
     name = "consul";
-    uid = 2999951406; # genid consul
+    uid = genid name;
   };
 
 in
diff --git a/tv/3modules/ejabberd.nix b/tv/3modules/ejabberd.nix
index 6b231fb56..581e10074 100644
--- a/tv/3modules/ejabberd.nix
+++ b/tv/3modules/ejabberd.nix
@@ -53,9 +53,9 @@ let
     };
   };
 
-  user = {
+  user = rec {
     name = "ejabberd";
-    uid = 3499746127; # genid ejabberd
+    uid = genid name;
   };
 
   my-ejabberdctl = pkgs.writeScriptBin "ejabberdctl" ''