Mailcow: Move to Nix and Docker-Compose.
diff --git a/mailcow/mailcow.yaml b/mailcow/mailcow.yaml
new file mode 100644
index 0000000..a403259
--- /dev/null
+++ b/mailcow/mailcow.yaml
@@ -0,0 +1,475 @@
+---
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+  name: mailcow
+  namespace: mulk
+  labels:
+    name: mailcow
+    k8s-app: mailcow
+  annotations:
+    kubernetes.io/ingress.class: traefik
+    traefik.ingress.kubernetes.io/preserve-host: "true"
+spec:
+  rules:
+    - host: mail.benkard.de
+      http:
+        paths:
+          - path: /
+            backend:
+              serviceName: mailcow
+              servicePort: 80
+    - host: autodiscover.benkard.de
+      http:
+        paths:
+          - path: /
+            backend:
+              serviceName: mailcow
+              servicePort: 80
+
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: mailcow-pub
+  namespace: mulk
+  labels:
+    name: mailcow-pub
+    k8s-app: mailcow
+spec:
+  selector:
+    name: mailcow
+  type: NodePort
+  externalTrafficPolicy: Local
+  ports:
+    - name: smtp-alt
+      port: 31025
+      targetPort: 25
+      protocol: TCP
+      nodePort: 31025
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: mailcow
+  namespace: mulk
+  labels:
+    name: mailcow
+    k8s-app: mailcow
+spec:
+  selector:
+    name: mailcow
+  type: ClusterIP
+  ports:
+    - name: http
+      port: 80
+      targetPort: 80
+      protocol: TCP
+
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: mailcow
+  namespace: mulk
+  labels:
+    name: mailcow
+    k8s-app: mailcow
+
+spec:
+  replicas: 1
+
+  strategy:
+    rollingUpdate:
+      maxSurge: 1
+      maxUnavailable: 1
+
+  selector:
+    matchLabels:
+      k8s-app: mailcow
+      name: mailcow
+
+  template:
+    metadata:
+      labels:
+        name: mailcow
+        k8s-app: mailcow
+
+    spec:
+      imagePullSecrets:
+        - name: portus-token
+
+      runtimeClassName: kata
+
+      containers:
+        - name: master
+          image: docker.benkard.de/mulk/mailcow:latest
+
+          securityContext:
+            # In a Kata container, this only gives the container full
+            # access to the guest VM rather than the host.  (To ensure
+            # this, it is important to set privileged_without_host_devices
+            # = true in the [plugins.cri.containerd.runtimes.kata] section
+            # of containerd's config.toml.)
+            privileged: true
+
+          env:
+            - name: COMPOSE_HTTP_TIMEOUT
+              value: "600"
+
+          ports:
+            - name: http
+              containerPort: 80
+            - name: smtp
+              hostPort: 25
+              containerPort: 25
+            - name: pop
+              hostPort: 110
+              containerPort: 110
+            - name: imap
+              hostPort: 143
+              containerPort: 143
+            - name: smtps
+              hostPort: 465
+              containerPort: 465
+            - name: submission
+              hostPort: 587
+              containerPort: 587
+            - name: imaps
+              hostPort: 993
+              containerPort: 993
+            - name: pops
+              hostPort: 995
+              containerPort: 995
+            - name: sieve
+              hostPort: 4190
+              containerPort: 4190
+            - name: doveadm
+              hostPort: 19991
+              containerPort: 12345
+
+          volumeMounts:
+            # Configuration data.
+            - name: assets
+              subPath: ssl
+              mountPath: /mailcow-dockerized/data/assets/ssl
+            - name: config
+              mountPath: /mailcow-dockerized/data/conf
+            - name: secrets
+              subPath: mailcow.conf
+              mountPath: /mailcow-dockerized/mailcow.conf
+
+            # State.
+            - name: crypt-data
+              mountPath: /vol/crypt-data
+            - name: postfix-data
+              mountPath: /vol/postfix-data
+            - name: redis-data
+              mountPath: /vol/redis-data
+            - name: rspamd-data
+              mountPath: /vol/rspamd-data
+            - name: solr-data
+              mountPath: /vol/solr-data
+            - name: sogo-web
+              mountPath: /vol/sogo-web
+            - name: sogo-userdata-backup
+              mountPath: /vol/sogo-userdata-backup
+            - name: vmail
+              mountPath: /vol/vmail
+            - name: vmail-index
+              mountPath: /vol/vmail-index
+            - name: web-data
+              mountPath: /vol/web-data
+            #- name: docker-data
+            #  subPath: vfs
+            #  mountPath: /var/lib/docker/vfs
+            #- name: docker-data
+            #  subPath: image
+            #  mountPath: /var/lib/docker/image
+            #- name: docker-data
+            #  subPath: overlay2
+            #  mountPath: /var/lib/docker/overlay2
+            #- name: docker-data
+            #  mountPath: /var/lib/docker
+            - name: docker-data
+              mountPath: /vol/docker-data
+
+      volumes:
+        - name: assets
+          persistentVolumeClaim:
+            claimName: mailcow-assets
+        - name: config
+          persistentVolumeClaim:
+            claimName: mailcow-config-v2
+        - name: crypt-data
+          persistentVolumeClaim:
+            claimName: mailcow-crypt
+        - name: postfix-data
+          persistentVolumeClaim:
+            claimName: mailcow-postfix
+        - name: redis-data
+          persistentVolumeClaim:
+            claimName: mailcow-redis
+        - name: rspamd-data
+          persistentVolumeClaim:
+            claimName: mailcow-rspamd
+        - name: solr-data
+          persistentVolumeClaim:
+            claimName: mailcow-solr
+        - name: sogo-web
+          persistentVolumeClaim:
+            claimName: mailcow-sogo-web
+        - name: sogo-userdata-backup
+          persistentVolumeClaim:
+            claimName: mailcow-sogo-userdata-backup
+        - name: vmail
+          persistentVolumeClaim:
+            claimName: mailcow-vmail
+        - name: vmail-index
+          persistentVolumeClaim:
+            claimName: mailcow-vmail-index
+        - name: web-data
+          persistentVolumeClaim:
+            claimName: mailcow-web
+        - name: docker-data
+          persistentVolumeClaim:
+            claimName: mailcow-docker
+        - name: secrets
+          secret:
+            secretName: mailcow-secrets
+
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  name: mailcow-web
+  namespace: mulk
+  labels:
+    k8s-app: mailcow
+  annotations:
+    volume.beta.kubernetes.io/storage-provisioner: rancher.io/local-path
+    volume.kubernetes.io/selected-node: ifirn
+spec:
+  storageClassName: local-path
+  accessModes:
+    - ReadWriteOnce
+  resources:
+    requests:
+      storage: 1Gi
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  name: mailcow-docker
+  namespace: mulk
+  labels:
+    k8s-app: mailcow
+  annotations:
+    volume.beta.kubernetes.io/storage-provisioner: rancher.io/local-path
+    volume.kubernetes.io/selected-node: ifirn
+spec:
+  storageClassName: local-path
+  accessModes:
+    - ReadWriteOnce
+  resources:
+    requests:
+      storage: 1Gi
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  name: mailcow-assets
+  namespace: mulk
+  labels:
+    k8s-app: mailcow
+  annotations:
+    volume.beta.kubernetes.io/storage-provisioner: rancher.io/local-path
+    volume.kubernetes.io/selected-node: ifirn
+spec:
+  storageClassName: local-path
+  accessModes:
+    - ReadWriteOnce
+  resources:
+    requests:
+      storage: 1Gi
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  name: mailcow-solr
+  namespace: mulk
+  labels:
+    k8s-app: mailcow
+  annotations:
+    volume.beta.kubernetes.io/storage-provisioner: rancher.io/local-path
+    volume.kubernetes.io/selected-node: ifirn
+spec:
+  storageClassName: local-path
+  accessModes:
+    - ReadWriteOnce
+  resources:
+    requests:
+      storage: 1Gi
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  name: mailcow-sogo-web
+  namespace: mulk
+  labels:
+    k8s-app: mailcow
+  annotations:
+    volume.beta.kubernetes.io/storage-provisioner: rancher.io/local-path
+    volume.kubernetes.io/selected-node: ifirn
+spec:
+  storageClassName: local-path
+  accessModes:
+    - ReadWriteOnce
+  resources:
+    requests:
+      storage: 1Gi
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  name: mailcow-sogo-userdata-backup
+  namespace: mulk
+  labels:
+    k8s-app: mailcow
+  annotations:
+    volume.beta.kubernetes.io/storage-provisioner: rancher.io/local-path
+    volume.kubernetes.io/selected-node: ifirn
+spec:
+  storageClassName: local-path
+  accessModes:
+    - ReadWriteOnce
+  resources:
+    requests:
+      storage: 1Gi
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  name: mailcow-vmail
+  namespace: mulk
+  labels:
+    k8s-app: mailcow
+  annotations:
+    volume.beta.kubernetes.io/storage-provisioner: rancher.io/local-path
+    volume.kubernetes.io/selected-node: ifirn
+spec:
+  storageClassName: local-path
+  accessModes:
+    - ReadWriteOnce
+  resources:
+    requests:
+      storage: 1Gi
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  name: mailcow-vmail-index
+  namespace: mulk
+  labels:
+    k8s-app: mailcow
+  annotations:
+    volume.beta.kubernetes.io/storage-provisioner: rancher.io/local-path
+    volume.kubernetes.io/selected-node: ifirn
+spec:
+  storageClassName: local-path
+  accessModes:
+    - ReadWriteOnce
+  resources:
+    requests:
+      storage: 1Gi
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  name: mailcow-redis
+  namespace: mulk
+  labels:
+    k8s-app: mailcow
+  annotations:
+    volume.beta.kubernetes.io/storage-provisioner: rancher.io/local-path
+    volume.kubernetes.io/selected-node: ifirn
+spec:
+  storageClassName: local-path
+  accessModes:
+    - ReadWriteOnce
+  resources:
+    requests:
+      storage: 1Gi
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  name: mailcow-rspamd
+  namespace: mulk
+  labels:
+    k8s-app: mailcow
+  annotations:
+    volume.beta.kubernetes.io/storage-provisioner: rancher.io/local-path
+    volume.kubernetes.io/selected-node: ifirn
+spec:
+  storageClassName: local-path
+  accessModes:
+    - ReadWriteOnce
+  resources:
+    requests:
+      storage: 1Gi
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  name: mailcow-postfix
+  namespace: mulk
+  labels:
+    k8s-app: mailcow
+  annotations:
+    volume.beta.kubernetes.io/storage-provisioner: rancher.io/local-path
+    volume.kubernetes.io/selected-node: ifirn
+spec:
+  storageClassName: local-path
+  accessModes:
+    - ReadWriteOnce
+  resources:
+    requests:
+      storage: 1Gi
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  name: mailcow-crypt
+  namespace: mulk
+  labels:
+    k8s-app: mailcow
+  annotations:
+    volume.beta.kubernetes.io/storage-provisioner: rancher.io/local-path
+    volume.kubernetes.io/selected-node: ifirn
+spec:
+  storageClassName: local-path
+  accessModes:
+    - ReadWriteOnce
+  resources:
+    requests:
+      storage: 1Gi
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  name: mailcow-config-v2
+  namespace: mulk
+  labels:
+    k8s-app: mailcow
+  annotations:
+    volume.beta.kubernetes.io/storage-provisioner: rancher.io/local-path
+    volume.kubernetes.io/selected-node: ifirn
+spec:
+  storageClassName: local-path
+  accessModes:
+    - ReadWriteOnce
+  resources:
+    requests:
+      storage: 1Gi
+---
diff --git a/mailcow/src/mailcow-dockerized/data/Dockerfiles/dockerapi/dockerapi.py b/mailcow/src/mailcow-dockerized/data/Dockerfiles/dockerapi/dockerapi.py
index 20e9d0e..32824a2 100644
--- a/mailcow/src/mailcow-dockerized/data/Dockerfiles/dockerapi/dockerapi.py
+++ b/mailcow/src/mailcow-dockerized/data/Dockerfiles/dockerapi/dockerapi.py
@@ -227,29 +227,11 @@
 
   # api call: container_post - post_action: exec - cmd: system - task: mysql_upgrade
   def container_post__exec__system__mysql_upgrade(self, container_id):
