Mailcow: Factor out main image into a separate Nix file.
diff --git a/images.nix b/images.nix
index 3098ce2..dfa228d 100644
--- a/images.nix
+++ b/images.nix
@@ -52,126 +52,7 @@
     };
   };
 
-  mailcow =
-    let
-      dockerComposeOverrideYaml =
-        pkgs.writeTextDir "docker-compose.override.yml" ''
-          version: '2.1'
-
-          services:
-            mysql-mailcow:
-              image: alpine/socat:1.0.3
-              command:
-                - UNIX-LISTEN:/var/run/mysqld/mysqld.sock,reuseaddr,fork,unlink-early,mode=0777
-                - TCP-CONNECT:mysql.system.svc.cluster.local.:3306
-              volumes:
-                - mysql-socket-vol-1:/var/run/mysqld/:Z
-              restart: always
-
-            netfilter-mailcow:
-              build: ./data/Dockerfiles/netfilter
-
-            watchdog-mailcow:
-              build: ./data/Dockerfiles/watchdog
-
-          volumes:
-            vmail-vol-1:                {driver: local, driver_opts: {o: bind, type: none, device: "/vol/vmail"}}
-            vmail-index-vol-1:          {driver: local, driver_opts: {o: bind, type: none, device: "/vol/vmail-index"}}
-            mysql-vol-1:                {driver: local, driver_opts: {o: bind, type: none, device: "/run/mysql"}}
-            mysql-socket-vol-1:         {driver: local, driver_opts: {o: bind, type: none, device: "/run/mysql-socket"}}
-            redis-vol-1:                {driver: local, driver_opts: {o: bind, type: none, device: "/vol/redis-data"}}
-            rspamd-vol-1:               {driver: local, driver_opts: {o: bind, type: none, device: "/vol/rspamd-data"}}
-            solr-vol-1:                 {driver: local, driver_opts: {o: bind, type: none, device: "/vol/solr-data"}}
-            postfix-vol-1:              {driver: local, driver_opts: {o: bind, type: none, device: "/vol/postfix-data"}}
-            crypt-vol-1:                {driver: local, driver_opts: {o: bind, type: none, device: "/vol/crypt-data"}}
-            sogo-web-vol-1:             {driver: local, driver_opts: {o: bind, type: none, device: "/vol/sogo-web"}}
-            sogo-userdata-backup-vol-1: {driver: local, driver_opts: {o: bind, type: none, device: "/vol/sogo-userdata-backup"}}
-        '';
-
-      init =
-        pkgs.writeShellScriptBin "init" ''
-          set -xeuo pipefail
-
-          if ! [ -e /vol/docker-data/docker.ext4 ]; then
-              ${pkgs.busybox}/bin/dd if=/dev/zero of=/vol/docker-data/docker.ext4 bs=1G count=0 seek=30
-              ${pkgs.e2fsprogs}/bin/mkfs.ext4 /vol/docker-data/docker.ext4
-          fi
-          ${pkgs.e2fsprogs}/bin/e2fsck -y /vol/docker-data/docker.ext4
-          ${pkgs.busybox}/bin/mkdir -p /var/lib/docker
-          ${pkgs.busybox}/bin/mount -o loop,rw /vol/docker-data/docker.ext4 /var/lib/docker
-
-          ${pkgs.docker}/bin/dockerd --storage-driver=overlay2 &
-          sleep 10s
-
-          ${pkgs.docker}/bin/docker kill $(${pkgs.docker}/bin/docker ps -a -q) || :
-          ${pkgs.docker}/bin/docker system prune --volumes --force || :
-
-          ${pkgs.docker-compose}/bin/docker-compose -f /mailcow-dockerized/docker-compose.yml -f ${dockerComposeOverrideYaml}/docker-compose.override.yml build
-
-          ${pkgs.busybox}/bin/mkdir -p /tmp /run/{mysql,mysql-socket}
-          exec ${pkgs.docker-compose}/bin/docker-compose --env-file /mailcow-dockerized/mailcow.conf -f /mailcow-dockerized/docker-compose.yml -f ${dockerComposeOverrideYaml}/docker-compose.override.yml up --remove-orphans
-        '';
-
-      src = ./mailcow/src;
-
-      extraDeps = with pkgs; [
-        # for Docker
-        cacert
-
-        # for update.sh
-        bash
-        coreutils
-        curl
-        docker
-        docker-compose
-        findutils
-        gawk
-        gitMinimal
-      ];
-
-      maintenanceDeps = with pkgs; [
-        bash
-        busybox
-        coreutils
-        findutils
-        pxattr
-        strace
-      ];
-    in
-    img {
-      name = "docker.benkard.de/mulk/mailcow";
-      tag = "latest";
-      maxLayers = 125;
-      contents = extraDeps ++ maintenanceDeps;
-      extraCommands =
-        ''
-          #!${pkgs.runtimeShell}
-
-          install -dm755 vol/{crypt-data,postfix-data,redis-data,rspamd-data,sogo-web,sogo-userdata-backup,solr-data,vmail,vmail-index,web-data}
-
-          cp -a ${src}/* .
-        '';
-      config = {
-        Entrypoint = [ "${init}/bin/init" ];
-        Cmd = [ ];
-        Workdir = "/mailcow-dockerized";
-        Volumes = {
-          "/mailcow-dockerized/data/conf" = { };
-          "/mailcow-dockerized/data/assets/ssl" = { };
-          "/vol/crypt-data" = { };
-          "/vol/docker-data" = { };
-          "/vol/postfix-data" = { };
-          "/vol/redis-data" = { };
-          "/vol/rspamd-data" = { };
-          "/vol/sogo-web" = { };
-          "/vol/sogo-userdata-backup" = { };
-          "/vol/solr-data" = { };
-          "/vol/vmail" = { };
-          "/vol/vmail-index" = { };
-          "/vol/web-data" = { };
-        };
-      };
-    };
+  mailcow = pkgs.callPackage ./mailcow/default.nix { };
 
   nextcloud = img {
     name = "docker.benkard.de/mulk/nextcloud";
diff --git a/mailcow/default.nix b/mailcow/default.nix
new file mode 100644
index 0000000..2691722
--- /dev/null
+++ b/mailcow/default.nix
@@ -0,0 +1,133 @@
+{ system ? builtins.currentSystem }:
+let
+  pkgs = import <nixpkgs> { inherit system; };
+
+in
+let
+  img = spec: {
+    streamed = pkgs.dockerTools.streamLayeredImage spec;
+    layered = pkgs.dockerTools.buildLayeredImage spec;
+    image = pkgs.dockerTools.buildImage spec;
+  };
+
+in
+let
+  dockerComposeOverrideYaml =
+    pkgs.writeTextDir "docker-compose.override.yml" ''
+      version: '2.1'
+
+      services:
+        mysql-mailcow:
+          image: alpine/socat:1.0.3
+          command:
+            - UNIX-LISTEN:/var/run/mysqld/mysqld.sock,reuseaddr,fork,unlink-early,mode=0777
+            - TCP-CONNECT:mysql.system.svc.cluster.local.:3306
+          volumes:
+            - mysql-socket-vol-1:/var/run/mysqld/:Z
+          restart: always
+
+        netfilter-mailcow:
+          build: ./data/Dockerfiles/netfilter
+
+        watchdog-mailcow:
+          build: ./data/Dockerfiles/watchdog
+
+      volumes:
+        vmail-vol-1:                {driver: local, driver_opts: {o: bind, type: none, device: "/vol/vmail"}}
+        vmail-index-vol-1:          {driver: local, driver_opts: {o: bind, type: none, device: "/vol/vmail-index"}}
+        mysql-vol-1:                {driver: local, driver_opts: {o: bind, type: none, device: "/run/mysql"}}
+        mysql-socket-vol-1:         {driver: local, driver_opts: {o: bind, type: none, device: "/run/mysql-socket"}}
+        redis-vol-1:                {driver: local, driver_opts: {o: bind, type: none, device: "/vol/redis-data"}}
+        rspamd-vol-1:               {driver: local, driver_opts: {o: bind, type: none, device: "/vol/rspamd-data"}}
+        solr-vol-1:                 {driver: local, driver_opts: {o: bind, type: none, device: "/vol/solr-data"}}
+        postfix-vol-1:              {driver: local, driver_opts: {o: bind, type: none, device: "/vol/postfix-data"}}
+        crypt-vol-1:                {driver: local, driver_opts: {o: bind, type: none, device: "/vol/crypt-data"}}
+        sogo-web-vol-1:             {driver: local, driver_opts: {o: bind, type: none, device: "/vol/sogo-web"}}
+        sogo-userdata-backup-vol-1: {driver: local, driver_opts: {o: bind, type: none, device: "/vol/sogo-userdata-backup"}}
+    '';
+
+  init =
+    pkgs.writeShellScriptBin "init" ''
+      set -xeuo pipefail
+
+      if ! [ -e /vol/docker-data/docker.ext4 ]; then
+          ${pkgs.busybox}/bin/dd if=/dev/zero of=/vol/docker-data/docker.ext4 bs=1G count=0 seek=30
+          ${pkgs.e2fsprogs}/bin/mkfs.ext4 /vol/docker-data/docker.ext4
+      fi
+      ${pkgs.e2fsprogs}/bin/e2fsck -y /vol/docker-data/docker.ext4
+      ${pkgs.busybox}/bin/mkdir -p /var/lib/docker
+      ${pkgs.busybox}/bin/mount -o loop,rw /vol/docker-data/docker.ext4 /var/lib/docker
+
+      ${pkgs.docker}/bin/dockerd --storage-driver=overlay2 &
+      sleep 10s
+
+      ${pkgs.docker}/bin/docker kill $(${pkgs.docker}/bin/docker ps -a -q) || :
+      ${pkgs.docker}/bin/docker system prune --volumes --force || :
+
+      ${pkgs.docker-compose}/bin/docker-compose -f /mailcow-dockerized/docker-compose.yml -f ${dockerComposeOverrideYaml}/docker-compose.override.yml build
+
+      ${pkgs.busybox}/bin/mkdir -p /tmp /run/{mysql,mysql-socket}
+      exec ${pkgs.docker-compose}/bin/docker-compose --env-file /mailcow-dockerized/mailcow.conf -f /mailcow-dockerized/docker-compose.yml -f ${dockerComposeOverrideYaml}/docker-compose.override.yml up --remove-orphans
+    '';
+
+  src = ./src;
+
+  extraDeps = with pkgs; [
+    # for Docker
+    cacert
+
+    # for update.sh
+    bash
+    coreutils
+    curl
+    docker
+    docker-compose
+    findutils
+    gawk
+    gitMinimal
+  ];
+
+  maintenanceDeps = with pkgs; [
+    bash
+    busybox
+    coreutils
+    findutils
+    pxattr
+    strace
+  ];
+
+in
+img {
+  name = "docker.benkard.de/mulk/mailcow";
+  tag = "latest";
+  maxLayers = 125;
+  contents = extraDeps ++ maintenanceDeps;
+  extraCommands =
+    ''
+      #!${pkgs.runtimeShell}
+
+      install -dm755 vol/{crypt-data,postfix-data,redis-data,rspamd-data,sogo-web,sogo-userdata-backup,solr-data,vmail,vmail-index,web-data}
+
+      cp -a ${src}/* .
+    '';
+  config = {
+    Entrypoint = [ "${init}/bin/init" ];
+    Cmd = [ ];
+    Workdir = "/mailcow-dockerized";
+    Volumes = {
+      "/mailcow-dockerized/data/conf" = { };
+      "/mailcow-dockerized/data/assets/ssl" = { };
+      "/vol/crypt-data" = { };
+      "/vol/docker-data" = { };
+      "/vol/postfix-data" = { };
+      "/vol/redis-data" = { };
+      "/vol/rspamd-data" = { };
+      "/vol/sogo-web" = { };
+      "/vol/sogo-userdata-backup" = { };
+      "/vol/solr-data" = { };
+      "/vol/vmail" = { };
+      "/vol/vmail-index" = { };
+      "/vol/web-data" = { };
+    };
+  };
+}