-    for container in docker_client.containers.list(filters={"id": container_id}):
-      sql_return = container.exec_run(["/bin/bash", "-c", "/usr/bin/mysql_upgrade -uroot -p'" + os.environ['DBROOT'].replace("'", "'\\''") + "'\n"], user='mysql')
-      if sql_return.exit_code == 0:
-        matched = False
-        for line in sql_return.output.decode('utf-8').split("\n"):
-          if 'is already upgraded to' in line:
-            matched = True
-        if matched:
-          return jsonify(type='success', msg='mysql_upgrade: already upgraded', text=sql_return.output.decode('utf-8'))
-        else:
-          container.restart()
-          return jsonify(type='warning', msg='mysql_upgrade: upgrade was applied', text=sql_return.output.decode('utf-8'))
-      else:
-        return jsonify(type='error', msg='mysql_upgrade: error running command', text=sql_return.output.decode('utf-8'))
+    return jsonify(type='success', msg='mysql_upgrade: not touching fake MySQL', text='')
 
   # api call: container_post - post_action: exec - cmd: system - task: mysql_tzinfo_to_sql
   def container_post__exec__system__mysql_tzinfo_to_sql(self, container_id):
-    for container in docker_client.containers.list(filters={"id": container_id}):
-      sql_return = container.exec_run(["/bin/bash", "-c", "/usr/bin/mysql_tzinfo_to_sql /usr/share/zoneinfo | /bin/sed 's/Local time zone must be set--see zic manual page/FCTY/' | /usr/bin/mysql -uroot -p'" + os.environ['DBROOT'].replace("'", "'\\''") + "' mysql \n"], user='mysql')
-      if sql_return.exit_code == 0:
-        return jsonify(type='info', msg='mysql_tzinfo_to_sql: command completed successfully', text=sql_return.output.decode('utf-8'))
-      else:
-        return jsonify(type='error', msg='mysql_tzinfo_to_sql: error running command', text=sql_return.output.decode('utf-8'))
+    return jsonify(type='success', msg='mysql_tzinfo_to_sql: not touching fake MySQL', text='')
 
   # api call: container_post - post_action: exec - cmd: reload - task: dovecot
   def container_post__exec__reload__dovecot(self, container_id):
@@ -284,7 +266,7 @@
   def container_post__exec__sieve__print(self, container_id):
     if 'username' in request.json and 'script_name' in request.json:
       for container in docker_client.containers.list(filters={"id": container_id}):
-        cmd = ["/bin/bash", "-c", "/usr/bin/doveadm sieve get -u '" + request.json['username'].replace("'", "'\\''") + "' '" + request.json['script_name'].replace("'", "'\\''") + "'"]  
+        cmd = ["/bin/bash", "-c", "/usr/bin/doveadm sieve get -u '" + request.json['username'].replace("'", "'\\''") + "' '" + request.json['script_name'].replace("'", "'\\''") + "'"]
         sieve_return = container.exec_run(cmd)
         return exec_run_handler('utf8_text_only', sieve_return)
 
diff --git a/mailcow/src/mailcow-dockerized/data/conf/postfix/main.cf b/mailcow/src/mailcow-dockerized/data/conf/postfix/main.cf
index e8da794..3e4b2b1 100644
--- a/mailcow/src/mailcow-dockerized/data/conf/postfix/main.cf
+++ b/mailcow/src/mailcow-dockerized/data/conf/postfix/main.cf
@@ -16,7 +16,7 @@
 alias_maps = hash:/etc/aliases
 alias_database = hash:/etc/aliases
 relayhost =
-mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 [fe80::]/10 [fc00::]/7
+mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 172.22.1.0/24 [fe80::]/10 [fc00::]/7
 mailbox_size_limit = 0
 recipient_delimiter = +
 inet_interfaces = all
diff --git a/mailcow/src/mailcow-dockerized/docker-compose.yml b/mailcow/src/mailcow-dockerized/docker-compose.yml
index 2c9c93a..ff1e5eb 100644
--- a/mailcow/src/mailcow-dockerized/docker-compose.yml
+++ b/mailcow/src/mailcow-dockerized/docker-compose.yml
@@ -552,7 +552,7 @@
     driver: bridge
     driver_opts:
       com.docker.network.bridge.name: br-mailcow
-    enable_ipv6: true
+    enable_ipv6: false
     ipam:
       driver: default
       config: