diff --git a/README.md b/README.md
index b94962eb501cf67c5d446ea889efa3a9627dc548..61268730a3c7dfc4a91319dd2d0b33af6e8af377 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,11 @@
 # Warpzone Infrastruktur Konfiguration
 
 Die Infrastruktur der Warpzone wird nach und nach durch das Konfigurationstool Ansible aufgebaut.
-Diese Konfiguration wird von den verschiedenen Teams gemeinschaftlich genutzt und soll als zentrale Dokumentation dienen.
-
+Diese Konfiguration soll als zentrale Dokumentation dienen.
 
 ## Aktueller Status
 
-Aktuell ist nur der neue Websserver in der Konfiguration erfasst.
-Weitere Dienste (wie z.B. der bestehende Webserver und die interne Infrastruktur) sind noch nicht abgebildet.
+Alle Server sind erfasst
 
 ## Vorraussetzungen
 Installiertes ansible
@@ -22,7 +20,7 @@ ansible-galaxy collection install community.docker
 
 Ausführen von Rollen per
 ```
-ansible-playbook  site.yml -l webserver -t hackmd
+ansible-playbook -i hosts.yml site.yml -l webserver -t hackmd
 ```
 
 mit -l wird der hosts eingeschränkt mit -t der tag bzw die Rolle, alle tags stehen in der site.yml
diff --git a/all/common/tasks/main.yml b/all/common/tasks/main.yml
index 99419e408b0157f3435c3c8318e9fb866daf97b1..22019a7711741663176c7a504a3ad47acae3ec9b 100644
--- a/all/common/tasks/main.yml
+++ b/all/common/tasks/main.yml
@@ -45,7 +45,8 @@
       - wget
       - psmisc
       - tree
-      - tmux 
+      - tmux
+      - mosh
 
 - name: deploy sshd config
   template: src=sshd_config.j2 dest=/etc/ssh/sshd_config
diff --git a/all/common/templates/sshd_config.j2 b/all/common/templates/sshd_config.j2
index 4bafc9405b8f66f74e82360018236bc7ea2574b9..9fe112fa6fb6c85db6477642c49c7418f83fe9a7 100644
--- a/all/common/templates/sshd_config.j2
+++ b/all/common/templates/sshd_config.j2
@@ -33,7 +33,7 @@ LogLevel INFO
 
 # Authentication:
 LoginGraceTime 120
-PermitRootLogin without-password
+PermitRootLogin prohibit-password
 StrictModes yes
 
 RSAAuthentication yes
diff --git a/ansible.cfg b/ansible.cfg
index b750525a6f270eb1407ff4c4ba0874955694e374..e2577c17dbd36bbbe9a9d336a0ae229307793746 100644
--- a/ansible.cfg
+++ b/ansible.cfg
@@ -1,4 +1,4 @@
 [defaults]
 # some default values for ansible
-inventory = hosts
+inventory = hosts.yml
 interpreter_python = /usr/bin/python3
diff --git a/common/borgbackup/templates/borgbackup-create.sh b/common/borgbackup/templates/borgbackup-create.sh
index f8378ce086fca7c629a1fcc9cc2cdfb83f66ef95..ab15ea30ef37df1ec6c8694a09148adccb389f4c 100644
--- a/common/borgbackup/templates/borgbackup-create.sh
+++ b/common/borgbackup/templates/borgbackup-create.sh
@@ -11,7 +11,7 @@ export LAST_BACKUPS_PROM="/var/lib/prometheus/node-exporter/lastbackup.prom"
 
 echo "===[ Create Backup: {{ item.value.repo }} ]===" \
 && \
-borg create $1 $2 $3 --info --show-rc --stats --compression {{ item.value.compression }} {{ item.value.options }} {{ item.value.repo }}::$BACKUP_DATE \
+borg create $1 $2 $3 --info --show-rc --stats --exclude *lost+found --compression {{ item.value.compression }} {{ item.value.options }} {{ item.value.repo }}::$BACKUP_DATE \
 {% for directory in borgbackup_directories %}
 {{ directory }} \
 {% endfor %} \
diff --git a/common/borgbackup/templates/borgbackup-prometheus.sh b/common/borgbackup/templates/borgbackup-prometheus.sh
index 497ad3f6e5e7fa9b07e27032d7586da118f7a27b..a76d76127400c2631d9b501fd7cb4836c7a886ad 100644
--- a/common/borgbackup/templates/borgbackup-prometheus.sh
+++ b/common/borgbackup/templates/borgbackup-prometheus.sh
@@ -3,6 +3,9 @@
 export BORG_PASSPHRASE="{{repo_passphrase}}"
 export BORG_RSH="ssh -i /srv/borgbackup/repo_sshkey"
 
+# Force locale for correct formatting
+LANG=en_US.UTF-8
+
 # Metrics output file in the prometheus node-exporter directory 
 PROM_FILE="/var/lib/prometheus/node-exporter/borgbackup.prom"
 
diff --git a/webserver/docker_autodiscover/tasks/main.yml b/common/crowdsec/tasks/main.yml
similarity index 75%
rename from webserver/docker_autodiscover/tasks/main.yml
rename to common/crowdsec/tasks/main.yml
index 039583792345c18142b09725e777e341bd1f6851..528ced23125f121bccf74ae5807322f5924a8ced 100644
--- a/webserver/docker_autodiscover/tasks/main.yml
+++ b/common/crowdsec/tasks/main.yml
@@ -7,26 +7,23 @@
   with_items:
     - "{{ basedir }}"
 
-
-- name: deploy {{ servicename }} config
+- name: "deploy {{ servicename }} config files"
   template:
     dest:  "{{ basedir }}/{{ item }}"
     src: "{{ item }}"
+    mode: 0644
   with_items:
     - docker-compose.yml
   register: config
 
-
 # Start containers
 - name: "stop {{ servicename }} docker"
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: "{{ basedir }}"
     state: absent
   when: config.changed
 
-
 - name: "start {{ servicename }} docker"
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: "{{ basedir }}"
-    state: present
-
+    state: present
\ No newline at end of file
diff --git a/common/crowdsec/templates/crowdsec/dashboard/Dockerfile b/common/crowdsec/templates/crowdsec/dashboard/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..0c09ec5499fcc1eb48cb71fd315fc9bf34bc23aa
--- /dev/null
+++ b/common/crowdsec/templates/crowdsec/dashboard/Dockerfile
@@ -0,0 +1,3 @@
+FROM metabase/metabase:v0.46.6.4
+
+RUN mkdir /data/ && wget https://crowdsec-statics-assets.s3-eu-west-1.amazonaws.com/metabase_sqlite.zip && unzip metabase_sqlite.zip -d /data/
\ No newline at end of file
diff --git a/common/crowdsec/templates/docker-compose.yml b/common/crowdsec/templates/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3ab2d8c88520e08fa850fbcef7fbd1f156accf02
--- /dev/null
+++ b/common/crowdsec/templates/docker-compose.yml
@@ -0,0 +1,39 @@
+version: '3'
+
+services:
+  app:
+    image: crowdsecurity/crowdsec:v1.5.2
+    healthcheck:
+      test: ["CMD", "cscli", "version"]
+      interval: 20s
+      timeout: 2s
+      retries: 5
+      start_period: 10s
+    ports:
+      - "127.0.0.1:8080:8080"
+    environment:
+      COLLECTIONS: "crowdsecurity/traefik crowdsecurity/http-cve crowdsecurity/whitelist-good-actors crowdsecurity/iptables crowdsecurity/linux crowdsecurity/nginx crowdsecurity/sshd"
+      GID: "${GID-1000}"
+      CUSTOM_HOSTNAME: dSHB
+    volumes:
+      - /etc/localtime:/etc/localtime:ro  
+      - /var/log:/var/log:ro
+      - /var/run/docker.sock:/var/run/docker.sock:ro
+      - /var/run/systemd/journal/socket:/var/run/systemd/journal/socket:ro
+      - {{ basedir }}/appdata/crowdsec/data:/var/lib/crowdsec/data
+      - {{ basedir }}/appdata/crowdsec/config:/etc/crowdsec
+      - {{ basedir }}/crowdsec-db:
+  
+  dashboard:
+    build: ./crowdsec/dashboard
+    restart: always
+    environment:
+      MB_DB_FILE: /data/metabase.db
+      MGID: "${GID-1000}"
+    labels:
+      - traefik.enable=true
+      - traefik.http.routers.{{ servicename }}.rule=Host(`{{ domain }}`)
+      - traefik.http.routers.{{ servicename }}.entrypoints=websecure
+      - traefik.http.services.{{ servicename }}.loadbalancer.server.port=3000
+    volumes:
+      - crowdsec-db:/metabase-data/
\ No newline at end of file
diff --git a/common/docker/tasks/main.yml b/common/docker/tasks/main.yml
index 5cb6c17777dfdd9ad4243b4f9c6cc43414827fb6..e7379036088c7ccecedc1f1830fff91602c5c155 100644
--- a/common/docker/tasks/main.yml
+++ b/common/docker/tasks/main.yml
@@ -20,6 +20,8 @@
     dest: /etc/docker/daemon.json
   notify: restart docker
 
+- name: Cronjob to prune unused images  
+  cron: name="docker-prune" weekday="*" hour="5" minute="5" job="/usr/bin/docker system prune --all -f"
 
 - name: "Create internal Networks: {{ docker.internal_networks }}"
   docker_network:
diff --git a/common/docker/templates/daemon.json b/common/docker/templates/daemon.json
index 6dd98eadb606b48e7e2609a17393950ae9fa1890..ff89d5df41dd8b0b0bd9e04ed34f1042dbb30ec4 100644
--- a/common/docker/templates/daemon.json
+++ b/common/docker/templates/daemon.json
@@ -6,7 +6,7 @@
       "max-file": "5"
     },
     "metrics-addr": "{{int_ip4}}:9323",
-    "experimental": true
-
+    "experimental": true,
+    "ip6tables": true
 }
 
diff --git a/common/docker_dockerstats/tasks/main.yml b/common/docker_dockerstats/tasks/main.yml
index 134a66c48250c2e711884783b239839ff58404cd..dbc65c107c09833b40658d6a8361e05d8809c517 100644
--- a/common/docker_dockerstats/tasks/main.yml
+++ b/common/docker_dockerstats/tasks/main.yml
@@ -19,6 +19,6 @@
 
 
 - name: start {{ servicename }} docker
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: "{{ basedir }}"
     state: present
diff --git a/common/docker_dockerstats/templates/Dockerfile b/common/docker_dockerstats/templates/Dockerfile
index 54677f76dd185c9540562f59c046621cbc149da5..793b7781f16e3c35b0213babc1185e883d014aba 100644
--- a/common/docker_dockerstats/templates/Dockerfile
+++ b/common/docker_dockerstats/templates/Dockerfile
@@ -1,4 +1,4 @@
-FROM node:19-alpine
+FROM node:21-alpine
 
 RUN apk update \
  && apk upgrade \
diff --git a/common/docker_ldap/tasks/main.yml b/common/docker_ldap/tasks/main.yml
index 5f38edd0ce755dc711185f62b8062568d3088271..4fcd906e2b0b16173b9b6d7f941a7f9f6ee0697a 100644
--- a/common/docker_ldap/tasks/main.yml
+++ b/common/docker_ldap/tasks/main.yml
@@ -22,8 +22,16 @@
     - docker-compose.yml
     - Dockerfile 
     - syncrepl_exporter.yml 
+  register: config
 
-- name: start openldap docker
-  docker_compose:
-    project_src: /srv/ldap/
+- name: "stop {{ servicename}} docker"
+  community.docker.docker_compose_v2:
+    project_src: "{{ basedir }}"
+    state: absent
+  when: config.changed
+
+- name: "start {{ servicename}} docker"
+  community.docker.docker_compose_v2:
+    project_src: "{{ basedir }}"
     state: present
+
diff --git a/common/docker_ldap/templates/Dockerfile b/common/docker_ldap/templates/Dockerfile
index 6c03ac2205932106a0446c303ab61ca583b063dd..e1b3bd048185fa7ae097c24dcc92d98974cdcddc 100644
--- a/common/docker_ldap/templates/Dockerfile
+++ b/common/docker_ldap/templates/Dockerfile
@@ -1,4 +1,4 @@
-FROM golang:1.13.5
+FROM golang:1.21.6
 
 RUN go get github.com/ThoreKr/syncrepl_exporter 
 
diff --git a/common/docker_traefik/tasks/main.yml b/common/docker_traefik/tasks/main.yml
index a13407e70b1816a3076aaaf0e9b982ce2c3d533d..54b26f8b8ee7a38f8965c45229d0f8514931a5ab 100644
--- a/common/docker_traefik/tasks/main.yml
+++ b/common/docker_traefik/tasks/main.yml
@@ -1,5 +1,5 @@
 
-- include: ../functions/get_secret.yml
+- include_tasks: ../functions/get_secret.yml
   with_items:
     - { path: "{{ basedir }}/letsencrypt_notification_email",  length: -1 }
   when: selfSignedCN is not defined 
@@ -37,19 +37,27 @@
     dest: "{{ basedir }}/{{ item }}"
   with_items:
     - docker-compose.yml
-    - traefik.yml 
-    - dynamic/redirect-default.yml
+    - traefik.yml
     - dynamic/tls.yml
   register: config
 
+- name: redirect-default ersstellen, wenn domain_default definiert ist
+  template:
+    src: "{{ item }}"
+    dest: "{{ basedir }}/{{ item }}"
+  with_items:
+    - dynamic/redirect-default.yml
+  when: domain_default is defined
+  register: config
+
 - name: "stop {{ servicename}} docker"
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: "{{ basedir }}"
     state: absent
   when: config.changed
 
 - name: "start {{ servicename}} docker"
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: "{{ basedir }}"
     state: present
-    
\ No newline at end of file
+    
diff --git a/common/docker_traefik/templates/docker-compose.yml b/common/docker_traefik/templates/docker-compose.yml
index a5ddc77e377aed275515213a67487f789874eb67..cfef612cde70392d8f247caeb80b40709afbcfdd 100644
--- a/common/docker_traefik/templates/docker-compose.yml
+++ b/common/docker_traefik/templates/docker-compose.yml
@@ -3,7 +3,7 @@ version: '2.4'
 services:
 
     app:
-        image: traefik:v2.9.8
+        image: traefik:v3.0
         restart: always
         ports:
             - "80:80"
diff --git a/common/docker_traefik/templates/dynamic/tls.yml b/common/docker_traefik/templates/dynamic/tls.yml
index e372473f40005fbf2b6b05917456dee589cecc73..0909bb1f47c3e55aa47b46aec72a3e4f9dbca74d 100644
--- a/common/docker_traefik/templates/dynamic/tls.yml
+++ b/common/docker_traefik/templates/dynamic/tls.yml
@@ -14,7 +14,6 @@ tls:
     options:
         default:
             sniStrict: true
-            preferServerCipherSuites: true
             minVersion: "VersionTLS12"
             curvePreferences:
                 - "secp521r1"
diff --git a/common/docker_watchtower/tasks/main.yml b/common/docker_watchtower/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..2ddbc65da6259ec07f4e919d701e878a0a8a5755
--- /dev/null
+++ b/common/docker_watchtower/tasks/main.yml
@@ -0,0 +1,29 @@
+---
+
+- include_tasks: ../functions/get_secret.yml
+  with_items:
+    - { path: "{{ basedir }}/matrix_notification_access_token",  length: -1 }
+
+
+- name: "create folder struct for {{ servicename }}"
+  file: 
+    path: "{{ item }}"
+    state: "directory"
+  with_items:
+    - "{{ basedir }}"
+
+
+- name: Konfig-Dateien erstellen (base,graphite)
+  template:
+    src: "{{ item }}"
+    dest: "{{ basedir }}/{{ item }}"
+  with_items:
+    - docker-compose.yml
+  register: dockerconfig
+
+  
+- name: "start {{ servicename }} docker"
+  community.docker.docker_compose_v2:
+    project_src: "{{ basedir }}"
+    state: present
+    build: "{{ dockerconfig.changed }}"
diff --git a/common/docker_watchtower/templates/docker-compose.yml b/common/docker_watchtower/templates/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..74e6864334ca7c80034ed9278e747a66b4101657
--- /dev/null
+++ b/common/docker_watchtower/templates/docker-compose.yml
@@ -0,0 +1,49 @@
+
+
+version: "2.4"
+
+services:
+
+  app:
+
+    image: containrrr/watchtower:latest
+    restart: always
+    volumes:
+      - /var/run/docker.sock:/var/run/docker.sock
+    environment:
+      TZ: "Europe/Berlin"
+      #WATCHTOWER_RUN_ONCE: "true"
+      WATCHTOWER_SCHEDULE: "0 0 5 * * *"
+      WATCHTOWER_CLEANUP: "true"
+      WATCHTOWER_NOTIFICATION_REPORT: "true"
+      WATCHTOWER_NOTIFICATION_URL: >
+        matrix://:{{ matrix_notification_access_token }}@{{ matrix.domain }}/?rooms={{ matrix.notifications_room_id }}
+      WATCHTOWER_NOTIFICATION_TEMPLATE: |
+        Watchtower @ {{ inventory_hostname }} {% raw %} {{"\n"}}
+        {{- if .Report -}}
+          {{- with .Report -}}
+        {{len .Scanned}} Scanned, {{len .Updated}} Updated, {{len .Failed}} Failed
+              {{- range .Updated}}
+        - {{.Name}} ({{.ImageName}}): {{.CurrentImageID.ShortID}} updated to {{.LatestImageID.ShortID}}
+              {{- end -}}
+              {{- range .Fresh}}
+        - {{.Name}} ({{.ImageName}}): {{.State}}
+            {{- end -}}
+            {{- range .Skipped}}
+        - {{.Name}} ({{.ImageName}}): {{.State}}: {{.Error}}
+            {{- end -}}
+            {{- range .Failed}}
+        - {{.Name}} ({{.ImageName}}): {{.State}}: {{.Error}}
+            {{- end -}}
+          {{- end -}}
+        {{- else -}}
+          {{range .Entries -}}{{.Message}}{{"\n"}}{{- end -}}
+        {{- end -}}
+        {% endraw %}
+
+
+
+
+
+
+
diff --git a/common/wireguard/tasks/main.yml b/common/wireguard/tasks/main.yml
index 9cf9ba9a6e891b4622a4fded2b19aa71d14d4af2..0b3c02ec959d2e12a25ecae5eea375f0fda8ebe1 100644
--- a/common/wireguard/tasks/main.yml
+++ b/common/wireguard/tasks/main.yml
@@ -53,6 +53,11 @@
   ansible.builtin.systemd:
     daemon_reload: true
 
+- name: "Stop systemd service for wg0"
+  ansible.builtin.systemd:
+    name: "wg-quick@wg0"
+    state: stopped
+
 - name: "Start systemd service for wg0"
   ansible.builtin.systemd:
     name: "wg-quick@wg0"
diff --git a/common/wireguard/templates/webserver.conf b/common/wireguard/templates/webserver.conf
new file mode 100644
index 0000000000000000000000000000000000000000..0ec608c4a8883786fc56cbe26faecdcf1e9e08ea
--- /dev/null
+++ b/common/wireguard/templates/webserver.conf
@@ -0,0 +1,8 @@
+[Interface]
+PrivateKey = {{ privatekey }}
+Address = 10.43.1.1 
+ListenPort = 51821
+
+[Peer]
+PublicKey = 9FLaGBXWjInPv4PFRuAJPPrPWruzocVrXg9lsmwGdX4=
+AllowedIPs = 10.43.1.2, 192.168.0.0/24, 10.0.0.0/22
diff --git a/group_vars/all b/group_vars/all
index 17f388f860d59db39c3db89845d50b099cd01709..c18974a26736db64a95ca09a7fe0c83fc029a8e5 100644
--- a/group_vars/all
+++ b/group_vars/all
@@ -5,21 +5,4 @@ ansible_python_interpreter: /usr/bin/python3
 # Globale Variablen für alle Server
 
 # Letsencrypt notification mail 
-letsencrypt_mail: verwaltung@warpzone.ms
-
-
-
-# Zentrale InfluxDb für Systemmonitoring  
-influxdb_sysmon:
-  url: "http://192.168.0.201:18086"
-  db: "influx"
-  user: "influx" 
-  password: "influx" 
-
-# Zentrale InfluxDb für Snmp Daten   
-influxdb_snmp:
-  url: "http://192.168.0.201:28086"
-  db: "influx"
-  user: "influx" 
-  password: "influx" 
-
+letsencrypt_mail: verwaltung@warpzone.ms
\ No newline at end of file
diff --git a/group_vars/prod b/group_vars/prod
index 8ac1256a668d808ed5d2a7701758c0a190eaf3f6..6689d75819bb5cb350de6c2963a7ee40444c59fa 100644
--- a/group_vars/prod
+++ b/group_vars/prod
@@ -32,40 +32,40 @@ global_domains:
 # Globale Mail konfiguration 
 mail_domains:
   warpzonems:
-    maildomain: warpzone.ms 
-    mxserver: mailserver.warpzone.ms
-    mxhostname: webserver
-    spf: v=spf1 mx ~all
-    dmarc: v=DMARC1; p=none;
+    maildomain: "warpzone.ms" 
+    mxserver: "mailserver.warpzone.ms"
+    mxhostname: "webserver"
+    spf: "v=spf1 mx a:mailserver.warpzone.ms ip4:{{ hostvars['webserver'].ext_ip4 }} ip6:{{ hostvars['webserver'].ext_ip6 }} -all"
+    dmarc: "v=DMARC1; p=none;"
     dkim:
-      - { selector: "dkim", value: "v=DKIM1;k=rsa;t=s;s=email;p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+ZvoSoa2LwBbzQMD9laVy8hUGbvhe1LkL/6SIk3Ks8GfiT7p+hdlbcvo+noBR4gvbmSWwn3yBxOnGCtSH+iP0q7HHrmeEXJqGkLK25zZh1EO8bZqIHi2NX/LnN7dJTO8C27CRLME+YtWdrDaerIWXsHk7U+qD1ZuM5Q+FgAzsQ5uxQVlD6sO3IU" }
+      - { selector: "dkim", value: "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxNnNZElbWq9EonFULbr8vWWykKmZEylRwjo4lYx/lXsGDFWBuNh2s6gFF10OuHWtavokjvh/7sFidNaRYQkn3uwHmylBWFn7Jr2lPWY8PBEoIeAZZx5qHaDWxJVgzE7maFyXAswDGXcR/DRTn2xR6osNXOovjGeYXq/atR/45iwfgkhqAaXaV1uP/K9y\" \"y2sZ2dRtGEwCKsWbP26cOZ6MUcADszgUTEp59iKey79m0uwi0IpA8WjEKVwbMcf/6fBw1ejIEjVUX+bami2fQ6RPl4uEyloco4paV3w/vww2hh4VchCFLYAEKMkZOZs/eTDGsjaMguwHbPeVJjkpX2T6WQIDAQAB" }
   member_warpzonems:
-    maildomain: member.warpzone.ms 
-    mxserver: mailserver.warpzone.ms
-    mxhostname: webserver
-    spf: v=spf1 mx ~all
-    dmarc: v=DMARC1; p=none;
+    maildomain: "member.warpzone.ms" 
+    mxserver: "mailserver.warpzone.ms"
+    mxhostname: "webserver"
+    spf: "v=spf1 mx a:mailserver.warpzone.ms ip4:{{ hostvars['webserver'].ext_ip4 }} ip6:{{ hostvars['webserver'].ext_ip6 }} -all"
     dkim:
-      - { selector: "dkim", value: "v=DKIM1;k=rsa;t=s;s=email;p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8lZDykC3gbxSHMwTNO7QrDytlO9Sg66nEXpIv1/GqQrj3T1i3tTn05XxpJbRXUMuooaP6xZqt2OR3f/Wex6d4WwHH4Z1YuvyKDUWewynGZ3Ge+Vca8T0LBdDw7DZWtkXv94SHPWLyPWuuBXQs2nAgrMn3rtlwKovEsOqg85mFNb1EVm9Rgj9TB2" }
+      - { selector: "dkim", value: "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu334a+uJ5b7D8UTz3Up6A8EjZhEnXaIpiIcKAGPXXD2ZBGmkWfUNcwDcfMoDErH6ntXzf0uH2VMvaajB/wdKLyly1irDKoyjLA3hJb5wnF9Gh0anL1qxY6UA189vWsw+2JlZJWyQ3IcaQ720SM3OrrK4AL3gRItieSEQ+23m5aW0P6sgUuMXTmmKLbd4\" \"DzZ14Emw293TD2p4gJtgxW/6EfIfcUU+/jP1NNm9gksyzynH1pJXPwVruo9u4QujEQiPqtVsVtrtUm1kbnW+pexj3eKOLLEHGZ+p5AZ/jtALk9pJfNumm/XHFK5PTZDBIipXOYvuG8RdwsaCQRezGKy04QIDAQAB" }
   lists_warpzonems:
-    maildomain: lists.warpzone.ms 
-    mxserver: mailserver.warpzone.ms
-    mxhostname: webserver
-    spf: v=spf1 mx ~all
-    dmarc: v=DMARC1; p=none;
+    maildomain: "lists.warpzone.ms" 
+    mxserver: "mailserver.warpzone.ms"
+    mxhostname: "webserver"
+    spf: "v=spf1 mx a:mailserver.warpzone.ms ip4:{{ hostvars['webserver'].ext_ip4 }} ip6:{{ hostvars['webserver'].ext_ip6 }} -all"
+    dkim:
+      - { selector: "dkim", value: "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoO7SXkUkM17Y1Vi/cvO48IJmlReGWSaYHY+wEldLHt80TiXP0AGZ8nG+DshXi1J2D5xjn8cJu4VqgDrLFnsRJyGYKmi7yVukANVg6gjYlET4y5+UU7Vk2W3xhN2U/8F0rcyynALzQa8i4Y/wEI0qkgHyE6+lITmglJvlj6tgp4YYK2TBH3Zo//PukOmU\" \"6gG/qu0+6p+CepvqzfGT2l1duov5a2+DJJzlJTULJ5D5Blsmg/0GeC81gZ4QDC3S8aaM5Pw3I3lQCSJT4Q4Ge6Ues4ccagNrdnZhtHNaVFGdL1mR1k+G784gpMZphPj5MylNEpA3V4bD7/Ygf4GuAvHdMwIDAQAB" }
 #  chaostreffmuensterde:
 #    maildomain: chaostreff-muenster.de 
-#    mxserver: mailserver.warpzone.ms
-#    mxhostname: webserver
-#    spf: v=spf1 mx ~all
+#    mxserver: "mailserver.warpzone.ms"
+#    mxhostname: "webserver"
+#    spf: "v=spf1 mx a:mailserver.warpzone.ms ip4:{{ hostvars['webserver'].ext_ip4 }} ip6:{{ hostvars['webserver'].ext_ip6 }} -all"
 #    dmarc: v=DMARC1; p=none;
 #    dkim:
 #      - { selector: "dkim", value: "v=DKIM1;k=rsa;t=s;s=email;p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz/OBnxYygjhKeZVyvhDAO1/O1XwyYEhQx3bW/rO/Wmp8ZzP/eQh3dljDEibj1KsfdUhfgTIU8CnTKLayb8B07MMzhBklpg8WUV2LrDmpndfhixizjaxzwBj/dhtiZE7e4BwhOPOmdBQ0cCIvNhMcQcCa1RgCpX/g5Ii0AtQ2zCPMTSOW5YWn+VY" }
 #  lists_chaostreffmuensterde:
-#    maildomain: lists.chaostreff-muenster.de 
-#    mxserver: mailserver.warpzone.ms
-#    mxhostname: webserver
-#    spf: v=spf1 mx ~all
+#    maildomain: "lists.chaostreff-muenster.de"
+#    mxserver: "mailserver.warpzone.ms"
+#    mxhostname: "webserver"
+#    spf: "v=spf1 mx a:mailserver.warpzone.ms ip4:{{ hostvars['webserver'].ext_ip4 }} ip6:{{ hostvars['webserver'].ext_ip6 }} -all"
 #    dmarc: v=DMARC1; p=none;
 
 
@@ -88,6 +88,7 @@ matrix:
   domain: matrix.warpzone.ms
   public_url: https://matrix.warpzone.ms
   identity_server: https://matrix.warpzone.ms
+  notifications_room_id: "!iYefxbySFEfFQfUGEK:matrix.warpzone.ms"
 
 # Monitoring 
 monitoring:
@@ -113,3 +114,10 @@ esphome_devices:
   - { id: "lounge",        name: "Lounge",        groups: "gLounge",        sensors: [ "Temp", "pressure", "humidity" ] }
   - { id: "status",        name: "Status/Strom",  groups: "gHauptraum",     sensors: [ "stromverbrauch", "warpzone_status" ] }
   - { id: "vortragsraum",  name: "Vortragsraum",  groups: "gVortragsraum",  sensors: [ "Temp", "pressure", "humidity" ] }
+
+# Global eQ3 Max configuration 
+eq3max:
+  cube_host: 192.168.0.15
+  devices_heizung:
+    - { name: "E-Werkstatt-Mitte", id: "MEQ1814738" }
+#    - { name: "HeizungKlo", id: "OEQ0663079" }
diff --git a/group_vars/test b/group_vars/test
new file mode 100644
index 0000000000000000000000000000000000000000..13266484ab87c0c55163d6d4b8f2a9774a1469af
--- /dev/null
+++ b/group_vars/test
@@ -0,0 +1,52 @@
+# SMTP Settings 
+smtp_domain: test-warpzone.de
+smtp_host: mailserver.test-warpzone.de
+smtp_port: 587 
+noreply_email_user: noreply@test-warpzone.de
+
+# Globale Domains
+global_domains:
+  warpzonems:
+    domain: test-warpzone.de
+
+# Globale Mail konfiguration 
+mail_domains:
+  warpzonems:
+    maildomain: "test-warpzone.de" 
+    mxserver: "mailserver.test-warpzone.de"
+    mxhostname: "test-warpzone-de"
+    spf: "v=spf1 mx a:mailserver.test-warpzone.de ip4:{{ hostvars['test-warpzone-de'].ext_ip4 }} ip6:{{ hostvars['test-warpzone-de'].ext_ip6 }} -all"
+    dmarc: "v=DMARC1; p=none;"
+    dkim:
+      - { selector: "dkim", value: "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqlvNCdae1bHGiuBrbXLwbtlEeQySngzG5wa7rG9O7eFFBnEKsrk9yOexRt1N5rOotRwL+Zy/9So8nylUFggP8nXlCgfUmEDPfNaWfzAeHUaPCTpUpbEZhOWr0vGxAyWeJ2p2eOAFK2PUU+KVqF7L3Zhb3yQxyYPKhKD4uxwgqH/Y2UPNP0SaJ7fOtZpW\" \"1cGiIVp2aVGiE5w1AbI3kDfLpGuh8g0AzBknVX4z8wb+f5wdZiX/3/iebv8LVxOpu6DRMt48D9PN9hRQywDVLPNko03rSu5MHoz3ilJC7lkFg7DRUssFT4JHeyrxoOu7FhZUc8BKjeQ3W2mrsGd6Y48ffQIDAQAB" }
+  # lists_warpzonems:
+  #   maildomain: "lists.test-warpzone.de" 
+  #   mxserver: "mailserver.test-warpzone.de"
+  #   mxhostname: "test-warpzone-de"
+  #   spf: "v=spf1 mx a:mailserver.test-warpzone.de ip4:{{ hostvars['test-warpzone-de'].ext_ip4 }} ip6:{{ hostvars['test-warpzone-de'].ext_ip6 }} -all"
+  #   dkim:
+  #     - { selector: "dkim", value: "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoO7SXkUkM17Y1Vi/cvO48IJmlReGWSaYHY+wEldLHt80TiXP0AGZ8nG+DshXi1J2D5xjn8cJu4VqgDrLFnsRJyGYKmi7yVukANVg6gjYlET4y5+UU7Vk2W3xhN2U/8F0rcyynALzQa8i4Y/wEI0qkgHyE6+lITmglJvlj6tgp4YYK2TBH3Zo//PukOmU\" \"6gG/qu0+6p+CepvqzfGT2l1duov5a2+DJJzlJTULJ5D5Blsmg/0GeC81gZ4QDC3S8aaM5Pw3I3lQCSJT4Q4Ge6Ues4ccagNrdnZhtHNaVFGdL1mR1k+G784gpMZphPj5MylNEpA3V4bD7/Ygf4GuAvHdMwIDAQAB" }
+
+# Monitoring 
+monitoring:
+  external_dns_servers:
+    - { ip: "1.1.1.1", name: "Cloudflare" }
+    - { ip: "8.8.8.8", name: "Google" }
+    - { ip: "9.9.9.9", name: "Quad9" }
+
+
+
+# Globale OAuth Server Settings
+oauth_global:
+  authorize_url: https://uffd.test-warpzone.de/oauth2/authorize
+  token_url: https://uffd.test-warpzone.de/oauth2/token
+  userinfo_url: https://uffd.test-warpzone.de/oauth2/userinfo
+  logout_url: https://uffd.test-warpzone.de/logout
+  metrics_url: https://uffd.test-warpzone.de/metrics
+
+# Matrix Settings 
+matrix:
+  domain: matrix.warpzone.ms
+  public_url: https://matrix.warpzone.ms
+  identity_server: https://matrix.warpzone.ms
+  notifications_room_id: "!QxrpmOPYwofaPFqKMY:matrix.warpzone.ms"
\ No newline at end of file
diff --git a/host_vars/carrot b/host_vars/carrot
index 04f184723a9552487c7518d0e766806e9c3682b3..e4b3440463889a7a91a43f50f6f7dcb6af54028b 100644
--- a/host_vars/carrot
+++ b/host_vars/carrot
@@ -6,9 +6,9 @@ motd_lines:
   - "Haupt-IP @ eth0: {{ansible_eth0.ipv4.address}}"
 
 debian_sources:
-  - "deb http://ftp2.de.debian.org/debian/ bullseye main contrib non-free"
-  - "deb http://ftp.debian.org/debian bullseye-updates main contrib non-free"
-  - "deb http://security.debian.org/ bullseye-security main contrib non-free"
+  - "deb http://ftp2.de.debian.org/debian/ bookworm main contrib non-free"
+  - "deb http://ftp.debian.org/debian bookworm-updates main contrib non-free"
+  - "deb http://security.debian.org/ bookworm-security main contrib non-free"
 
 debian_keys_id:
 
@@ -35,8 +35,8 @@ administratorenteam:
 # Monitoring aktivieren
 alert:
   load:
-    warn: 2
-    crit: 4
+    warn: 15
+    crit: 30
   disks:
     - { mountpoint: "/", warn: "5 GB", crit: "1 GB" }
 
diff --git a/host_vars/hex b/host_vars/hex
index 5ca98d3be68c9263f11a3f0772eae52cf6b32271..f7f78f8efb60a97fd4d4c07625d620e87157de2e 100644
--- a/host_vars/hex
+++ b/host_vars/hex
@@ -6,15 +6,15 @@ motd_lines:
   - "IPs: {{ansible_vmbr0.ipv4.address}}"
 
 debian_sources: 
-  - "deb http://deb.debian.org/debian/ bullseye main non-free contrib"
-  - "deb http://security.debian.org/debian-security bullseye-security main contrib non-free"
-  - "deb http://deb.debian.org/debian/ bullseye-updates main contrib non-free"
-  - "deb http://download.proxmox.com/debian/pve bullseye pve-no-subscription"
+  - "deb http://deb.debian.org/debian/ bookworm main non-free contrib"
+  - "deb http://security.debian.org/debian-security bookworm-security main contrib non-free"
+  - "deb http://deb.debian.org/debian/ bookworm-updates main contrib non-free"
+  - "deb http://download.proxmox.com/debian/pve bookworm pve-no-subscription"
 
 debian_keys_id:
 
 debian_keys_url:
-  - "https://enterprise.proxmox.com/debian/proxmox-release-bullseye.gpg"
+  - "https://enterprise.proxmox.com/debian/proxmox-release-bookworm.gpg"
 
 
 # Art des Hosts: physical, vm, docker 
diff --git a/host_vars/hix b/host_vars/hix
index 3258fb4291ff9c332e5d2754a2bee05f80f87ab1..cfd38bd628c351578a35932d44682a2b58788c9f 100644
--- a/host_vars/hix
+++ b/host_vars/hix
@@ -6,10 +6,10 @@ motd_lines:
   - "Haupt-IP @ eth0: {{ansible_eth0.ipv4.address}}"
 
 debian_sources:
-  - "deb http://ftp2.de.debian.org/debian/ bullseye main contrib non-free"
-  - "deb http://ftp.debian.org/debian bullseye-updates main contrib non-free"
-  - "deb http://security.debian.org/ bullseye-security main contrib non-free"
-  - "deb https://download.docker.com/linux/debian bullseye stable"
+  - "deb http://ftp2.de.debian.org/debian/ bookworm main contrib non-free"
+  - "deb http://ftp.debian.org/debian bookworm-updates main contrib non-free"
+  - "deb http://security.debian.org/ bookworm-security main contrib non-free"
+  - "deb https://download.docker.com/linux/debian bookworm stable"
 
 debian_keys_id:
 
diff --git a/host_vars/ogg b/host_vars/ogg
index ded6053ec42d11fc363fe80eb50af059880f2d03..e54838a3cf0979a1675de2541ff369ed47c4396f 100644
--- a/host_vars/ogg
+++ b/host_vars/ogg
@@ -6,10 +6,10 @@ motd_lines:
   - "Haupt-IP @ eth0: {{ansible_eth0.ipv4.address}}"
 
 debian_sources:
-  - "deb http://ftp2.de.debian.org/debian/ bullseye main contrib non-free"
-  - "deb http://ftp.debian.org/debian bullseye-updates main contrib non-free"
-  - "deb http://security.debian.org/ bullseye-security main contrib non-free"
-  - "deb https://download.docker.com/linux/debian bullseye stable"
+  - "deb http://ftp2.de.debian.org/debian/ bookworm main contrib non-free"
+  - "deb http://ftp.debian.org/debian bookworm-updates main contrib non-free"
+  - "deb http://security.debian.org/ bookworm-security main contrib non-free"
+  - "deb https://download.docker.com/linux/debian bookworm stable"
 
 debian_keys_id:
 
@@ -49,15 +49,25 @@ docker:
 # Monitoring aktivieren
 alert:
   load:
-    warn: 2
-    crit: 4
+    warn: 15
+    crit: 30
   containers:
-    - { name: "dockerstats_app_1" }    
-    - { name: "mqtt_app_1" } 
-    - { name: "mqtt_influxdb_1" } 
-    - { name: "mqtt_telegraf_1" } 
-    - { name: "nodered_app_1" }
-    - { name: "unifi_app_1" }
+    - { name: "dockerstats-app-1" }    
+    - { name: "esphome-app-1" }    
+    - { name: "esphome-dev-app-1" }    
+    - { name: "fridgeserver-app-1" }    
+    - { name: "grafana-app-1" }    
+    - { name: "heimdall-app-1" }    
+    - { name: "homeassistant-app-1" }    
+    - { name: "homeassistant-influxdb-1" }    
+    - { name: "mqtt-app-1" } 
+    - { name: "mqtt-influxdb-1" } 
+    - { name: "mqtt-tgbinary-1" } 
+    - { name: "mqtt-tgfloat-1" } 
+    - { name: "nodered-app-1" }
+    - { name: "omada-app-1" }
+    - { name: "tasmoadmin-app-1" }
+    - { name: "traefik-app-1" }
   disks:
     - { mountpoint: "/", warn: "5 GB", crit: "1 GB" }
     - { mountpoint: "/srv", warn: "5 GB", crit: "1 GB" }
@@ -70,21 +80,21 @@ borgbackup_repos:
   borgbase:
 
     # URL des Repos
-    repo: "juxt0t1v@juxt0t1v.repo.borgbase.com:repo"
+    repo: "apu4cibr@apu4cibr.repo.borgbase.com:repo"
 
     # Repo-spezifische Optionen zum Aufruf von Borgbackup
     # z.B. bei Sicherungen zu rsync.net ist --remote-path=borg1 erforderlich
     options: ""
 
     # Compression Options, z,b. "zlib,5, "zstd,5"
-    compression: "zlib,5"
+    compression: "zstd,5"
 
     # Prune Optionen
     prune: "--keep-within=2d --keep-daily=7 --keep-weekly=4 --keep-monthly=6"
 
     # Backup Schedule
     weekday: "*"
-    hour: "*/4"
+    hour: "6"
     minute: "40"
 
     #  Zusätzliche Verzeichnisse, die nur in diesem Backup gesichtert werden sollen
@@ -92,8 +102,8 @@ borgbackup_repos:
 
     # Monitoring
     alert: true
-    warning_age: 10
-    critical_age: 20
+    warning_age: 36
+    critical_age: 60
     warning_count: 10
     critical_count: 5
 
diff --git a/host_vars/test-warpzone-de b/host_vars/test-warpzone-de
new file mode 100644
index 0000000000000000000000000000000000000000..a00479198185e8e4f897e1021a95d1a46b2c1642
--- /dev/null
+++ b/host_vars/test-warpzone-de
@@ -0,0 +1,196 @@
+
+# Host spezifische Variablen 
+
+motd_lines: 
+  - "Testserver"
+  - "Öffentliche IPs: {{ansible_eth0.ipv4.address}} / {{ansible_eth0.ipv6[0].address}}"
+
+debian_sources: 
+  - "deb http://ftp2.de.debian.org/debian/ bookworm main contrib non-free"
+  - "deb http://ftp.debian.org/debian bookworm-updates main contrib non-free"
+  - "deb http://security.debian.org/ bookworm-security main contrib non-free"
+  - "deb https://download.docker.com/linux/debian bookworm stable"
+
+debian_keys_id:
+
+debian_keys_url:
+  - "https://download.docker.com/linux/debian/gpg"
+
+
+# Primäre IP Adressen des Hosts 
+ext_ip4: 159.69.57.56
+ext_ip6: 2a01:4f8:231:8a1:159:69:57:56
+int_ip4: 127.0.0.1
+
+# Art des Hosts: physical, vm, docker 
+host_type: "lxc"
+
+# SSL aktivieren 
+webserver_ssl: true
+
+# Liste der gehosteten Domänen
+webserver_domains: 
+  - "test-warpzone.de"
+#  - "api.test-warpzone.de"
+#  - "auth.test-warpzone.de"
+  - "gitlab.test-warpzone.de"
+#  - "matrix.test-warpzone.de"
+#  - "mailserver.test-warpzone.de"
+#  - "ldap.test-warpzone.de"
+#  - "keycloak.test-warpzone.de"
+#  - "md.test-warpzone.de"
+#  - "turn.test-warpzone.de"
+  - "wiki.test-warpzone.de"
+  - "www.test-warpzone.de"
+#  - "workadventure.test-warpzone.de"
+#  - "play.workadventure.test-warpzone.de"
+#  - "pusher.workadventure.test-warpzone.de"
+#  - "api.workadventure.test-warpzone.de"
+#  - "icon.workadventure.test-warpzone.de"
+
+
+# #OpenVPN Konfigurationen 
+# openvpn_server:
+#   - "server-zone"
+#   - "server-verwaltung"
+
+administratorenteam:
+  - "void"
+  - "sandhome"
+  - "jabertwo"
+
+# Docker konfigurationen 
+docker:
+  # Interne Docker-Netzwerke 
+  internal_networks:
+    - web
+    
+# Monitoring aktivieren 
+alert:  
+  load: 
+    warn: 5
+    crit: 10
+  containers:
+    #- { name: "coturn_coturn_1" }
+    - { name: "dockerstats-app-1" }
+    #- { name: "dokuwiki_app_1" }
+    - { name: "gitlab-app-1" }
+    - { name: "gitlab-dind-1" }
+    - { name: "gitlab-runner-1" }
+    #- { name: "hackmd_app_1" }
+    #- { name: "hackmd_db_1" }
+    #- { name: "icinga_app_1" }
+    #- { name: "icinga_db_1" }
+    #- { name: "icinga_graphite_1" }
+    #- { name: "keycloak_app_1" }
+    #- { name: "keycloak_db_1" }
+    #- { name: "keycloak_sync-group-active_1" }
+    #- { name: "ldap_openldap_1" }
+    #- { name: "ldap_phpldapadmin_1" }
+    #- { name: "mail_admin_1" }
+    #- { name: "mail_antispam_1" }
+    #- { name: "mail_certdumper_1" }
+    #- { name: "mail_db_1" }
+    #- { name: "mail_front_1" }
+    #- { name: "mail_imap_1" }
+    #- { name: "mail_oletools_1" }
+    #- { name: "mail_redis_1" }
+    #- { name: "mail_resolver_1" }
+    #- { name: "mail_smtp_1" }
+    #- { name: "mail_webmail_1" }
+    #- { name: "mail_mailman-core_1" }
+    #- { name: "mail_mailman-web_1" }
+    #- { name: "mail_mailman-nginx_1" }
+    #- { name: "matrix_ma1sd_1" }
+    #- { name: "matrix_db_1" }
+    #- { name: "matrix_purgemediacache_1" }
+    #- { name: "matrix_synapse_1" }
+    #- { name: "matterbridge_cw_1" }
+    #- { name: "matterbridge_wz_1" }
+    #- { name: "matterbridge_web_1" }
+    #- { name: "matterbridge_restarter_1" }
+    - { name: "traefik-app-1" }
+    #- { name: "vpnserver_app_1" }
+    #- { name: "warpapi_app_1" }
+    #- { name: "watchtower_app_1" }
+    - { name: "wordpress-app-1" }
+    - { name: "wordpress-db-1" }
+    #- { name: "workadventure_back_1" }
+    #- { name: "workadventure_front_1" }
+    #- { name: "workadventure_icon_1" }
+    #- { name: "workadventure_pusher_1" }
+    #- { name: "workadventure_redis_1" }
+  disks: 
+    - { mountpoint: "/", warn: "5 GB", crit: "1 GB" }
+    - { mountpoint: "/srv", warn: "5 GB", crit: "1 GB" }
+  
+
+# # Definition von Borgbackup Repositories 
+# borgbackup_repos:
+
+#   # warpsrvint: 
+
+#   #   # URL des Repos   
+#   #   repo: "ssh://warpzone@192.168.0.201:22/data/warpzone/webserver"
+    
+#   #   # Repo-spezifische Optionen zum Aufruf von Borgbackup
+#   #   # z.B. bei Sicherungen zu rsync.net ist --remote-path=borg1 erforderlich
+#   #   options: ""
+
+#   #   # Compression Options, z,b. "zlib,5, "zstd,5"
+#   #   compression: "zlib,5"
+
+#   #   # Prune Optionen 
+#   #   prune: "--keep-within=2d --keep-daily=7 --keep-weekly=4 --keep-monthly=6"
+    
+#   #   # Backup Schedule 
+#   #   weekday: "*"
+#   #   hour: "6"
+#   #   minute: "0"
+
+#   #   #  Zusätzliche Verzeichnisse, die nur in diesem Backup gesichtert werden sollen 
+#   #   # directories:
+
+#   #   # Monitoring
+#   #   alert: true
+#   #   warning_age: 26 
+#   #   critical_age: 50
+#   #   warning_count: 10
+#   #   critical_count: 5
+
+#   borgbase: 
+
+#     # URL des Repos   
+#     repo: "ani9ve0q@ani9ve0q.repo.borgbase.com:repo"
+    
+#     # Repo-spezifische Optionen zum Aufruf von Borgbackup
+#     # z.B. bei Sicherungen zu rsync.net ist --remote-path=borg1 erforderlich
+#     options: ""
+
+#     # Compression Options, z,b. "zlib,5, "zstd,5"
+#     compression: "zlib,5"
+
+#     # Prune Optionen 
+#     prune: "--keep-within=2d --keep-daily=7 --keep-weekly=4 --keep-monthly=6"
+    
+#     # Backup Schedule 
+#     weekday: "*"
+#     hour: "4"
+#     minute: "10"
+
+#     #  Zusätzliche Verzeichnisse, die nur in diesem Backup gesichtert werden sollen 
+#     # directories:
+
+#     # Monitoring
+#     alert: true
+#     warning_age: 26 
+#     critical_age: 50
+#     warning_count: 10
+#     critical_count: 5
+
+
+# # Definition der Verzeichnisse, die in allen Borgbackup Repos gesichert werden sollen 
+# borgbackup_directories:
+#   - "/etc/"
+#   - "/srv/"
+
diff --git a/host_vars/tiffany b/host_vars/tiffany
index 2c0ce7b4d57bfb3d5ac9db26451a3f9397226c38..77140dbcdb9b4de5197319b30c2f40f8d2ed09e2 100644
--- a/host_vars/tiffany
+++ b/host_vars/tiffany
@@ -6,15 +6,15 @@ motd_lines:
   - "Öffentliche IPs: {{ansible_enp35s0.ipv4.address}} / {{ansible_enp35s0.ipv6[0].address}}"
 
 debian_sources: 
-  - "deb http://ftp2.de.debian.org/debian/ bullseye main contrib non-free"
-  - "deb http://ftp.debian.org/debian bullseye-updates main contrib non-free"
-  - "deb http://security.debian.org/ bullseye-security main contrib non-free"
-  - "deb http://download.proxmox.com/debian/pve bullseye pve-no-subscription"
+  - "deb http://ftp2.de.debian.org/debian/ bookworm main contrib non-free"
+  - "deb http://ftp.debian.org/debian bookworm-updates main contrib non-free"
+  - "deb http://security.debian.org/ bookworm-security main contrib non-free"
+  - "deb http://download.proxmox.com/debian/pve bookworm pve-no-subscription"
 
 debian_keys_id:
 
 debian_keys_url:
-  - "http://download.proxmox.com/debian/proxmox-release-bullseye.gpg"
+  - "http://download.proxmox.com/debian/proxmox-release-bookworm.gpg"
 
 
 # Art des Hosts: physical, vm, docker 
diff --git a/host_vars/verwaltung b/host_vars/verwaltung
index 670b831256a9b6bc8055b676033ad2509db27f03..f29794ba2c8baef178db1e7c8213555faef153de 100644
--- a/host_vars/verwaltung
+++ b/host_vars/verwaltung
@@ -6,10 +6,10 @@ motd_lines:
   - "Öffentliche IPs: {{ansible_ens18.ipv4.address}} / {{ansible_ens18.ipv6[0].address}}"
 
 debian_sources: 
-  - "deb http://ftp2.de.debian.org/debian/ bullseye main contrib non-free"
-  - "deb http://ftp.debian.org/debian bullseye-updates main contrib non-free"
-  - "deb http://security.debian.org/ bullseye-security main contrib non-free"
-  - "deb https://download.docker.com/linux/debian bullseye stable"
+  - "deb http://ftp2.de.debian.org/debian/ bookworm main contrib non-free"
+  - "deb http://ftp.debian.org/debian bookworm-updates main contrib non-free"
+  - "deb http://security.debian.org/ bookworm-security main contrib non-free"
+  - "deb https://download.docker.com/linux/debian bookworm stable"
 
 debian_keys_id:
   
@@ -34,6 +34,7 @@ webserver_domains:
   - "verwaltung.warpzone.ms"
   - "verwaltung-git.warpzone.ms"
   - "verwaltung-jameica.warpzone.ms"
+  - "vault.warpzone.ms"
 
 
 #OpenVPN Konfigurationen 
@@ -50,7 +51,7 @@ administratorenteam:
 
 vorstandteam:
   - "void"
-  - "larsm"
+  - "hn13"
   - "jabertwo"
   - "3d"
 
@@ -63,21 +64,24 @@ docker:
 # Monitoring aktivieren 
 alert:  
   load: 
-    warn: 8
-    crit: 16
+    warn: 5
+    crit: 10
   containers:
-    - { name: "dockerstats_app_1" }
-    - { name: "gitea_app_1" }
-    - { name: "gitea_db_1" }
-    - { name: "jameica-vnc_ldap_auth_1" }
-    - { name: "jameica-vnc_nginx_1" }
-    - { name: "jameica-vnc_vnc_1" }
-    - { name: "mysql_app_1" }
-    - { name: "nextcloud_app_1" }
-    - { name: "nextcloud_mysql_1" }
-    - { name: "nextcloud_redis_1" }
-    - { name: "nextcloud_webcron_1" }
-    - { name: "traefik_app_1" }
+    - { name: "dockerstats-app-1" }
+    - { name: "gitea-app-1" }
+    - { name: "gitea-db-1" }
+    - { name: "jameica-vnc-ldap_  auth-1" }
+    - { name: "jameica-vnc-nginx-1" }
+    - { name: "jameica-vnc-vnc-1" }
+    - { name: "mysql-app-1" }
+    - { name: "nextcloud-app-1" }
+    - { name: "nextcloud-mysql-1" }
+    - { name: "nextcloud-redis-1" }
+    - { name: "nextcloud-webcron-1" }
+    - { name: "traefik-app-1" }
+    - { name: "vaultwarden-app-1" }
+    - { name: "vaultwarden-backup-1" }
+    - { name: "watchtower-app-1" }
   disks: 
     - { mountpoint: "/", warn: "5 GB", crit: "1 GB" }
     - { mountpoint: "/srv", warn: "5 GB", crit: "1 GB" }
@@ -86,35 +90,35 @@ alert:
 # Definition von Borgbackup Repositories 
 borgbackup_repos:
 
-  warpsrvint: 
+  # warpsrvint: 
 
-    # URL des Repos   
-    repo: "ssh://warpzone@192.168.0.201:22/data/warpzone/verwaltung"
+  #   # URL des Repos   
+  #   repo: "ssh://warpzone@192.168.0.201:22/data/warpzone/verwaltung"
     
-    # Repo-spezifische Optionen zum Aufruf von Borgbackup
-    # z.B. bei Sicherungen zu rsync.net ist --remote-path=borg1 erforderlich
-    options: ""
+  #   # Repo-spezifische Optionen zum Aufruf von Borgbackup
+  #   # z.B. bei Sicherungen zu rsync.net ist --remote-path=borg1 erforderlich
+  #   options: ""
 
-    # Compression Options, z,b. "zlib,5, "zstd,5"
-    compression: "zlib,5"
+  #   # Compression Options, z,b. "zlib,5, "zstd,5"
+  #   compression: "zlib,5"
 
-    # Prune Optionen 
-    prune: "--keep-within=2d --keep-daily=7 --keep-weekly=4 --keep-monthly=6"
+  #   # Prune Optionen 
+  #   prune: "--keep-within=2d --keep-daily=7 --keep-weekly=4 --keep-monthly=6"
     
-    # Backup Schedule 
-    weekday: "*"
-    hour: "10"
-    minute: "30"
-
-    #  Zusätzliche Verzeichnisse, die nur in diesem Backup gesichtert werden sollen 
-    # directories:
-
-    # Monitoring
-    alert: true
-    warning_age: 26 
-    critical_age: 50
-    warning_count: 10
-    critical_count: 5
+  #   # Backup Schedule 
+  #   weekday: "*"
+  #   hour: "10"
+  #   minute: "30"
+
+  #   #  Zusätzliche Verzeichnisse, die nur in diesem Backup gesichtert werden sollen 
+  #   # directories:
+
+  #   # Monitoring
+  #   alert: true
+  #   warning_age: 26 
+  #   critical_age: 50
+  #   warning_count: 10
+  #   critical_count: 5
 
   borgbase: 
 
diff --git a/host_vars/weatherwax b/host_vars/weatherwax
index 48fd99fdb09aaeece9e23f6424ee063b563bacd4..fe3db651c8adbbce23ccc70138efb480b0278505 100644
--- a/host_vars/weatherwax
+++ b/host_vars/weatherwax
@@ -6,15 +6,15 @@ motd_lines:
   - "IPs: {{ansible_bond0.ipv4.address}}"
 
 debian_sources: 
-  - "deb http://deb.debian.org/debian/ bullseye main non-free contrib"
-  - "deb http://security.debian.org/debian-security bullseye-security main contrib non-free"
-  - "deb http://deb.debian.org/debian/ bullseye-updates main contrib non-free"
-  - "deb http://download.proxmox.com/debian/pve bullseye pve-no-subscription"
+  - "deb http://deb.debian.org/debian/ bookworm main non-free contrib"
+  - "deb http://security.debian.org/debian-security bookworm-security main contrib non-free"
+  - "deb http://deb.debian.org/debian/ bookworm-updates main contrib non-free"
+  - "deb http://download.proxmox.com/debian/pve bookworm pve-no-subscription"
 
 debian_keys_id:
 
 debian_keys_url:
-  - "https://enterprise.proxmox.com/debian/proxmox-release-bullseye.gpg"
+  - "https://enterprise.proxmox.com/debian/proxmox-release-bookworm.gpg"
 
 
 # Art des Hosts: physical, vm, docker 
@@ -32,9 +32,10 @@ administratorenteam:
 # Monitoring aktivieren
 alert:
   load:
-    warn: 4
-    crit: 8
+    warn: 20
+    crit: 40
   disks:
     - { mountpoint: "/",         warn: "10 GB", crit: "3 GB" }
-    - { mountpoint: "/mnt/data", warn: "10 GB", crit: "3 GB" }
+    # btrfs currently no data from node exporter 
+    # - { mountpoint: "/mnt/data", warn: "10 GB", crit: "3 GB" }
 
diff --git a/host_vars/webserver b/host_vars/webserver
index 5a736d90dc0267f8628eb575716b6f3007fb1789..1eeb7d175f7ae5c0feb00e2961e1b0f90fd51790 100644
--- a/host_vars/webserver
+++ b/host_vars/webserver
@@ -6,10 +6,10 @@ motd_lines:
   - "Öffentliche IPs: {{ansible_ens18.ipv4.address}} / {{ansible_ens18.ipv6[0].address}}"
 
 debian_sources: 
-  - "deb http://ftp2.de.debian.org/debian/ bullseye main contrib non-free"
-  - "deb http://ftp.debian.org/debian bullseye-updates main contrib non-free"
-  - "deb http://security.debian.org/ bullseye-security main contrib non-free"
-  - "deb https://download.docker.com/linux/debian bullseye stable"
+  - "deb http://ftp2.de.debian.org/debian/ bookworm main contrib non-free non-free-firmware"
+  - "deb http://ftp.debian.org/debian bookworm-updates main contrib non-free non-free-firmware"
+  - "deb http://security.debian.org/ bookworm-security main contrib non-free non-free-firmware"
+  - "deb https://download.docker.com/linux/debian bookworm stable"
 
 debian_keys_id:
 
@@ -33,8 +33,6 @@ webserver_domains:
   - "warpzone.ms"
   - "api.warpzone.ms"
 #  - "auth.warpzone.ms"
-  - "autodiscover.warpzone.ms"
-  - "autoconfig.warpzone.ms"
   - "gitlab.warpzone.ms"
   - "matrix.warpzone.ms"
   - "mailserver.warpzone.ms"
@@ -45,7 +43,7 @@ webserver_domains:
   - "wiki.warpzone.ms"
   - "www.warpzone.ms"
 #  - "workadventure.warpzone.ms"
-  - "play.workadventure.warpzone.ms"
+#  - "play.workadventure.warpzone.ms"
 #  - "pusher.workadventure.warpzone.ms"
 #  - "api.workadventure.warpzone.ms"
 #  - "icon.workadventure.warpzone.ms"
@@ -65,108 +63,100 @@ administratorenteam:
 docker:
   # Interne Docker-Netzwerke 
   internal_networks:
-    - mail
     - web
     
 # Monitoring aktivieren 
 alert:  
   load: 
-    warn: 8
-    crit: 16
+    warn: 5
+    crit: 10
   containers:
-    - { name: "autodiscover_warpzonems_1" }
-    - { name: "autodiscover_lists_warpzonems_1" }
-    - { name: "autodiscover_member_warpzonems_1" }
-    - { name: "dockerstats_app_1" }
-    - { name: "dokuwiki_app_1" }
-    - { name: "coturn_coturn_1" }
-    - { name: "gitlab_app_1" }
-    - { name: "gitlab_dind_1" }
-    - { name: "gitlab_runner_1" }
-    - { name: "hackmd_app_1" }
-    - { name: "hackmd_db_1" }
-    - { name: "icinga_app_1" }
-    - { name: "icinga_db_1" }
-    - { name: "icinga_graphite_1" }
-    - { name: "keycloak_app_1" }
-    - { name: "keycloak_db_1" }
-    - { name: "keycloak_sync-group-active_1" }
-    - { name: "ldap_openldap_1" }
-    - { name: "ldap_phpldapadmin_1" }
-    - { name: "mail_dovecot-mailcow_1" }
-    - { name: "mail_dockerapi-mailcow_1" }
-    - { name: "mail_ipv6nat-mailcow_1" }
-    - { name: "mail_mailman-core" }
-    - { name: "mail_mailman-db" }
-    - { name: "mail_mailman-nginx" }
-    - { name: "mail_mailman-web" }
-    - { name: "mail_memcached-mailcow_1" }
-    - { name: "mail_mysql-mailcow_1" }
-    - { name: "mail_netfilter-mailcow_1" }
-    - { name: "mail_nginx-mailcow_1" }
-    - { name: "mail_olefy-mailcow_1" }
-    - { name: "mail_ofelia-mailcow_1" }
-    - { name: "mail_postfix-mailcow_1" }
-    - { name: "mail_postfix-exporter_1" }
-    - { name: "mail_php-fpm-mailcow_1" }
-    - { name: "mail_redis-mailcow_1" }
-    - { name: "mail_rspamd-mailcow_1" }
-    - { name: "mail_traefik-certdumper_1" }    
-    - { name: "mail_unbound-mailcow_1" }
-    - { name: "mail_watchdog-mailcow_1" }
-    - { name: "matterbridge_cw_1" }
-    - { name: "matterbridge_wz_1" }
-    - { name: "matterbridge_web_1" }
-    - { name: "matterbridge_restarter_1" }
-    - { name: "matrix_ma1sd_1" }
-    - { name: "matrix_db_1" }
-    - { name: "matrix_synapse_1" }
-    - { name: "traefik_app_1" }
-    - { name: "warpapi_app_1" }
-    - { name: "wordpress_app_1" }
-    - { name: "wordpress_db_1" }
-    - { name: "workadventure_back_1" }
-    - { name: "workadventure_front_1" }
-    - { name: "workadventure_icon_1" }
-    - { name: "workadventure_pusher_1" }
-    - { name: "workadventure_redis_1" }
+    - { name: "coturn-coturn-1" }
+    - { name: "dockerstats-app-1" }
+    - { name: "dokuwiki-app-1" }
+    - { name: "gitlab-app-1" }
+    - { name: "gitlab-dind-1" }
+    - { name: "gitlab-runner-1" }
+    - { name: "hackmd-app-1" }
+    - { name: "hackmd-db-1" }
+    - { name: "icinga-app-1" }
+    - { name: "icinga-db-1" }
+    - { name: "icinga-graphite-1" }
+    - { name: "keycloak-app-1" }
+    - { name: "keycloak-db-1" }
+    - { name: "keycloak-sync-group-active-1" }
+    - { name: "ldap-openldap-1" }
+    - { name: "ldap-phpldapadmin-1" }
+    - { name: "mail-admin-1" }
+    - { name: "mail-antispam-1" }
+    - { name: "mail-certdumper-1" }
+    - { name: "mail-db-1" }
+    - { name: "mail-front-1" }
+    - { name: "mail-imap-1" }
+    - { name: "mail-oletools-1" }
+    - { name: "mail-redis-1" }
+    - { name: "mail-resolver-1" }
+    - { name: "mail-smtp-1" }
+    - { name: "mail-webmail-1" }
+    - { name: "mail-mailman-core-1" }
+    - { name: "mail-mailman-web-1" }
+    - { name: "mail-mailman-nginx-1" }
+    - { name: "matrix-ma1sd-1" }
+    - { name: "matrix-db-1" }
+    - { name: "matrix-purgemediacache-1" }
+    - { name: "matrix-synapse-1" }
+    - { name: "matterbridge-cw-1" }
+    - { name: "matterbridge-wz-1" }
+    - { name: "matterbridge-web-1" }
+    - { name: "matterbridge-restarter-1" }
+    - { name: "traefik-app-1" }
+    - { name: "vpnserver-app-1" }
+    - { name: "warpapi-app-1" }
+    - { name: "watchtower-app-1" }
+    - { name: "wordpress-app-1" }
+    - { name: "wordpress-db-1" }
+  #  - { name: "workadventure_back_1" }
+  #  - { name: "workadventure_front_1" }
+  #  - { name: "workadventure_icon_1" }
+  #  - { name: "workadventure_pusher_1" }
+  #  - { name: "workadventure_redis_1" }
   disks: 
     - { mountpoint: "/", warn: "5 GB", crit: "1 GB" }
-    - { mountpoint: "/srv", warn: "1 GB", crit: "500 MB" }
+    - { mountpoint: "/srv", warn: "5 GB", crit: "1 GB" }
   
 
 # Definition von Borgbackup Repositories 
 borgbackup_repos:
 
-  warpsrvint: 
+  # warpsrvint: 
 
-    # URL des Repos   
-    repo: "ssh://warpzone@192.168.0.201:22/data/warpzone/webserver"
+  #   # URL des Repos   
+  #   repo: "ssh://warpzone@192.168.0.201:22/data/warpzone/webserver"
     
-    # Repo-spezifische Optionen zum Aufruf von Borgbackup
-    # z.B. bei Sicherungen zu rsync.net ist --remote-path=borg1 erforderlich
-    options: ""
+  #   # Repo-spezifische Optionen zum Aufruf von Borgbackup
+  #   # z.B. bei Sicherungen zu rsync.net ist --remote-path=borg1 erforderlich
+  #   options: ""
 
-    # Compression Options, z,b. "zlib,5, "zstd,5"
-    compression: "zlib,5"
+  #   # Compression Options, z,b. "zlib,5, "zstd,5"
+  #   compression: "zlib,5"
 
-    # Prune Optionen 
-    prune: "--keep-within=2d --keep-daily=7 --keep-weekly=4 --keep-monthly=6"
+  #   # Prune Optionen 
+  #   prune: "--keep-within=2d --keep-daily=7 --keep-weekly=4 --keep-monthly=6"
     
-    # Backup Schedule 
-    weekday: "*"
-    hour: "6"
-    minute: "0"
-
-    #  Zusätzliche Verzeichnisse, die nur in diesem Backup gesichtert werden sollen 
-    # directories:
-
-    # Monitoring
-    alert: true
-    warning_age: 26 
-    critical_age: 50
-    warning_count: 10
-    critical_count: 5
+  #   # Backup Schedule 
+  #   weekday: "*"
+  #   hour: "6"
+  #   minute: "0"
+
+  #   #  Zusätzliche Verzeichnisse, die nur in diesem Backup gesichtert werden sollen 
+  #   # directories:
+
+  #   # Monitoring
+  #   alert: true
+  #   warning_age: 26 
+  #   critical_age: 50
+  #   warning_count: 10
+  #   critical_count: 5
 
   borgbase: 
 
diff --git a/hosts b/hosts
deleted file mode 100644
index aef6a3c38f46c15a821e0bdd271cb92037bb56d2..0000000000000000000000000000000000000000
--- a/hosts
+++ /dev/null
@@ -1,47 +0,0 @@
-
-# Nameskonvention für Server: Pratchett Name/Charaktere
-# Namensliste: https://wiki.lspace.org/List_of_Pratchett_characters
-# Nächste freie Namen: vimes, cake, colon, detritus, dibbler, dorfl, gaspode, quirm, cherry, nobby, ramkin, ron, shoe, slant, angua, vetinary, bursar, coin, dean, hex, hix, worblehat, luggage. mustrum, rincewind, wrangler, stibbons, whitlow  
-
-[prod]
-
-# Interner Server Warpzone 
-# Umgebaute Watchguard im Serverschrank 
-# https://wiki.warpzone.ms/intern:warpzone_internal_it_infrastructure#host_fuer_interne_dienste_watchguard_xtm_505
-# Für Verbindungen über den Webserver als Jumphost folgende Parameter ergänzen: 
-# ansible_ssh_common_args='-o ForwardAgent=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ProxyCommand="ssh -W %h:%p -q 159.69.57.51"'
-
-# Interner Proxmox-Server (neu ab 09-2022) 
-weatherwax   ansible_ssh_host=192.168.0.200
-
-# Server für interne Dienste (neu ab 09-2022)
-# Container auf dem internen Proxmox Server 
-# Wichtige Optionen: Nesting = Yes, keyctl = enabled
-ogg          ansible_ssh_host=192.168.0.201
-
-# Server für VPN Verbindung zum Webserver 
-# Container auf dem internen Proxmox Server 
-# Wichtige Optionen: Nesting = Yes, keyctl = enabled
-carrot       ansible_ssh_host=192.168.0.202
-
-# Externe Server Warpzone
-# Öffentlicher Root Server Warpzone bei Hetzner 
-tiffany     ansible_ssh_host=159.69.57.15
-
-# Öffentlicher Webserver Warpzone 
-# VM auf Tiffany
-webserver   ansible_ssh_host=159.69.57.51 
-
-# Vorstands-VM
-# VM auf Tiffany
-# Auch erreichbar unter verwaltung.warpzone.ms
-verwaltung ansible_ssh_host=195.201.179.60
-
-# Physischer Server für Veranstaltungen / Camps 
-# warpzone.remote Proxmox-Server
-hex         ansible_ssh_host=10.111.10.100
-
-# Virtueller Server für Infrastruktur-Dienste auf Veranstaltungen / Camps
-# Container auf dem warpzone.remote Proxmox-Server 
-# Wichtige Optionen: Nesting = Yes, keyctl = enabled
-hix         ansible_ssh_host=10.111.10.101
\ No newline at end of file
diff --git a/hosts.yml b/hosts.yml
new file mode 100644
index 0000000000000000000000000000000000000000..d74984eac01114d2c83de0e22403324cca360c6f
--- /dev/null
+++ b/hosts.yml
@@ -0,0 +1,67 @@
+---
+# Nameskonvention für Server: Pratchett Name/Charaktere
+# Namensliste: https://wiki.lspace.org/List_of_Pratchett_characters
+# Nächste freie Namen: vimes, cake, colon, detritus, dibbler, dorfl, gaspode, quirm, cherry, nobby, ramkin, ron, shoe, slant, angua, vetinary, bursar, coin, dean, worblehat, luggage. mustrum, rincewind, wrangler, stibbons, whitlow  
+
+test:
+  hosts:
+    test-warpzone-de:
+      ansible_ssh_host: 159.69.57.56
+      ansible_user: root
+
+prod:
+  hosts:
+    # Interner Proxmox-Server
+    # Für Verbindungen über den Webserver als Jumphost folgende Parameter ergänzen: 
+    # ansible_ssh_common_args='-o ForwardAgent=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ProxyCommand="ssh -W %h:%p -q 159.69.57.51"'
+    weatherwax:
+      ansible_ssh_host: 192.168.0.200
+      ansible_user: root
+
+    # Externe Server Warpzone
+    # Öffentlicher Root Server Warpzone bei Hetzner
+    tiffany:
+      ansible_ssh_host: 159.69.57.15
+      ansible_user: root
+
+    # Server für interne Dienste
+    # Container auf dem internen Proxmox Server
+    # Wichtige Optionen: Nesting = Yes, keyctl = enabled
+    ogg:
+      ansible_ssh_host: 192.168.0.201
+      ansible_user: root
+
+    # Server für VPN Verbindung zum Webserver
+    # Container auf dem internen Proxmox Server
+    # Wichtige Optionen: Nesting = Yes, keyctl = enabled
+    carrot:
+      ansible_ssh_host: 192.168.0.202
+      ansible_user: root
+
+    # Öffentlicher Webserver Warpzone
+    # VM auf Tiffany
+    webserver:
+      ansible_ssh_host: 159.69.57.51
+      ansible_user: root
+
+    # Vorstands-VM
+    # VM auf Tiffany
+    # Auch erreichbar unter verwaltung.warpzone.ms
+    verwaltung:
+      ansible_ssh_host: 195.201.179.60
+      ansible_user: root
+
+event:
+  hosts:
+    # Physischer Server für Veranstaltungen / Camps
+    # warpzone.remote Proxmox-Server
+    hex:
+      ansible_ssh_host: 10.111.10.100
+      ansible_user: root
+
+    # Virtueller Server für Infrastruktur-Dienste auf Veranstaltungen / Camps
+    # Container auf dem warpzone.remote Proxmox-Server
+    # Wichtige Optionen: Nesting = Yes, keyctl = enabled
+    hix:
+      ansible_ssh_host: 10.111.10.101
+      ansible_user: root
\ No newline at end of file
diff --git a/intern/docker_esphome-dev/tasks/main.yml b/intern/docker_esphome-dev/tasks/main.yml
index a23eef10ceb1aa581df9d1a8f67effc4884dcaad..045d2e4baef7f5bcaf520fd6ffcbf8ce68c383dd 100644
--- a/intern/docker_esphome-dev/tasks/main.yml
+++ b/intern/docker_esphome-dev/tasks/main.yml
@@ -36,12 +36,12 @@
   register: config
 
 - name: "stop {{ servicename }} docker"
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: "{{ basedir }}"
     state: absent
   when: config.changed
 
 - name: "start {{ servicename }} docker"
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: "{{ basedir }}"
     state: present
diff --git a/intern/docker_esphome/tasks/main.yml b/intern/docker_esphome/tasks/main.yml
index ce21f68207ffd378c38c3f583b7342dc2b893cce..d527833dad5cfc1e8568d5ebd0e18587fd6358b6 100644
--- a/intern/docker_esphome/tasks/main.yml
+++ b/intern/docker_esphome/tasks/main.yml
@@ -60,12 +60,12 @@
   register: config
 
 - name: "stop {{ servicename }} docker"
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: "{{ basedir }}"
     state: absent
   when: config.changed
 
 - name: "start {{ servicename }} docker"
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: "{{ basedir }}"
     state: present
diff --git a/intern/docker_esphome/templates/config/esphome_kuehlschrank.yaml b/intern/docker_esphome/templates/config/esphome_kuehlschrank.yaml
index 2db524be95434ceb3621a33f4c4d7310c0e06e72..f15c7268ce99271f973da9694a9d185f2a40a216 100644
--- a/intern/docker_esphome/templates/config/esphome_kuehlschrank.yaml
+++ b/intern/docker_esphome/templates/config/esphome_kuehlschrank.yaml
@@ -93,7 +93,8 @@ binary_sensor:
           white: 100%
       - media_player.play_media:
           id: speaker
-          media_url: 'http://10.0.0.1/filesrv/usb/nootnoot.mp3'
+          media_url: 'http://fridgeserver.warpzone.lan:5000/audio.php'
+
 
 light:
   - platform: neopixelbus
diff --git a/intern/docker_esphome/templates/config/esphome_plug02.yaml b/intern/docker_esphome/templates/config/esphome_plug02.yaml
index c613318bf660449cfe0be546f739392eb6d5aab8..f904a63f2b5403e6849c09f0518d64523f948035 100644
--- a/intern/docker_esphome/templates/config/esphome_plug02.yaml
+++ b/intern/docker_esphome/templates/config/esphome_plug02.yaml
@@ -19,6 +19,10 @@
       payload: "CLOSED"
       then:
         - switch.turn_off: relay
+    - topic: warpzone/door/status_once
+      payload: "OPEN"
+      then:
+        - switch.turn_on: relay
 
 status_led:
   pin:
diff --git a/intern/docker_esphome/templates/config/esphome_plug03.yaml b/intern/docker_esphome/templates/config/esphome_plug03.yaml
index 07c62e6fffa956ea038aa5d3da54eb2d48d01eed..0ee4706da43bde1190644bd7caf1b30884cb1e7a 100644
--- a/intern/docker_esphome/templates/config/esphome_plug03.yaml
+++ b/intern/docker_esphome/templates/config/esphome_plug03.yaml
@@ -19,6 +19,10 @@
       payload: "CLOSED"
       then:
         - switch.turn_off: relay
+    - topic: warpzone/door/status_once
+      payload: "OPEN"
+      then:
+        - switch.turn_on: relay
 
 status_led:
   pin:
diff --git a/intern/docker_esphome/templates/config/esphome_plug04.yaml b/intern/docker_esphome/templates/config/esphome_plug04.yaml
index 04ecaa88b5924626b31540544824ff4d3992610a..596242842158acd630e7e83c29da14727c05715c 100644
--- a/intern/docker_esphome/templates/config/esphome_plug04.yaml
+++ b/intern/docker_esphome/templates/config/esphome_plug04.yaml
@@ -3,7 +3,7 @@
 {% include "/includes/ansible.inc.yaml" %}
 {% include "/includes/board.esp01_1m.inc.yaml" %}
 
-  comment: Halogen Lounge
+  comment: frei
 {% include "/includes/common.inc.yaml" %}
 
   on_message:
diff --git a/intern/docker_esphome/templates/config/esphome_plug07.yaml b/intern/docker_esphome/templates/config/esphome_plug07.yaml
index a2d482abf18ce9780563b4f8c7b19b0f95e51264..56c4caa9023640920cbcc20dd45cb70cf7d6eceb 100644
--- a/intern/docker_esphome/templates/config/esphome_plug07.yaml
+++ b/intern/docker_esphome/templates/config/esphome_plug07.yaml
@@ -19,6 +19,10 @@
       payload: "CLOSED"
       then:
         - switch.turn_off: relay
+    - topic: warpzone/door/status_once
+      payload: "OPEN"
+      then:
+        - switch.turn_on: relay
         
 substitutions:
   plug_name: {{ devicename }}
diff --git a/intern/docker_esphome/templates/config/esphome_plug08.yaml b/intern/docker_esphome/templates/config/esphome_plug08.yaml
index 78daa4fb7b31665d4fa95c7321ca87100e842385..8d53bcbe5ea44dbf887ce0d68d3fa4aeae80738a 100644
--- a/intern/docker_esphome/templates/config/esphome_plug08.yaml
+++ b/intern/docker_esphome/templates/config/esphome_plug08.yaml
@@ -3,7 +3,7 @@
 {% include "/includes/ansible.inc.yaml" %}
 {% include "/includes/board.esp01_1m.inc.yaml" %}
 
-  comment: 3D Drucker Prusanet
+  comment: WLED Vorhang
 {% include "/includes/common.inc.yaml" %}
 
   on_message:
@@ -15,10 +15,10 @@
       payload: "OFF"
       then:
         - switch.turn_off: relay
-    - topic: warpzone/door/status
-      payload: "CLOSED"
+    - topic: warpzone/door/status_once
+      payload: "OPEN"
       then:
-        - switch.turn_off: relay
+        - switch.turn_on: relay
         
 substitutions:
   plug_name: {{ devicename }}
diff --git a/intern/docker_esphome/templates/config/esphome_popcorn.yaml b/intern/docker_esphome/templates/config/esphome_popcorn.yaml
index d8f3f4c8de716280fe00100ea641d3617a10af26..d3b855f24512c2e2caa4cf20a1c1c678bdc2e980 100644
--- a/intern/docker_esphome/templates/config/esphome_popcorn.yaml
+++ b/intern/docker_esphome/templates/config/esphome_popcorn.yaml
@@ -135,7 +135,7 @@ climate:
     id: pid_heater
     name: "PID Heater Controller"
     sensor: pot_sensor
-    default_target_temperature: 240
+    default_target_temperature: 220
     heat_output: pot_heater
     control_parameters:
       kp: 0.09549
diff --git a/intern/docker_esphome/templates/config/esphome_switchboard.yaml b/intern/docker_esphome/templates/config/esphome_switchboard.yaml
index 8dc9eb8a73304fb9678d54d857d08af4c4a7f462..07cea5b0edef179cab4b04090889d495c4be51ea 100644
--- a/intern/docker_esphome/templates/config/esphome_switchboard.yaml
+++ b/intern/docker_esphome/templates/config/esphome_switchboard.yaml
@@ -9,7 +9,7 @@
 
 binary_sensor:
   - platform: gpio
-    pi2n:
+    pin:
       number: GPIO13
       mode: INPUT_PULLUP
       inverted: True
diff --git a/intern/docker_esphome/templates/docker-compose.yml b/intern/docker_esphome/templates/docker-compose.yml
index 82e7f1163ebdb08ebc00f6315ab81cc2a0f305ae..f1975dbc206d1d75777a8a5584b6b15aab558876 100644
--- a/intern/docker_esphome/templates/docker-compose.yml
+++ b/intern/docker_esphome/templates/docker-compose.yml
@@ -4,7 +4,7 @@ services:
 
   app:
 
-    image: esphome/esphome:2022.10
+    image: esphome/esphome:latest
     restart: always
     volumes:
       - "{{ basedir }}/config/:/config"
diff --git a/intern/docker_fridgeserver/tasks/main.yml b/intern/docker_fridgeserver/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..df0aa807054586cb486fe0dcede43d48cea45796
--- /dev/null
+++ b/intern/docker_fridgeserver/tasks/main.yml
@@ -0,0 +1,23 @@
+---
+- name: "create folder struct for {{ servicename }}"
+  ansible.builtin.file:
+    path: "{{ item }}"
+    state: "directory"
+    recurse: yes
+    owner: 33
+    group: 33
+  with_items:
+    - "{{ basedir }}/audio_files/"
+
+- name: copy config files for {{ servicename }}
+  ansible.builtin.template:
+    src: "{{ item }}" 
+    dest: "{{ basedir }}/{{ item }}"
+    mode: '0755'
+  with_items:
+    - docker-compose.yml
+
+- name: start {{ servicename }}
+  community.docker.docker_compose_v2:
+    state: present
+    project_src: "{{ basedir }}"
diff --git a/intern/docker_fridgeserver/templates/docker-compose.yml b/intern/docker_fridgeserver/templates/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..af5966968e9d79318463cfb05dd1f572e9e10fb7
--- /dev/null
+++ b/intern/docker_fridgeserver/templates/docker-compose.yml
@@ -0,0 +1,27 @@
+---
+version: "3.3"
+
+services:
+
+  app:
+    image: gitlab-registry.warpzone.ms/nandxor/fridge-audioserver:latest 
+    restart: always
+    environment:
+      PDIG: 1001
+      PUDI: 1001
+    volumes:
+      - "{{ basedir }}/audio_files:/var/www/html/audio"
+    ports:
+      - "5000:80"
+    labels:
+      - traefik.enable=false
+    networks:
+      - default
+      - web
+
+networks:
+  web:
+    external: true
+
+volumes:
+  audio_files:
diff --git a/intern/docker_fridgeserver/templates/htaccess b/intern/docker_fridgeserver/templates/htaccess
new file mode 100644
index 0000000000000000000000000000000000000000..48c2f41eb7f5bd2d802d59080abefd6a2ddbde09
--- /dev/null
+++ b/intern/docker_fridgeserver/templates/htaccess
@@ -0,0 +1,2 @@
+<Files *.php>
+deny from all
diff --git a/intern/docker_grafana/tasks/main.yml b/intern/docker_grafana/tasks/main.yml
index 8cd9271047cf0245d689d7cce10427edd3d62ad0..819188dcdde045e927e5efc3a5cd96401717f7d1 100644
--- a/intern/docker_grafana/tasks/main.yml
+++ b/intern/docker_grafana/tasks/main.yml
@@ -12,17 +12,41 @@
   with_items:
     - "{{ basedir }}"
     - "{{ basedir }}/data/"   
+    - "{{ basedir }}/provisioning/"
+    - "{{ basedir }}/provisioning/dashboards/"
+    - "{{ basedir }}/provisioning/dashboards/pixelflut/"
+    - "{{ basedir }}/provisioning/datasources/"
 
 - name: create config filess
   template: 
     src: "{{ item }}" 
     dest: "{{ basedir }}/{{ item }}"
   with_items:
-    - datasources.yml
     - docker-compose.yml
     - grafana.ini
 
+- name: create dashboards
+  template:
+    src: "provisioning/dashboards/{{ item }}"
+    dest: "{{ basedir }}/provisioning/dashboards/{{ item }}"
+  with_items:
+    - dashboards.yml
+
+- name: create dashboards for pixelflut
+  template:
+    src: "provisioning/dashboards/pixelflut/{{ item }}"
+    dest: "{{ basedir }}/provisioning/dashboards/pixelflut/{{ item }}"
+  with_items:
+    - breakwater.json
+
+- name: create datasources
+  template:
+    src: "provisioning/datasources/{{ item }}"
+    dest: "{{ basedir }}/provisioning/datasources/{{ item }}"
+  with_items:
+    - datasources.yml
+
 - name: start grafana docker
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: "{{ basedir }}"
     state: present
diff --git a/intern/docker_grafana/templates/docker-compose.yml b/intern/docker_grafana/templates/docker-compose.yml
index 3a05212ed804cd15a7e03655f2b73190b7b26a0e..e8d66fe5b8f05a23d58a56b04905cbbbddc9115f 100644
--- a/intern/docker_grafana/templates/docker-compose.yml
+++ b/intern/docker_grafana/templates/docker-compose.yml
@@ -4,11 +4,11 @@ services:
 
   app:
 
-    image: grafana/grafana:9.4.3
+    image: grafana/grafana:latest
     restart: always
     volumes:
       - "{{ basedir }}/grafana.ini:/etc/grafana/grafana.ini"
-      - "{{ basedir }}/datasources.yml:/etc/grafana/provisioning/datasources/datasources.yml"
+      - "{{ basedir }}/provisioning/:/etc/grafana/provisioning/"
       - "{{ basedir }}/data/:/var/lib/grafana"
     environment:
       GF_SERVER_ROOT_URL: "https://{{ domain }}"
diff --git a/intern/docker_grafana/templates/provisioning/dashboards/dashboards.yml b/intern/docker_grafana/templates/provisioning/dashboards/dashboards.yml
new file mode 100644
index 0000000000000000000000000000000000000000..45bfb06d0dd4bcfe6e17b08a33a5d1cc1477c6ac
--- /dev/null
+++ b/intern/docker_grafana/templates/provisioning/dashboards/dashboards.yml
@@ -0,0 +1,25 @@
+apiVersion: 1
+
+providers:
+  # <string> an unique provider name
+- name: 'Pixelflut'
+  # <int> org id. will default to orgId 1 if not specified
+  # orgId: 1
+  # <string, required> name of the dashboard folder. Required
+  folder: 'Pixelflut'
+  # <string> folder UID. will be automatically generated if not specified
+  # folderUid: ''
+  # <string, required> provider type. Required
+  type: file
+  # <bool> disable dashboard deletion
+  # disableDeletion: false
+  # <bool> enable dashboard editing
+  editable: true
+  # <int> how often Grafana will scan for changed dashboards
+  updateIntervalSeconds: 10
+  # <bool> allow updating provisioned dashboards from the UI
+  allowUiUpdates: true
+  options:
+    # <string, required> path to dashboard files on disk. Required
+    path: /etc/grafana/provisioning/dashboards/pixelflut
+
diff --git a/intern/docker_grafana/templates/provisioning/dashboards/pixelflut/breakwater.json b/intern/docker_grafana/templates/provisioning/dashboards/pixelflut/breakwater.json
new file mode 100644
index 0000000000000000000000000000000000000000..5eebc771ff054207d86b699f7dc08ea4a5bab2c9
--- /dev/null
+++ b/intern/docker_grafana/templates/provisioning/dashboards/pixelflut/breakwater.json
@@ -0,0 +1,1055 @@
+{
+  "annotations": {
+    "list": [
+      {
+        "builtIn": 1,
+        "datasource": "-- Grafana --",
+        "enable": true,
+        "hide": true,
+        "iconColor": "rgba(0, 211, 255, 1)",
+        "name": "Annotations & Alerts",
+        "target": {
+          "limit": 100,
+          "matchAny": false,
+          "tags": [],
+          "type": "dashboard"
+        },
+        "type": "dashboard"
+      }
+    ]
+  },
+  "editable": true,
+  "fiscalYearStartMonth": 0,
+  "graphTooltip": 1,
+  "id": 6,
+  "links": [],
+  "liveNow": false,
+  "panels": [
+    {
+      "datasource": {
+        "type": "prometheus",
+        "uid": "P0FAC05DE14135586"
+      },
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "thresholds"
+          },
+          "mappings": [],
+          "noValue": "0",
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "red",
+                "value": 80
+              }
+            ]
+          }
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 5,
+        "w": 3,
+        "x": 0,
+        "y": 0
+      },
+      "id": 6,
+      "options": {
+        "colorMode": "value",
+        "graphMode": "area",
+        "justifyMode": "auto",
+        "orientation": "auto",
+        "reduceOptions": {
+          "calcs": [
+            "lastNotNull"
+          ],
+          "fields": "",
+          "values": false
+        },
+        "text": {},
+        "textMode": "auto"
+      },
+      "pluginVersion": "8.4.6",
+      "targets": [
+        {
+          "datasource": {
+            "type": "prometheus",
+            "uid": "P0FAC05DE14135586"
+          },
+          "exemplar": true,
+          "expr": "breakwater_ips",
+          "interval": "",
+          "legendFormat": "",
+          "refId": "A"
+        }
+      ],
+      "title": "Connected IPs",
+      "type": "stat"
+    },
+    {
+      "datasource": {
+        "type": "prometheus",
+        "uid": "P0FAC05DE14135586"
+      },
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "fixedColor": "green",
+            "mode": "fixed"
+          },
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "red",
+                "value": 80
+              }
+            ]
+          }
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 5,
+        "w": 3,
+        "x": 3,
+        "y": 0
+      },
+      "id": 7,
+      "options": {
+        "colorMode": "value",
+        "graphMode": "area",
+        "justifyMode": "auto",
+        "orientation": "auto",
+        "reduceOptions": {
+          "calcs": [
+            "lastNotNull"
+          ],
+          "fields": "",
+          "values": false
+        },
+        "textMode": "auto"
+      },
+      "pluginVersion": "8.4.6",
+      "targets": [
+        {
+          "datasource": {
+            "type": "prometheus",
+            "uid": "P0FAC05DE14135586"
+          },
+          "exemplar": true,
+          "expr": "sum(breakwater_connections) or vector(0)",
+          "interval": "",
+          "legendFormat": "",
+          "refId": "A"
+        }
+      ],
+      "title": "Connections",
+      "type": "stat"
+    },
+    {
+      "datasource": {
+        "type": "prometheus",
+        "uid": "P0FAC05DE14135586"
+      },
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "thresholds"
+          },
+          "mappings": [],
+          "noValue": "0",
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "red",
+                "value": null
+              },
+              {
+                "color": "green",
+                "value": 25
+              }
+            ]
+          },
+          "unit": "FPS"
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 5,
+        "w": 3,
+        "x": 9,
+        "y": 0
+      },
+      "id": 15,
+      "options": {
+        "colorMode": "value",
+        "graphMode": "area",
+        "justifyMode": "auto",
+        "orientation": "auto",
+        "reduceOptions": {
+          "calcs": [
+            "lastNotNull"
+          ],
+          "fields": "",
+          "values": false
+        },
+        "textMode": "auto"
+      },
+      "pluginVersion": "8.4.6",
+      "targets": [
+        {
+          "datasource": {
+            "type": "prometheus",
+            "uid": "P0FAC05DE14135586"
+          },
+          "exemplar": true,
+          "expr": "breakwater_fps",
+          "interval": "",
+          "legendFormat": "",
+          "refId": "A"
+        }
+      ],
+      "title": "FPS",
+      "type": "stat"
+    },
+    {
+      "datasource": {
+        "type": "prometheus",
+        "uid": "P0FAC05DE14135586"
+      },
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "fixedColor": "green",
+            "mode": "fixed"
+          },
+          "mappings": [],
+          "noValue": "0",
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "red",
+                "value": 80
+              }
+            ]
+          },
+          "unit": "binbps"
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 5,
+        "w": 3,
+        "x": 12,
+        "y": 0
+      },
+      "id": 19,
+      "options": {
+        "colorMode": "value",
+        "graphMode": "area",
+        "justifyMode": "auto",
+        "orientation": "auto",
+        "reduceOptions": {
+          "calcs": [
+            "lastNotNull"
+          ],
+          "fields": "",
+          "values": false
+        },
+        "textMode": "auto"
+      },
+      "pluginVersion": "8.4.6",
+      "targets": [
+        {
+          "datasource": {
+            "type": "prometheus",
+            "uid": "P0FAC05DE14135586"
+          },
+          "exemplar": true,
+          "expr": "sum(rate(breakwater_bytes[1m])) * 8  or vector(0)",
+          "interval": "",
+          "legendFormat": "",
+          "refId": "A"
+        }
+      ],
+      "title": "Throughput",
+      "type": "stat"
+    },
+    {
+      "datasource": {
+        "type": "prometheus",
+        "uid": "P0FAC05DE14135586"
+      },
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "thresholds"
+          },
+          "mappings": [],
+          "noValue": "0",
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              }
+            ]
+          },
+          "unit": "bytes"
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 5,
+        "w": 3,
+        "x": 15,
+        "y": 0
+      },
+      "id": 9,
+      "options": {
+        "colorMode": "value",
+        "graphMode": "area",
+        "justifyMode": "auto",
+        "orientation": "auto",
+        "reduceOptions": {
+          "calcs": [
+            "lastNotNull"
+          ],
+          "fields": "",
+          "values": false
+        },
+        "textMode": "auto"
+      },
+      "pluginVersion": "8.4.6",
+      "targets": [
+        {
+          "datasource": {
+            "type": "prometheus",
+            "uid": "P0FAC05DE14135586"
+          },
+          "exemplar": true,
+          "expr": "sum(breakwater_bytes) or vector(0)",
+          "interval": "",
+          "legendFormat": "",
+          "refId": "A"
+        }
+      ],
+      "title": "Total Traffic",
+      "type": "stat"
+    },
+    {
+      "datasource": {
+        "type": "prometheus",
+        "uid": "P0FAC05DE14135586"
+      },
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "fixedColor": "green",
+            "mode": "fixed"
+          },
+          "mappings": [],
+          "noValue": "0",
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "red",
+                "value": 80
+              }
+            ]
+          },
+          "unit": "reqps"
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 5,
+        "w": 3,
+        "x": 18,
+        "y": 0
+      },
+      "id": 16,
+      "options": {
+        "colorMode": "value",
+        "graphMode": "area",
+        "justifyMode": "auto",
+        "orientation": "auto",
+        "reduceOptions": {
+          "calcs": [
+            "lastNotNull"
+          ],
+          "fields": "",
+          "values": false
+        },
+        "textMode": "auto"
+      },
+      "pluginVersion": "8.4.6",
+      "targets": [
+        {
+          "datasource": {
+            "type": "prometheus",
+            "uid": "P0FAC05DE14135586"
+          },
+          "exemplar": true,
+          "expr": "sum(rate(breakwater_pixels[1m])) * 8  or vector(0)",
+          "interval": "",
+          "legendFormat": "",
+          "refId": "A"
+        }
+      ],
+      "title": "Pixels / s",
+      "type": "stat"
+    },
+    {
+      "datasource": {
+        "type": "prometheus",
+        "uid": "P0FAC05DE14135586"
+      },
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "thresholds"
+          },
+          "mappings": [],
+          "noValue": "0",
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              }
+            ]
+          },
+          "unit": "short"
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 5,
+        "w": 3,
+        "x": 21,
+        "y": 0
+      },
+      "id": 17,
+      "options": {
+        "colorMode": "value",
+        "graphMode": "area",
+        "justifyMode": "auto",
+        "orientation": "auto",
+        "reduceOptions": {
+          "calcs": [
+            "lastNotNull"
+          ],
+          "fields": "",
+          "values": false
+        },
+        "textMode": "auto"
+      },
+      "pluginVersion": "8.4.6",
+      "targets": [
+        {
+          "datasource": {
+            "type": "prometheus",
+            "uid": "P0FAC05DE14135586"
+          },
+          "exemplar": true,
+          "expr": "sum(breakwater_pixels) or vector(0)",
+          "interval": "",
+          "legendFormat": "",
+          "refId": "A"
+        }
+      ],
+      "title": "Total Pixels",
+      "type": "stat"
+    },
+    {
+      "datasource": {
+        "type": "prometheus",
+        "uid": "P0FAC05DE14135586"
+      },
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "palette-classic"
+          },
+          "custom": {
+            "axisLabel": "",
+            "axisPlacement": "auto",
+            "barAlignment": 0,
+            "drawStyle": "line",
+            "fillOpacity": 0,
+            "gradientMode": "none",
+            "hideFrom": {
+              "legend": false,
+              "tooltip": false,
+              "viz": false
+            },
+            "lineInterpolation": "linear",
+            "lineWidth": 1,
+            "pointSize": 5,
+            "scaleDistribution": {
+              "type": "linear"
+            },
+            "showPoints": "never",
+            "spanNulls": false,
+            "stacking": {
+              "group": "A",
+              "mode": "none"
+            },
+            "thresholdsStyle": {
+              "mode": "off"
+            }
+          },
+          "decimals": 0,
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "red",
+                "value": 80
+              }
+            ]
+          }
+        },
+        "overrides": [
+          {
+            "matcher": {
+              "id": "byName",
+              "options": "IPv4"
+            },
+            "properties": [
+              {
+                "id": "color",
+                "value": {
+                  "fixedColor": "yellow",
+                  "mode": "fixed"
+                }
+              }
+            ]
+          },
+          {
+            "matcher": {
+              "id": "byName",
+              "options": "All"
+            },
+            "properties": [
+              {
+                "id": "color",
+                "value": {
+                  "fixedColor": "green",
+                  "mode": "fixed"
+                }
+              }
+            ]
+          }
+        ]
+      },
+      "gridPos": {
+        "h": 8,
+        "w": 12,
+        "x": 0,
+        "y": 5
+      },
+      "id": 13,
+      "options": {
+        "legend": {
+          "calcs": [
+            "last",
+            "max"
+          ],
+          "displayMode": "table",
+          "placement": "right"
+        },
+        "tooltip": {
+          "mode": "single",
+          "sort": "none"
+        }
+      },
+      "targets": [
+        {
+          "datasource": {
+            "type": "prometheus",
+            "uid": "P0FAC05DE14135586"
+          },
+          "exemplar": true,
+          "expr": "breakwater_ips",
+          "interval": "",
+          "legendFormat": "All",
+          "refId": "A"
+        },
+        {
+          "datasource": {
+            "type": "prometheus",
+            "uid": "P0FAC05DE14135586"
+          },
+          "exemplar": true,
+          "expr": "breakwater_legacy_ips",
+          "hide": false,
+          "interval": "",
+          "legendFormat": "IPv4",
+          "refId": "B"
+        }
+      ],
+      "title": "Connected IPs",
+      "type": "timeseries"
+    },
+    {
+      "datasource": {
+        "type": "prometheus",
+        "uid": "P0FAC05DE14135586"
+      },
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "palette-classic"
+          },
+          "custom": {
+            "axisLabel": "",
+            "axisPlacement": "auto",
+            "barAlignment": 0,
+            "drawStyle": "line",
+            "fillOpacity": 10,
+            "gradientMode": "none",
+            "hideFrom": {
+              "legend": false,
+              "tooltip": false,
+              "viz": false
+            },
+            "lineInterpolation": "linear",
+            "lineWidth": 1,
+            "pointSize": 5,
+            "scaleDistribution": {
+              "type": "linear"
+            },
+            "showPoints": "never",
+            "spanNulls": false,
+            "stacking": {
+              "group": "A",
+              "mode": "normal"
+            },
+            "thresholdsStyle": {
+              "mode": "off"
+            }
+          },
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "red",
+                "value": 80
+              }
+            ]
+          },
+          "unit": "bps"
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 8,
+        "w": 12,
+        "x": 12,
+        "y": 5
+      },
+      "id": 14,
+      "interval": "1m",
+      "options": {
+        "legend": {
+          "calcs": [
+            "last",
+            "max"
+          ],
+          "displayMode": "table",
+          "placement": "right",
+          "sortBy": "Last",
+          "sortDesc": true
+        },
+        "tooltip": {
+          "mode": "single",
+          "sort": "none"
+        }
+      },
+      "targets": [
+        {
+          "datasource": {
+            "type": "prometheus",
+            "uid": "P0FAC05DE14135586"
+          },
+          "exemplar": true,
+          "expr": "rate(breakwater_bytes[$__interval]) * 8",
+          "interval": "",
+          "legendFormat": "pixelflut.warpzone.lan",
+          "refId": "A"
+        }
+      ],
+      "title": "Traffic / IP",
+      "type": "timeseries"
+    },
+    {
+      "datasource": {
+        "type": "prometheus",
+        "uid": "P0FAC05DE14135586"
+      },
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "palette-classic"
+          },
+          "custom": {
+            "axisLabel": "",
+            "axisPlacement": "auto",
+            "barAlignment": 0,
+            "drawStyle": "line",
+            "fillOpacity": 10,
+            "gradientMode": "none",
+            "hideFrom": {
+              "legend": false,
+              "tooltip": false,
+              "viz": false
+            },
+            "lineInterpolation": "linear",
+            "lineWidth": 1,
+            "pointSize": 5,
+            "scaleDistribution": {
+              "type": "linear"
+            },
+            "showPoints": "never",
+            "spanNulls": false,
+            "stacking": {
+              "group": "A",
+              "mode": "normal"
+            },
+            "thresholdsStyle": {
+              "mode": "off"
+            }
+          },
+          "decimals": 0,
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "red",
+                "value": 80
+              }
+            ]
+          }
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 8,
+        "w": 12,
+        "x": 0,
+        "y": 13
+      },
+      "id": 11,
+      "options": {
+        "legend": {
+          "calcs": [
+            "last",
+            "max"
+          ],
+          "displayMode": "table",
+          "placement": "right",
+          "sortBy": "Last",
+          "sortDesc": true
+        },
+        "tooltip": {
+          "mode": "single",
+          "sort": "none"
+        }
+      },
+      "targets": [
+        {
+          "datasource": {
+            "type": "prometheus",
+            "uid": "P0FAC05DE14135586"
+          },
+          "exemplar": true,
+          "expr": "breakwater_connections",
+          "interval": "",
+          "legendFormat": "pixelflut.warpzone.lan",
+          "refId": "A"
+        }
+      ],
+      "title": "Connections / IP",
+      "type": "timeseries"
+    },
+    {
+      "datasource": {
+        "type": "prometheus",
+        "uid": "P0FAC05DE14135586"
+      },
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "palette-classic"
+          },
+          "custom": {
+            "axisLabel": "",
+            "axisPlacement": "auto",
+            "barAlignment": 0,
+            "drawStyle": "line",
+            "fillOpacity": 10,
+            "gradientMode": "none",
+            "hideFrom": {
+              "legend": false,
+              "tooltip": false,
+              "viz": false
+            },
+            "lineInterpolation": "linear",
+            "lineWidth": 1,
+            "pointSize": 5,
+            "scaleDistribution": {
+              "type": "linear"
+            },
+            "showPoints": "never",
+            "spanNulls": false,
+            "stacking": {
+              "group": "A",
+              "mode": "normal"
+            },
+            "thresholdsStyle": {
+              "mode": "off"
+            }
+          },
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "red",
+                "value": 80
+              }
+            ]
+          },
+          "unit": "reqps"
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 8,
+        "w": 12,
+        "x": 12,
+        "y": 13
+      },
+      "id": 18,
+      "interval": "1m",
+      "options": {
+        "legend": {
+          "calcs": [
+            "last",
+            "max"
+          ],
+          "displayMode": "table",
+          "placement": "right",
+          "sortBy": "Last",
+          "sortDesc": true
+        },
+        "tooltip": {
+          "mode": "single",
+          "sort": "none"
+        }
+      },
+      "targets": [
+        {
+          "datasource": {
+            "type": "prometheus",
+            "uid": "P0FAC05DE14135586"
+          },
+          "exemplar": true,
+          "expr": "rate(breakwater_pixels[$__interval]) * 8",
+          "interval": "",
+          "legendFormat": "pixelflut.warpzone.lan",
+          "refId": "A"
+        }
+      ],
+      "title": "Pixels / s / IP",
+      "type": "timeseries"
+    },
+    {
+      "datasource": {
+        "type": "prometheus",
+        "uid": "P0FAC05DE14135586"
+      },
+      "description": "",
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "fixedColor": "green",
+            "mode": "thresholds"
+          },
+          "custom": {
+            "axisLabel": "",
+            "axisPlacement": "auto",
+            "barAlignment": 0,
+            "drawStyle": "line",
+            "fillOpacity": 0,
+            "gradientMode": "none",
+            "hideFrom": {
+              "legend": false,
+              "tooltip": false,
+              "viz": false
+            },
+            "lineInterpolation": "linear",
+            "lineWidth": 1,
+            "pointSize": 5,
+            "scaleDistribution": {
+              "type": "linear"
+            },
+            "showPoints": "never",
+            "spanNulls": false,
+            "stacking": {
+              "group": "A",
+              "mode": "none"
+            },
+            "thresholdsStyle": {
+              "mode": "off"
+            }
+          },
+          "mappings": [],
+          "noValue": "0",
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "red",
+                "value": null
+              },
+              {
+                "color": "green",
+                "value": 25
+              }
+            ]
+          },
+          "unit": "FPS"
+        },
+        "overrides": [
+          {
+            "matcher": {
+              "id": "byName",
+              "options": "30 FPS"
+            },
+            "properties": [
+              {
+                "id": "color",
+                "value": {
+                  "fixedColor": "dark-green",
+                  "mode": "fixed"
+                }
+              }
+            ]
+          }
+        ]
+      },
+      "gridPos": {
+        "h": 6,
+        "w": 12,
+        "x": 12,
+        "y": 21
+      },
+      "id": 21,
+      "options": {
+        "legend": {
+          "calcs": [],
+          "displayMode": "hidden",
+          "placement": "bottom"
+        },
+        "tooltip": {
+          "mode": "single",
+          "sort": "none"
+        }
+      },
+      "pluginVersion": "8.4.6",
+      "targets": [
+        {
+          "datasource": {
+            "type": "prometheus",
+            "uid": "P0FAC05DE14135586"
+          },
+          "exemplar": true,
+          "expr": "breakwater_fps{}",
+          "interval": "",
+          "legendFormat": "Measured",
+          "refId": "A"
+        },
+        {
+          "datasource": {
+            "type": "prometheus",
+            "uid": "P0FAC05DE14135586"
+          },
+          "exemplar": true,
+          "expr": "30",
+          "hide": false,
+          "interval": "",
+          "legendFormat": "30 FPS",
+          "refId": "B"
+        }
+      ],
+      "title": "FPS",
+      "type": "timeseries"
+    }
+  ],
+  "refresh": false,
+  "schemaVersion": 35,
+  "style": "dark",
+  "tags": [
+    "pixelflut",
+    "breakwater"
+  ],
+  "templating": {
+    "list": []
+  },
+  "time": {
+    "from": "now-1h",
+    "to": "now"
+  },
+  "timepicker": {},
+  "timezone": "",
+  "title": "Pixelflut overview",
+  "uid": "bfgb09843",
+  "weekStart": ""
+}
diff --git a/intern/docker_grafana/templates/datasources.yml b/intern/docker_grafana/templates/provisioning/datasources/datasources.yml
similarity index 81%
rename from intern/docker_grafana/templates/datasources.yml
rename to intern/docker_grafana/templates/provisioning/datasources/datasources.yml
index 2c3e31a00bcc5f03bd6117de1d3bedf4aba192e7..8e9cb3f4717e00fa8cd63179a593193f462cdb66 100644
--- a/intern/docker_grafana/templates/datasources.yml
+++ b/intern/docker_grafana/templates/provisioning/datasources/datasources.yml
@@ -35,3 +35,13 @@ datasources:
     url: http://{{ int_ip4 }}:9090
 
 {% endif %}
+
+{% if inventory_hostname == 'ogg' %}
+
+  - name: Pixelflut
+    type: prometheus
+    access: proxy
+    url: http://pixelflut.warpzone.lan:9090
+    uuid: P0FAC05DE14135586
+
+{% endif %}
diff --git a/intern/docker_graylog/tasks/main.yml b/intern/docker_graylog/tasks/main.yml
deleted file mode 100644
index 38e57a0bf8d8bd82454a1fc32046d49d3ecb3fef..0000000000000000000000000000000000000000
--- a/intern/docker_graylog/tasks/main.yml
+++ /dev/null
@@ -1,29 +0,0 @@
----
-
-- name: "create folder struct for {{ servicename }}"
-  file: 
-    path: "{{ basedir }}" 
-    state: "directory"
-
-- name: "create folder struct for {{ servicename }}"
-  file: 
-    path: "{{ basedir }}/{{ item }}" 
-    state: "directory"
-    owner: 508
-    group: 508
-  with_items:
-    - "data"
-    - "logs"
-
-- name: "create config files for {{ servicename }}"
-  template: 
-    src: "{{ item }}"
-    dest: "{{ basedir }}/{{ item }}"
-  with_items:
-    - docker-compose.yml 
-
-- name: "start {{ servicename }} docker"
-  docker_compose:
-    project_src: "{{ basedir }}"
-    state: present
-
diff --git a/intern/docker_graylog/templates/docker-compose.yml b/intern/docker_graylog/templates/docker-compose.yml
deleted file mode 100644
index 2b2f890ac9420269a609ef9843159eb8331e7215..0000000000000000000000000000000000000000
--- a/intern/docker_graylog/templates/docker-compose.yml
+++ /dev/null
@@ -1,48 +0,0 @@
-version: "3"
-
-services:
-  mongodb:
-    image: "mongo:6.0.4"
-    restart: "always"
-
-  opensearch:
-    image: "opensearchproject/opensearch:2.6.0"
-    environment:
-      - "TZ=Europe/Berlin"
-      - "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g"
-      - "bootstrap.memory_lock=true"
-      - "discovery.type=single-node"
-      - "action.auto_create_index=false"
-      - "plugins.security.ssl.http.enabled=false"
-      - "plugins.security.disabled=true"
-    restart: "always"
-
-  graylog:
-    hostname: "server"
-    image: "graylog/graylog:5.0.5"
-    entrypoint: "/usr/bin/tini -- wait-for-it opensearch:9200 --  /docker-entrypoint.sh"
-    environment:
-      TZ: "Europe/Berlin"
-      GRAYLOG_NODE_ID_FILE: "/usr/share/graylog/data/config/node-id"
-      GRAYLOG_PASSWORD_SECRET: "warpzonewarpzone"
-      GRAYLOG_ROOT_PASSWORD_SHA2: "26230bc6e5e044e6e3cef7c76a2800fdf2d3952ef03e85c83491b99eef149c40"
-      GRAYLOG_HTTP_BIND_ADDRESS: "0.0.0.0:9000"
-      GRAYLOG_HTTP_EXTERNAL_URI: "http://graylog.warpzone.lan/"
-      GRAYLOG_ELASTICSEARCH_HOSTS: "http://opensearch:9200"
-      GRAYLOG_MONGODB_URI: "mongodb://mongodb:27017/graylog"
-    ports:
-      - "514:5140/udp"   # Syslog
-      - "514:5140/tcp"   # Syslog
-    restart: "always"
-    labels:
-      - traefik.enable=true
-      - traefik.http.routers.{{ servicename }}.rule=Host(`{{ domain }}`)
-      - traefik.http.routers.{{ servicename }}.entrypoints=websecure
-      - traefik.http.services.{{ servicename }}.loadbalancer.server.port=9000
-    networks:
-      - web
-      - default
-
-networks:
-  web:
-    external: true
diff --git a/intern/docker_heimdall/tasks/main.yml b/intern/docker_heimdall/tasks/main.yml
index 45a8fbf7395088b62163cc241c76043bccbdedc9..d34c8ab5464a1020f7a5c5f684868de2ce83d64e 100644
--- a/intern/docker_heimdall/tasks/main.yml
+++ b/intern/docker_heimdall/tasks/main.yml
@@ -16,6 +16,6 @@
     - docker-compose.yml
 
 - name: start {{ servicename }}
-  community.docker.docker_compose:
+  community.docker.docker_compose_v2:
     state: present
     project_src: "{{ basedir }}"
diff --git a/intern/docker_heimdall/templates/docker-compose.yml b/intern/docker_heimdall/templates/docker-compose.yml
index 6eb20682f9094cb9769ebb6335b5d53306a5d2e0..9722de418eb81c034885c7c0e8a5d5816805e5c9 100644
--- a/intern/docker_heimdall/templates/docker-compose.yml
+++ b/intern/docker_heimdall/templates/docker-compose.yml
@@ -4,7 +4,7 @@ version: "2.1"
 services:
 
   app:
-    image: lscr.io/linuxserver/heimdall:2.5.6
+    image: lscr.io/linuxserver/heimdall:latest
     restart: always
     environment:
       - PUID=1000
diff --git a/intern/docker_homeassistant/tasks/main.yml b/intern/docker_homeassistant/tasks/main.yml
index f4c07134a06e6e3146291649b1a1702a69419794..c1f61a9788c803e7691208464d60544e8bb46ccf 100644
--- a/intern/docker_homeassistant/tasks/main.yml
+++ b/intern/docker_homeassistant/tasks/main.yml
@@ -1,8 +1,9 @@
 ---
 
-- include: ../functions/get_secret.yml
+- include_tasks: ../functions/get_secret.yml
   with_items:
    - { path: "{{ basedir }}/warpai_status_update_key",     length: -1 }
+   - { path: "{{ basedir }}/portal_password",              length: -1 }
    - { path: "{{ basedir }}/homeassistant_admin_password", length: 12 }
    - { path: "{{ basedir }}/influxdb_password",            length: 12 }
    - { path: "{{ basedir }}/influxdb_token",               length: 32 }
@@ -29,13 +30,13 @@
 
 
 - name: "stop {{ servicename }} docker"
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: "{{ basedir }}"
     state: absent
   when: config_files.changed 
 
 
 - name: "start {{ servicename }} docker"
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: "{{ basedir }}"
     state: present
diff --git a/intern/docker_homeassistant/templates/config/configuration.yaml b/intern/docker_homeassistant/templates/config/configuration.yaml
index 8b3fe2c99971aeaceb5e368ac2f182895636543d..aa7bf2e15e34502a5c94bf3488d9e600a34eb2c7 100644
--- a/intern/docker_homeassistant/templates/config/configuration.yaml
+++ b/intern/docker_homeassistant/templates/config/configuration.yaml
@@ -54,6 +54,14 @@ influxdb:
   token: {{ influxdb_token }}
   default_measurement: units
 
+
+# eQ3 Max 
+maxcube:
+  gateways:
+    - host: {{ eq3max.cube_host }}
+      port: 62910
+      scan_interval: 60
+
 # zonenstatus wird vom hauptschalter gesteuert, switch02 ping ist nicht mehr notwendig
 # https://www.home-assistant.io/integrations/ping/
 #binary_sensor:
@@ -71,6 +79,15 @@ rest_command:
   set_zone_status_closed: 
     url: "https://api.warpzone.ms/setstatus?newstatus=CLOSED&update_key={{ warpai_status_update_key }}"
     method: GET 
+  set_lounge_matrix_off:
+    url: "http://led-matrix.warpzone.lan/play/off.png"
+    method: GET
+  set_lounge_matrix_on:
+    url: "http://led-matrix.warpzone.lan/skip"
+    method: GET
+  open_door:
+    url: "http://shippo.warpzone.lan:7000/open_door?username=warpzone&password={{ portal_password }}"
+    method: GET
 
 # https://www.home-assistant.io/integrations/telegram/
 telegram_bot:
@@ -240,3 +257,527 @@ automation ansible:
                   timeout: 30
                   message: Die warpzone ist seit {{ '{{' }} states('sensor.time') {{ '}}' }} geschlossen!
     mode: restart
+  
+  # Stromverbrauch auf Telegram senden
+  - alias: ANSIBLE_stromverbrauch_send_telegram
+    description: Sendet alle 10 Minuten den Stromverbrauch per Telegram
+    trigger:
+      - platform: time_pattern
+        minutes: /10
+    condition: []
+    action:
+      - if:
+        - condition: state
+          entity_id: automation.ansible_zonenstatus_send_telegram
+          attribute: current
+          state: "1"
+        then:
+          - wait_for_trigger:
+            - platform: state
+              entity_id:
+                - automation.ansible_zonenstatus_send_telegram
+              attribute: current
+              to: "0"
+      - service: telegram_bot.send_message
+        data:
+          target: -1001341516106
+          timeout: 30
+          message: >-
+            {{ '{{' }} states('sensor.esphome_status_power') {{ '}}' }} kW bei angenehmen {{ '{{' }} states('sensor.temp') {{ '}}' }}°C
+    mode: restart
+
+  # Licht im Hackcenter dimmen
+  - alias: ANSIBLE_dali_licht_hackcenter
+    description: Ruft den Helper aus um per MQTT das Licht zu dimmen
+    trigger:
+      - platform: state
+        entity_id:
+          - input_number.dali_licht_hackcenter
+        for:
+          hours: 0
+          minutes: 0
+          seconds: 0
+    action:
+      - service: mqtt.publish
+        data:
+          topic: light/dali
+          payload_template: "{{ '{{' }} states('input_number.dali_licht_hackcenter') | int {{ '}}' }}"
+    mode: restart
+
+  # Feinstaubsensor steuert Luftfilter
+  - alias: ANSIBLE_Feinstaubsensor_Luftfilter
+    description: Feinstaubsensor steuer Luftfilter
+    trigger:
+      - platform: time_pattern
+        seconds: /10
+    condition: []
+    action:
+      - choose:
+          - conditions:
+              - condition: numeric_state
+                entity_id: sensor.feinstaub_2_5
+                below: 36
+            sequence:
+              - service: fan.set_percentage
+                data:
+                  percentage: 33
+                target:
+                  device_id: 8b6ff876340558ef11d13441afecec8d
+          - conditions:
+              - condition: numeric_state
+                entity_id: sensor.feinstaub_2_5
+                above: 35
+                below: 86
+            sequence:
+              - service: fan.set_percentage
+                data:
+                  percentage: 66
+                target:
+                  device_id: 8b6ff876340558ef11d13441afecec8d
+          - conditions:
+              - condition: numeric_state
+                entity_id: sensor.feinstaub_2_5
+                above: 85
+            sequence:
+              - service: fan.set_percentage
+                data:
+                  percentage: 100
+                target:
+                  device_id: 8b6ff876340558ef11d13441afecec8d
+    mode: restart
+
+
+  # Feinstaubsensor steuert Ampel
+  - alias: ANSIBLE_Feinstaubsensor_Ampel
+    description: Feinstaubsensor status auf Ampel anzeigen
+    trigger:
+      - platform: time_pattern
+        seconds: /10
+    condition: []
+    action:
+      - choose:
+          - conditions:
+              - condition: numeric_state
+                entity_id: sensor.feinstaub_2_5
+                below: 36
+            sequence:
+              - device_id: e26403f906b93f7c6b4f5339a21f9b26
+                domain: select
+                entity_id: select.ampel_preset
+                type: select_option
+                option: Green static
+          - conditions:
+              - condition: numeric_state
+                entity_id: sensor.feinstaub_2_5
+                above: 35
+                below: 86
+            sequence:
+              - device_id: e26403f906b93f7c6b4f5339a21f9b26
+                domain: select
+                entity_id: select.ampel_preset
+                type: select_option
+                option: Orange static
+          - conditions:
+              - condition: numeric_state
+                entity_id: sensor.feinstaub_2_5
+                above: 85
+            sequence:
+              - device_id: e26403f906b93f7c6b4f5339a21f9b26
+                domain: select
+                entity_id: select.ampel_preset
+                type: select_option
+                option: Red static
+    mode: restart
+
+  # WLED rot lounge
+  - alias: ANSIBLE_WLED_lounge_red
+    description: WLED rot in der lounge
+    trigger:
+      - type: turned_on
+        platform: device
+        device_id: 33915e12bd114226dcd4718e77a27779
+        entity_id: binary_sensor.button_5
+        domain: binary_sensor
+    condition: []
+    action:
+      - service: light.turn_on
+        data:
+          rgb_color:
+            - 255
+            - 0
+            - 0
+          effect: Solid
+        target:
+          area_id:
+            - kuche
+            - lounge
+            - serverrack
+    mode: queued
+    max: 30
+
+  # WLED rot im hackcenter
+  - alias: ANSIBLE_WLED_hackcenter_red
+    description: WLED rot im hackcenter
+    trigger:
+      - type: turned_on
+        platform: device
+        device_id: 33915e12bd114226dcd4718e77a27779
+        entity_id: binary_sensor.button_2
+        domain: binary_sensor
+    condition: []
+    action:
+      - service: light.turn_on
+        data:
+          rgb_color:
+            - 255
+            - 0
+            - 0
+          effect: Solid
+        target:
+          area_id:
+            - hackcenter
+            - eingang
+    mode: queued
+    max: 30
+
+
+  # WLED gruen lounge
+  - alias: ANSIBLE_WLED_lounge_green
+    description: WLED gruen in der lounge
+    trigger:
+      - type: turned_on
+        platform: device
+        device_id: 33915e12bd114226dcd4718e77a27779
+        entity_id: binary_sensor.button_5
+        domain: binary_sensor
+        for:
+          hours: 0
+          minutes: 0
+          seconds: 1
+    condition: []
+    action:
+      - service: light.turn_on
+        data:
+          rgb_color:
+            - 0
+            - 255
+            - 0
+          effect: Solid
+        target:
+          area_id:
+            - kuche
+            - lounge
+            - serverrack
+    mode: queued
+    max: 30
+
+  # WLED gruen hackcenter
+  - alias: ANSIBLE_WLED_hackcenter_green
+    description: WLED gruen im hackcenter
+    trigger:
+      - type: turned_on
+        platform: device
+        device_id: 33915e12bd114226dcd4718e77a27779
+        entity_id: binary_sensor.button_2
+        domain: binary_sensor
+        for:
+          hours: 0
+          minutes: 0
+          seconds: 1
+    condition: []
+    action:
+      - service: light.turn_on
+        data:
+          rgb_color:
+            - 0
+            - 255
+            - 0
+          effect: Solid
+        target:
+          area_id:
+            - hackcenter
+            - eingang
+    mode: queued
+    max: 30
+
+
+  # WLED blue lounge
+  - alias: ANSIBLE_WLED_lounge_blue
+    description: wLED blau in der lounge
+    trigger:
+      - type: turned_on
+        platform: device
+        device_id: 33915e12bd114226dcd4718e77a27779
+        entity_id: binary_sensor.button_5
+        domain: binary_sensor
+        for:
+          hours: 0
+          minutes: 0
+          seconds: 2
+    condition: []
+    action:
+      - service: light.turn_on
+        data:
+          rgb_color:
+            - 0
+            - 0
+            - 255
+          effect: Solid
+        target:
+          area_id:
+            - kuche
+            - lounge
+            - serverrack
+    mode: queued
+    max: 30
+
+  # WLED blue hackcenter
+  - alias: ANSIBLE_WLED_hackcenter_blue
+    description: wLED blau im hackcenter
+    trigger:
+      - type: turned_on
+        platform: device
+        device_id: 33915e12bd114226dcd4718e77a27779
+        entity_id: binary_sensor.button_2
+        domain: binary_sensor
+        for:
+          hours: 0
+          minutes: 0
+          seconds: 2
+    condition: []
+    action:
+      - service: light.turn_on
+        data:
+          rgb_color:
+            - 0
+            - 0
+            - 255
+          effect: Solid
+        target:
+          area_id:
+            - hackcenter
+            - eingang
+    mode: queued
+    max: 30
+
+
+  # WLED white lounge
+  - alias: ANSIBLE_WLED_lounge_white
+    description: WLED weiss in der lounge
+    trigger:
+      - type: turned_on
+        platform: device
+        device_id: 33915e12bd114226dcd4718e77a27779
+        entity_id: binary_sensor.button_5
+        domain: binary_sensor
+        for:
+          hours: 0
+          minutes: 0
+          seconds: 3
+    condition: []
+    action:
+      - service: light.turn_on
+        data:
+          rgb_color:
+            - 255
+            - 255
+            - 255
+          effect: Solid
+        target:
+          area_id:
+            - kuche
+            - lounge
+            - serverrack
+    mode: queued
+    max: 30
+
+  # WLED white hackcenter
+  - alias: ANSIBLE_WLED_hackcenter_white
+    description: WLED weiss im hackcenter
+    trigger:
+      - type: turned_on
+        platform: device
+        device_id: 33915e12bd114226dcd4718e77a27779
+        entity_id: binary_sensor.button_2
+        domain: binary_sensor
+        for:
+          hours: 0
+          minutes: 0
+          seconds: 3
+    condition: []
+    action:
+      - service: light.turn_on
+        data:
+          rgb_color:
+            - 255
+            - 255
+            - 255
+          effect: Solid
+        target:
+          area_id:
+            - hackcenter
+            - eingang
+    mode: queued
+    max: 30
+
+  # WLED off lounge
+  - alias: ANSIBLE_WLED_lounge_off
+    description: WLED aus in der lounge
+    trigger:
+      - type: turned_on
+        platform: device
+        device_id: 33915e12bd114226dcd4718e77a27779
+        entity_id: binary_sensor.button_6
+        domain: binary_sensor
+        for:
+          hours: 0
+          minutes: 0
+          seconds: 0
+    condition: []
+    action:
+      - service: light.turn_off
+        target:
+          area_id:
+            - kuche
+            - lounge
+            - serverrack
+      - service: rest_command.set_lounge_matrix_off
+        data: {}
+    mode: queued
+    max: 30
+  
+  # WLED off hackcenter
+  - alias: ANSIBLE_WLED_hackcenter_off
+    description: WLED aus im hackcenter
+    trigger:
+      - type: turned_on
+        platform: device
+        device_id: 33915e12bd114226dcd4718e77a27779
+        entity_id: binary_sensor.button_3
+        domain: binary_sensor
+        for:
+          hours: 0
+          minutes: 0
+          seconds: 0
+    condition: []
+    action:
+      - service: light.turn_off
+        target:
+          area_id:
+            - hackcenter
+            - eingang
+    mode: queued
+    max: 30
+  
+  # WLED Zonenstatus
+  - alias: "ANSIBLE_WLED_Zonenstatus"
+    description: "Turn WLED devices on, when opened, off when closed"
+    mode: single
+    trigger:
+      - platform: state
+        entity_id:
+          - input_select.zonenstatus
+    condition: []
+    action:
+      - choose:
+          - conditions:
+              - condition: state
+                entity_id: input_select.zonenstatus
+                state: open
+            sequence:
+              - service: light.turn_on
+                data: {}
+                target:
+                  area_id:
+                    - eingang
+                    - hackcenter
+                    - kuche
+                    - lounge
+          - conditions:
+              - condition: state
+                entity_id: input_select.zonenstatus
+                state: closed
+            sequence:
+              - service: light.turn_off
+                data: {}
+                target:
+                  area_id:
+                    - eingang
+                    - hackcenter
+                    - kuche
+                    - lounge
+
+  # ESPHOME Zonenstatus
+  - alias: "ANSIBLE_ESPHOME_Zonenstatus"
+    description: ""
+    mode: single
+    trigger:
+      - platform: state
+        entity_id:
+          - input_select.zonenstatus
+    condition: []
+    action:
+      - choose:
+          - conditions:
+              - condition: state
+                entity_id: input_select.zonenstatus
+                state: "opened"
+            sequence:
+              - service: light.turn_on
+                data:
+                  effect: Rainbow
+                target:
+                  entity_id:
+                    - light.liba_logo_leds
+                    - light.kuehl_leds
+              - type: turn_on
+                device_id: 7ba91dde6b1413340fdc66f2984dfd00
+                entity_id: light.brightness
+                domain: light
+          - conditions:
+              - condition: state
+                entity_id: input_select.zonenstatus
+                state: "closed"
+            sequence:
+              - type: turn_off
+                device_id: 1dace6e3f89d85152cde6383312792eb
+                entity_id: switch.esphome_plug01_relay
+                domain: switch
+              - type: turn_off
+                device_id: 9f6aded98a4a96ab85c96b829895f449
+                entity_id: switch.esphome_plug02_relay
+                domain: switch
+              - type: turn_off
+                device_id: 502f88ff07aa71cb053ad4112e0dd6bd
+                entity_id: switch.esphome_plug03_relay
+                domain: switch
+              - type: turn_off
+                device_id: b9ea4fd30dabfe365b5098c66eb1f4ba
+                entity_id: switch.esphome_plug04_relay
+                domain: switch
+              - type: turn_off
+                device_id: c5f54add49fda7640497b1883315d48b
+                entity_id: switch.esphome_plug05_relay
+                domain: switch
+              - type: turn_off
+                device_id: a0788c8cf4ee036ce43e0d563fdbdb3a
+                entity_id: switch.esphome_plug06_relay
+                domain: switch
+              - type: turn_off
+                device_id: 1637a583963ba02dc7baa17427f8ac00
+                entity_id: switch.esphome_plug07_relay
+                domain: switch
+              - type: turn_off
+                device_id: 1da3229859c49c822fd8e9c630fa9004
+                entity_id: switch.esphome_plug08_relay
+                domain: switch
+              - service: light.turn_off
+                data: {}
+                target:
+                  entity_id:
+                    - light.liba_logo_leds
+                    - light.kuehl_leds
+              - type: turn_off
+                device_id: 7ba91dde6b1413340fdc66f2984dfd00
+                entity_id: light.brightness
+                domain: light
\ No newline at end of file
diff --git a/intern/docker_homeassistant/templates/docker-compose.yml b/intern/docker_homeassistant/templates/docker-compose.yml
index 1a63ce4e6b3d245765593172fc41d89b03db5f68..b770ce40f3948e8d5fbbcb559aa84dfd3fdf6478 100644
--- a/intern/docker_homeassistant/templates/docker-compose.yml
+++ b/intern/docker_homeassistant/templates/docker-compose.yml
@@ -5,8 +5,10 @@ services:
   
   app:
 
-    image: homeassistant/home-assistant:2023.3
+    image: homeassistant/home-assistant:latest
     restart: always
+    ports:
+      - "{{ int_ip4 }}:{{ homematic_callback_port }}:{{ homematic_callback_port }}"
     volumes:
       - "/etc/localtime:/etc/localtime:ro"
       - "{{ basedir }}/config:/config"
@@ -24,7 +26,7 @@ services:
   
   influxdb:
 
-    image: influxdb:2.6.1
+    image: influxdb:2
     restart: always
     ports:
       - "{{ int_ip4 }}:{{ influxdb_port }}:8086"
diff --git a/intern/docker_mqtt/tasks/main.yml b/intern/docker_mqtt/tasks/main.yml
index 7ea26060f50845b669359e79e98d6a8f97d6585b..910e17290ed6f1d136edf764385354611b6ec7d2 100644
--- a/intern/docker_mqtt/tasks/main.yml
+++ b/intern/docker_mqtt/tasks/main.yml
@@ -1,5 +1,5 @@
 ---
-- include: ../functions/get_secret.yml
+- include_tasks: ../functions/get_secret.yml
   with_items:
    - { path: "{{ basedir }}/influxdb_password", length: 12 }
    - { path: "{{ basedir }}/influxdb_token", length: 24 }
@@ -26,7 +26,7 @@
     - telegraf_float.conf
 
 - name: "start {{ servicename }} docker"
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: "{{ basedir }}"
     state: present
 
diff --git a/intern/docker_mqtt/templates/docker-compose.yml b/intern/docker_mqtt/templates/docker-compose.yml
index 63b6fcd4d655f5d31e4f2a20d781fdbb4d82559a..7edd906f64ce5f6edba34add896001e9660d72bf 100644
--- a/intern/docker_mqtt/templates/docker-compose.yml
+++ b/intern/docker_mqtt/templates/docker-compose.yml
@@ -4,7 +4,7 @@ services:
 
   app:
 
-    image: eclipse-mosquitto:2.0.15
+    image: eclipse-mosquitto:2
     restart: always
     ports:
       - "{{mqtt_port}}:1883" 
@@ -16,7 +16,7 @@ services:
 
   influxdb:
 
-    image: influxdb:2.6.1
+    image: influxdb:2
     restart: always
     ports:
       - {{ int_ip4 }}:{{ influxdb_port }}:8086
@@ -34,7 +34,7 @@ services:
 
   tgbinary:
 
-    image: telegraf:1.25.3
+    image: telegraf:latest
     restart: always
     depends_on: 
       - app
@@ -45,7 +45,7 @@ services:
 
   tgfloat:
 
-    image: telegraf:1.25.3
+    image: telegraf:latest
     restart: always
     depends_on: 
       - app
diff --git a/intern/docker_nodered/tasks/main.yml b/intern/docker_nodered/tasks/main.yml
index c0ec94294fb80f73af038470fad0b8432b3c6271..3a249f0e1df0916278711098fd805cef5fc04c57 100644
--- a/intern/docker_nodered/tasks/main.yml
+++ b/intern/docker_nodered/tasks/main.yml
@@ -18,6 +18,6 @@
     - "docker-compose.yml"
 
 - name: "start {{ servicename }} with docker-compose"
-  community.docker.docker_compose:
+  community.docker.docker_compose_v2:
     state: present
     project_src: "{{ basedir }}"
diff --git a/intern/docker_nodered/templates/docker-compose.yml b/intern/docker_nodered/templates/docker-compose.yml
index 7f1a910983435baf01ad96c197c3aa080608937b..98ed85b48f177163fa374bcdae10f716fc4b9b1b 100644
--- a/intern/docker_nodered/templates/docker-compose.yml
+++ b/intern/docker_nodered/templates/docker-compose.yml
@@ -9,7 +9,7 @@ version: "3"
 services:
 
   app:
-    image: nodered/node-red:2.2.3
+    image: nodered/node-red:latest
     restart: always
     volumes:
       - "{{ basedir }}/data:/data"
diff --git a/intern/docker_omada/tasks/main.yml b/intern/docker_omada/tasks/main.yml
index 413c9109605e23df34696b0f74e33fbcc7be527b..81cd8b99be8296c74167111ded8b1e24a0159d4c 100644
--- a/intern/docker_omada/tasks/main.yml
+++ b/intern/docker_omada/tasks/main.yml
@@ -24,7 +24,7 @@
     - docker-compose.yml 
 
 - name: "start {{ servicename }} docker"
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: "{{ basedir }}"
     state: present
 
diff --git a/intern/docker_omada/templates/docker-compose.yml b/intern/docker_omada/templates/docker-compose.yml
index 6a760cc71aa798bd879c28b552ba8f05e143afe1..4ccdfb95901f6c245977ccdc0423545cebbabdba 100644
--- a/intern/docker_omada/templates/docker-compose.yml
+++ b/intern/docker_omada/templates/docker-compose.yml
@@ -5,7 +5,7 @@ services:
 
   app:
 
-    image: mbentley/omada-controller:5.9
+    image: mbentley/omada-controller:latest
     restart: always
     ports:
       - {{ omada_port_http }}:8088
diff --git a/intern/docker_tasmoadmin/tasks/main.yml b/intern/docker_tasmoadmin/tasks/main.yml
index c0ec94294fb80f73af038470fad0b8432b3c6271..3a249f0e1df0916278711098fd805cef5fc04c57 100644
--- a/intern/docker_tasmoadmin/tasks/main.yml
+++ b/intern/docker_tasmoadmin/tasks/main.yml
@@ -18,6 +18,6 @@
     - "docker-compose.yml"
 
 - name: "start {{ servicename }} with docker-compose"
-  community.docker.docker_compose:
+  community.docker.docker_compose_v2:
     state: present
     project_src: "{{ basedir }}"
diff --git a/keyfiles/hn13.pub b/keyfiles/hn13.pub
new file mode 100644
index 0000000000000000000000000000000000000000..1f964658aa83c9eb668179cd221d8562b5264054
--- /dev/null
+++ b/keyfiles/hn13.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPxuzp0oHqdljtB9rvXY3reFCOI/p/KHVdysIn6fqTc7FtE0/ry1CzlxCZaqYi0pt0kswRNU0qYvDnwBQY1qGnQ= beyer@DESKTOP-KDLNDA0
diff --git a/keyfiles/jabertwo.pub b/keyfiles/jabertwo.pub
index 310a8d66df774852ffffb0f8bf2da3e05e100724..760fc26924b69a0f01a14a12b24a09b9996461d9 100644
--- a/keyfiles/jabertwo.pub
+++ b/keyfiles/jabertwo.pub
@@ -1,2 +1,2 @@
-ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBCxsaY88ZP/bk15JNs2zzVbpG4S4uLYlzfMVlqSZQJVZ0t65vJMKp2yepp6BdOb2rAuXnhPX5zrFEP/A8idR0DFLR5kp6pvdKOeWToND3V763WXJvOutyoKIXPGSuEJF+Q== jabertwo
-ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBGR9N60F+0annoCi9cM+94jSxsw8KPgMf7GqKoFmxwpcDf6fd7Vc5sRQg0avnEg009D2nxihED0y2eTP2Tzn6eQQ/2LRXRfMCa+hRK99YYPUjpszH/y2bC2r/08CvcdeVA== jabertwo
+ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBMU/DG+S/3fGsXsQk6cTOClLH8LXFtL9IL8u6B6Pr1xC4iluZ2xoqQvsYIx5H2sX3nw6WM/VoEVP+xMxEazoOKAwB/31OazpYGG3JGuDvOVlbRVHNoxF9wn3JY9uPyI+Jg== jabertwo-home
+ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBGR9N60F+0annoCi9cM+94jSxsw8KPgMf7GqKoFmxwpcDf6fd7Vc5sRQg0avnEg009D2nxihED0y2eTP2Tzn6eQQ/2LRXRfMCa+hRK99YYPUjpszH/y2bC2r/08CvcdeVA== jabertwo-mob
diff --git a/remote/docker_homeassistant/tasks/main.yml b/remote/docker_homeassistant/tasks/main.yml
index 9717f264b53d3c663afddfb7ff2e0da804d8761b..df24774fced1cd2f9455a43b19a1c74c287eb220 100644
--- a/remote/docker_homeassistant/tasks/main.yml
+++ b/remote/docker_homeassistant/tasks/main.yml
@@ -1,6 +1,6 @@
 ---
 
-- include: ../functions/get_secret.yml
+- include_tasks: ../functions/get_secret.yml
   with_items:
    - { path: "{{ basedir }}/homeassistant_admin_password", length: 12 }
    - { path: "{{ basedir }}/influxdb_password",            length: 12 }
@@ -26,13 +26,13 @@
 
 
 - name: "stop {{ servicename }} docker"
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: "{{ basedir }}"
     state: absent
   when: config_files.changed 
 
 
 - name: "start {{ servicename }} docker"
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: "{{ basedir }}"
     state: present
diff --git a/remote/docker_homeassistant/templates/docker-compose.yml b/remote/docker_homeassistant/templates/docker-compose.yml
index fb1e1051106766ff55b2d0c07f5824f5e612fb6e..dd4c1e3fa89c66f57b6a3638448bd34ba28bba49 100644
--- a/remote/docker_homeassistant/templates/docker-compose.yml
+++ b/remote/docker_homeassistant/templates/docker-compose.yml
@@ -5,7 +5,7 @@ services:
   
   app:
 
-    image: homeassistant/home-assistant:2023.3.3
+    image: homeassistant/home-assistant:latest
     restart: always
     volumes:
       - "/etc/localtime:/etc/localtime:ro"
@@ -24,7 +24,7 @@ services:
   
   influxdb:
 
-    image: influxdb:2.6.0
+    image: influxdb:2
     restart: always
     ports:
       - "{{ int_ip4 }}:{{ influxdb_port }}:8086"
diff --git a/remote/docker_netdata/tasks/main.yml b/remote/docker_netdata/tasks/main.yml
index 21a41e1fad3b5dc8d4f619e88fae855cee94f793..7016306ab303ee4b3b0e8c21ab51847e4b012061 100644
--- a/remote/docker_netdata/tasks/main.yml
+++ b/remote/docker_netdata/tasks/main.yml
@@ -18,7 +18,7 @@
     - docker-compose.yml 
 
 - name: "start {{ servicename }} docker"
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: "{{ basedir }}"
     state: present
 
diff --git a/remote/docker_netdata/templates/docker-compose.yml b/remote/docker_netdata/templates/docker-compose.yml
index bc1f81a504345877beb9a7100d42f446b14a3bbd..e22fc1391b485430631a8822ab4e1f98a31f64fc 100644
--- a/remote/docker_netdata/templates/docker-compose.yml
+++ b/remote/docker_netdata/templates/docker-compose.yml
@@ -3,7 +3,7 @@ version: '3'
 services:
   
   app:
-    image: netdata/netdata:v1.38.1
+    image: netdata/netdata:latest
     restart: always
     cap_add:
       - SYS_PTRACE
diff --git a/remote/docker_prometheus/tasks/main.yml b/remote/docker_prometheus/tasks/main.yml
index 85279791f8900f1f2bac0e948414b7b29ef0e1b8..ffe884ff6d998dea1dc28d487ed4ca064769e048 100644
--- a/remote/docker_prometheus/tasks/main.yml
+++ b/remote/docker_prometheus/tasks/main.yml
@@ -17,7 +17,7 @@
     - prometheus.yml 
 
 - name: "start {{ servicename }} docker"
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: "{{ basedir }}"
     state: present
 
diff --git a/remote/docker_prometheus/templates/docker-compose.yml b/remote/docker_prometheus/templates/docker-compose.yml
index 1c8c842bf58bdb27724020400eae17c11cd98b0c..06d5d333c5a06d82aa53dc4527db1075e409cb89 100644
--- a/remote/docker_prometheus/templates/docker-compose.yml
+++ b/remote/docker_prometheus/templates/docker-compose.yml
@@ -5,7 +5,7 @@ services:
 
   app:
 
-    image: prom/prometheus:v2.42.0
+    image: prom/prometheus:latest
     restart: always
     ports:
       - 9090:9090
@@ -27,7 +27,7 @@ services:
       - web
 
   snmp:
-    image: quay.io/prometheus/snmp-exporter:v0.21.0
+    image: quay.io/prometheus/snmp-exporter:latest
     restart: always
 
 
diff --git a/remote/docker_unifi/tasks/main.yml b/remote/docker_unifi/tasks/main.yml
index 1f9e11ca793ad268b631259947db9966ee96ca26..c6b3681d36b64630b9c11e706c7e4da551f4759f 100644
--- a/remote/docker_unifi/tasks/main.yml
+++ b/remote/docker_unifi/tasks/main.yml
@@ -19,7 +19,7 @@
     - docker-compose.yml 
 
 - name: "start {{ basedir }} docker"
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: "{{ basedir }}"
     state: present
 
diff --git a/remote/docker_unifi/templates/docker-compose.yml b/remote/docker_unifi/templates/docker-compose.yml
index c7459c226c1054b9bffd2ddcc74e0a01eab8fad5..b20c7e1af2d310af65a5acbdd0ff7aad10f3d6b3 100644
--- a/remote/docker_unifi/templates/docker-compose.yml
+++ b/remote/docker_unifi/templates/docker-compose.yml
@@ -5,7 +5,7 @@ services:
 
   app:
 
-    image: linuxserver/unifi-controller:7.3.83
+    image: linuxserver/unifi-controller:latest
     restart: always
     ports:
       - 8443:8443
diff --git a/renovate.json b/renovate.json
new file mode 100644
index 0000000000000000000000000000000000000000..15822c89c67d5ddcf7ebc3349382588555b781d2
--- /dev/null
+++ b/renovate.json
@@ -0,0 +1,9 @@
+{
+  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
+  "extends": [
+    "config:base"
+  ],
+  "prConcurrentLimit": 0,
+  "prHourlyLimit": 0,
+  "additionalBranchPrefix": "{{parentDir}}-"
+}
diff --git a/site.yml b/site.yml
index f3b4b3deca045688a220a62f3f86a7f3b0cfadbb..a2c96de1f9eb3e9ae58fab8bff0832337d26450e 100644
--- a/site.yml
+++ b/site.yml
@@ -10,6 +10,51 @@
     - { role: all/common, tags: common }
     - { role: all/sysctl, tags: sysctl }
 
+##################################################
+# Test Server
+##################################################
+
+- hosts: test-warpzone-de
+  remote_user: root
+  roles:
+    - { role: common/cronapt, tags: cronapt }
+    - { role: common/docker, tags: docker }
+    - { 
+        role: testserver/docker_traefik, tags: traefik,
+        servicename: traefik,
+        basedir: /srv/traefik,
+        domain: "test-warpzone.de",
+        domain_default: "www.test-warpzone.de",
+      }    
+    - { 
+        role: testserver/docker_mail, tags: test_mail, 
+        servicename: mail,
+        basedir: "/srv/{{ servicename }}",
+        domain: "test-warpzone.de",
+        mailserver: "mailserver.test-warpzone.de",
+        listserver: "listserver.test-warpzone.de"
+      }
+    - { 
+        role: testserver/docker_uffd, tags: test_uffd, 
+        servicename: uffd, 
+        basedir: "/srv/{{ servicename }}",
+        domain: "uffd.test-warpzone.de",
+      }
+    - { 
+        role: testserver/docker_icinga, tags: test_icinga,
+        servicename: icinga,
+        basedir: "/srv/{{ servicename }}",
+        domain: "icinga.test-warpzone.de",
+        api_port: 5665,
+        mysql_port: 33306
+      }
+    - { 
+        role: verwaltung/docker_gitea, tags: gitea,
+        servicename: "gitea",
+        domain: "verwaltung-git.test-warpzone.ms"
+      }
+
+
 
 ##################################################
 # Produktive Server
@@ -26,6 +71,7 @@
   remote_user: root
   roles:
     - { role: common/proxmox, tags: proxmox }
+    - { role: common/prometheus-node, tags: prometheus-node }
     - { role: common/cronapt, tags: cronapt }
 
 
@@ -33,6 +79,7 @@
   remote_user: root
   roles:
     - { role: common/cronapt, tags: cronapt }
+    - { role: common/prometheus-node, tags: prometheus-node }
     - { role: common/wireguard, tags: wireguard }
 
 
@@ -87,7 +134,8 @@
         servicename: homeassistant, 
         basedir: /srv/homeassistant,
         domain: "ha.warpzone.lan",
-        influxdb_port: 38086
+        homematic_callback_port: 8060,
+        influxdb_port: 38086       
       }
     - { 
         role: intern/docker_mqtt, tags: mqtt, 
@@ -113,19 +161,18 @@
         omada_port_https: 8043,
         omada_portal_https: 8843
       }
-    - {
-        role: intern/docker_graylog, tags: graylog,
-        servicename: graylog,
-        basedir: /srv/graylog,
-        domain: "graylog.warpzone.lan"
-      }
     - { 
         role: intern/docker_tasmoadmin, tags: tasmoadmin, 
         servicename: tasmoadmin,
         basedir: /srv/tasmoadmin,
         domain: "tasmoadmin.warpzone.lan"
       }
-
+    - {
+        role: intern/docker_fridgeserver, tags: fridgeserver,
+        servicename: fridgeserver,
+        basedir: /srv/fridgeserver,
+        domain: "fridgeserver.warpzone.lan"
+      }
 
 - hosts: webserver
   remote_user: root
@@ -136,6 +183,7 @@
     - { role: common/kvm-guest, tags: kvm-guest }
     - { role: common/openvpn, tags: openvpn }
     - { role: common/prometheus-node, tags: prometheus-node }
+    - { role: common/wireguard, tags: wireguard }
     - { 
         role: common/docker_dockerstats, tags: dockerstats, 
         servicename: dockerstats, 
@@ -143,7 +191,8 @@
       }
     - {
         role: common/docker_ldap, tags: ldap,
-        servicename: "ldap",
+        servicename: ldap,
+        basedir: /srv/ldap,
         domain: "ldap.warpzone.ms"
       }
     - { 
@@ -155,10 +204,10 @@
         matrix_federation: true
       }   
     - { 
-        role: webserver/docker_autodiscover, tags: autodiscover,
-        servicename: autodiscover, 
-        basedir: /srv/autodiscover
-      }
+        role: common/docker_watchtower, tags: watchtower,
+        servicename: watchtower,
+        basedir: /srv/watchtower,
+      }   
     - { 
         role: webserver/docker_coturn, tags: coturn,
         servicename: "coturn",
@@ -167,7 +216,9 @@
     - { 
         role: webserver/docker_dokuwiki, tags: dokuwiki,
         servicename: "dokuwiki",
-        domain: "wiki.warpzone.ms"
+        domain: "wiki.warpzone.ms",
+        basedir: /srv/dokuwiki,
+        healthchecks_url: "https://hc-ping.com/038adcfe-05bf-45b4-919b-88b69aab8844"
       }
     - { 
         role: webserver/docker_gitlab, tags: gitlab,
@@ -181,7 +232,7 @@
         basedir: /srv/icinga, 
         domain: icinga.warpzone.ms,
         api_port: 5665,
-        mysql_port: 33306, 
+        mysql_port: 33306
       }
     - { 
         role: webserver/docker_hackmd, tags: hackmd,
@@ -197,10 +248,15 @@
       }
     - { 
         role: webserver/docker_mail, tags: mail, 
+        servicename: mail,
         basedir: /srv/mail, 
+        domain: "warpzone.ms",
+        mailserver: "mailserver.warpzone.ms",
+        listserver: "listserver.warpzone.ms"      
       }
     - { 
         role: webserver/docker_matterbridge, tags: matterbridge,
+        servicename: matterbridge,
         basedir: /srv/matterbridge, 
         domain: "www.warpzone.ms" 
       }
@@ -228,12 +284,12 @@
         basedir: /srv/wordpress, 
         domain: "www.warpzone.ms"
       }
-    - { 
-        role: webserver/docker_workadventure, tags: workadventure,
-        servicename: "workadventure",
-        basedir: /srv/workadventure, 
-        domain: "workadventure.warpzone.ms"
-      }
+    # - { 
+    #     role: webserver/docker_workadventure, tags: workadventure,
+    #     servicename: "workadventure",
+    #     basedir: /srv/workadventure, 
+    #     domain: "workadventure.warpzone.ms"
+    #   }
 
 
 - hosts: verwaltung
@@ -255,8 +311,12 @@
         servicename: traefik,
         basedir: /srv/traefik,
         domain: "warpzone.ms",
-        domain_default: "www.warpzone.ms" 
       }      
+    - { 
+        role: common/docker_watchtower, tags: watchtower,
+        servicename: watchtower,
+        basedir: /srv/watchtower,
+      }   
     - { 
         role: verwaltung/docker_gitea, tags: gitea,
         servicename: "gitea",
@@ -272,9 +332,15 @@
       }
     - { 
         role: verwaltung/docker_nextcloud, tags: nextcloud,
-        servicename: "nextcloud",
+        servicename: "nextcloud",        
         domain: "verwaltung.warpzone.ms" 
       }
+    - { 
+        role: verwaltung/docker_vaultwarden, tags: vaultwarden,
+        servicename: "vaultwarden",
+        basedir: /srv/vaultwarden,
+        domain: "vault.warpzone.ms" 
+      }
     - { 
         role: verwaltung/docker_mysql, tags: mysql 
       }
diff --git a/testserver/docker_dockerstats/tasks/main.yml b/testserver/docker_dockerstats/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..673605687d98f958504626d9aa673af1a70d1e21
--- /dev/null
+++ b/testserver/docker_dockerstats/tasks/main.yml
@@ -0,0 +1,27 @@
+---
+- name: "create folder struct for {{ servicename }}"
+  file: 
+    path: "{{ item }}"
+    state: "directory"
+  with_items:
+    - "{{ basedir }}"
+
+
+- name: Konfig-Dateien erstellen
+  template:
+    src: "{{ item }}"
+    dest: "{{ basedir }}/{{ item }}"
+  with_items:
+    - Dockerfile
+    - docker-compose.yml
+  register: config
+
+- name: "stop {{ servicename }} docker"
+  community.docker.docker_compose_v2:
+    project_src: "{{ basedir }}"
+    state: absent
+
+- name: "start {{ servicename }} docker"
+  community.docker.docker_compose_v2:
+    project_src: "{{ basedir }}"
+    state: present
diff --git a/testserver/docker_dockerstats/templates/Dockerfile b/testserver/docker_dockerstats/templates/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..793b7781f16e3c35b0213babc1185e883d014aba
--- /dev/null
+++ b/testserver/docker_dockerstats/templates/Dockerfile
@@ -0,0 +1,19 @@
+FROM node:21-alpine
+
+RUN apk update \
+ && apk upgrade \
+ && apk add --no-cache git
+
+RUN mkdir -p /usr/src/app \
+  && cd /usr/src/app \
+  && git clone https://github.com/elberfeld/docker_stats_exporter.git \
+  && cd /usr/src/app/docker_stats_exporter \
+  && git checkout 2020.07.30.1 \
+  && npm install
+
+WORKDIR /usr/src/app/docker_stats_exporter
+
+EXPOSE 9487
+ENV DOCKERSTATS_PORT=9487 DOCKERSTATS_INTERVAL=15 DEBUG=0
+
+ENTRYPOINT [ "npm", "start" ]
diff --git a/testserver/docker_dockerstats/templates/docker-compose.yml b/testserver/docker_dockerstats/templates/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b7b871e44001f773b0bdad625fc025b9588b2ff5
--- /dev/null
+++ b/testserver/docker_dockerstats/templates/docker-compose.yml
@@ -0,0 +1,16 @@
+version: "3"
+
+services:
+
+  app:
+
+    build: .
+    restart: always
+    ports:
+      - "{{ int_ip4 }}:9487:9487" 
+    volumes:
+      - /var/run/docker.sock:/var/run/docker.sock
+      - /usr/bin/docker:/usr/bin/docker
+    labels:
+      - com.centurylinklabs.watchtower.enable=false
+
diff --git a/testserver/docker_gitea/tasks/main.yml b/testserver/docker_gitea/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..780d091904ca60070506a546a3723c85bfe174f4
--- /dev/null
+++ b/testserver/docker_gitea/tasks/main.yml
@@ -0,0 +1,29 @@
+---
+# Get secrets 
+- include_tasks: ../functions/get_secret.yml
+  with_items:
+    - { path: /srv/gitea/mysql_root_pw, length: 24 }
+    - { path: /srv/gitea/mysql_user_pw, length: 12 }
+
+- name: create folder struct for gitea
+  file: 
+    path: "{{item}}" 
+    state: "directory"
+    owner: 1000
+    group: 1000
+  with_items:
+    - "/srv/gitea/db/"
+    - "/srv/gitea/data/"
+
+- name: Konfig-Dateien erstellen
+  template: 
+    src: "{{item}}" 
+    dest: "/srv/gitea/{{item}}"
+  with_items:
+    - "docker-compose.yml"
+
+- name: start gitea docker
+  community.docker.docker_compose_v2:
+    project_src: /srv/gitea/
+    state: present
+  
diff --git a/testserver/docker_gitea/templates/docker-compose.yml b/testserver/docker_gitea/templates/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6330d9e70fa6303886c33be1b2119529667e0b05
--- /dev/null
+++ b/testserver/docker_gitea/templates/docker-compose.yml
@@ -0,0 +1,65 @@
+
+version: "2.4"
+
+services:
+
+  app:
+    image: gitea/gitea:1.21.4
+    restart: always
+    depends_on:
+      - db
+    ports:
+      - 444:444
+    volumes:
+      - /srv/gitea/data:/data
+    environment:
+      APP_NAME: "Warpzone Verwaltung"
+      RUN_MODE: "prod"
+      SSH_DOMAIN: "verwaltung-git.warpzone.ms"
+      SSH_PORT: "444"
+      ROOT_URL: "https://verwaltung-git.warpzone.ms"
+      HTTP_PORT: "42001"
+      USER_UID: "1000"
+      USER_GID: "1000"
+      DB_TYPE: "mysql"
+      DB_HOST: "db:3306"
+      DB_NAME: "gitea"
+      DB_USER: "gitea"
+      DB_PASSWD: "{{ mysql_user_pw }}"
+    labels:
+      - traefik.enable=true
+      - traefik.http.routers.{{ servicename }}.rule=Host(`{{ domain }}`)
+      - traefik.http.routers.{{ servicename }}.entrypoints=websecure
+      - traefik.http.services.{{ servicename }}.loadbalancer.server.port=42001
+    networks:
+      - default
+      - web
+
+
+  db:
+    image: mariadb:11.2.2
+    restart: always
+    volumes:
+      - /srv/gitea/db/:/var/lib/mysql
+    environment:
+      MYSQL_ROOT_PASSWORD: "{{ mysql_root_pw }}"
+      MYSQL_PASSWORD: "{{ mysql_user_pw }}"
+      MYSQL_DATABASE: "gitea"
+      MYSQL_USER: "gitea"
+      MARIADB_AUTO_UPGRADE: "1"
+      MARIADB_INITDB_SKIP_TZINFO: "1"
+    networks:
+      - default
+
+
+networks:
+  web:
+    external: true    
+  default:
+    driver: bridge
+    enable_ipv6: true
+    ipam:
+      driver: default
+      config:
+        # must be a ULA range
+        - subnet: fd00:dead:beef:444::/64
diff --git a/testserver/docker_icinga/handlers/main.yml b/testserver/docker_icinga/handlers/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..d93deaf5c93d0f00632ecf25796a2d15a3d39f1d
--- /dev/null
+++ b/testserver/docker_icinga/handlers/main.yml
@@ -0,0 +1,6 @@
+---
+
+- name: restart icinga docker
+  community.docker.docker_compose_v2:
+    project_src: /srv/icinga/
+    state: restarted
diff --git a/testserver/docker_icinga/tasks/main.yml b/testserver/docker_icinga/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..de4d9c837eeee37b65975cdd6ce2a7bc24d7b8c7
--- /dev/null
+++ b/testserver/docker_icinga/tasks/main.yml
@@ -0,0 +1,133 @@
+---
+
+- include_tasks: ../functions/get_secret.yml
+  with_items:
+    - { path: "{{ basedir }}/secrets/forward_auth_secret", length: 64 }
+    - { path: "{{ basedir }}/secrets/oauth_client_secret", length: 64 }
+    - { path: "{{ basedir }}/secrets/icinga_admin_pass",   length: 12 }
+    - { path: "{{ basedir }}/secrets/icinga_api_user",     length: 8 }
+    - { path: "{{ basedir }}/secrets/icinga_api_pass",     length: 8 }
+    - { path: "{{ basedir }}/secrets/mysql_admin_pass",    length: 12 }
+    - { path: "{{ basedir }}/secrets/mysql_user_pass",     length: 12 }
+    - { path: "{{ basedir }}/secrets/matrix_notification_access_token",  length: -1 }
+
+
+- name: Setup OAuth Client Info 
+  ansible.builtin.debug:
+    msg: "Client ID: {{ servicename }} // Client Secret: {{ oauth_client_secret }} // Redirect-URI: https://{{ domain }}/_oauth" 
+
+
+- name: pakete installieren
+  apt:
+    update_cache: no
+    state: present
+    name: 
+      - logrotate
+
+
+- name: icinga LogRotate config erstellen 
+  template: 
+    src: logrotate 
+    dest: /etc/logrotate.d/icinga
+
+
+- name: "create folder struct for {{ servicename }}"
+  file: 
+    path: "{{ item }}"
+    state: "directory"
+  with_items:
+    - "{{ basedir }}"
+    - "{{ basedir }}/secrets/"
+    - "{{ basedir }}/data/"
+    - "{{ basedir }}/etc/"
+    - "{{ basedir }}/log/"
+    - "{{ basedir }}/db/"
+    - "{{ basedir }}/graphite-conf/"
+    - "{{ basedir }}/graphite-storage/"
+
+
+- name: Konfig-Dateien erstellen (base)
+  template:
+    src: "{{ item }}"
+    dest: "{{ basedir }}/{{ item }}"
+  with_items:
+    - Dockerfile
+    - docker-compose.yml
+    - check_rbl_helper.sh
+    - notify_by_pushover.sh
+    - etc/locale.gen
+    - etc/oauth_header.conf
+  notify: restart icinga docker
+  register: dockerconfig
+
+- stat:
+    path: "{{ basedir }}/etc/icingaweb2/CONFIGURED"
+  register: configured
+
+- name: "start {{ servicename }} docker (init)"
+  community.docker.docker_compose_v2:
+    project_src: "{{ basedir }}"
+    state: present
+  when: configured.stat.exists == False
+
+- name: "wait for {{ servicename }} docker (init)"
+  wait_for:
+    path: "{{ basedir }}/etc/icingaweb2/CONFIGURED"
+  when: configured.stat.exists == False
+  
+- name: "stop {{ servicename }} docker (init)"
+  community.docker.docker_compose_v2:
+    project_src: "{{ basedir }}"
+    state: absent
+  when: configured.stat.exists == False
+
+- name: Script Helper erstellen
+  template: 
+    src: "{{ item }}" 
+    dest: "{{ basedir }}/{{ item }}"
+    mode: u+x
+  with_items:
+    - debuglog_enable.sh
+    - debuglog_disable.sh
+
+- name: Default users.conf löschen
+  ansible.builtin.file:
+    path: "{{ basedir }}/etc/icinga/conf.d/users.conf"
+    state: absent
+
+
+- name: Konfig-Dateien erstellen (icinga,icingaweb2,graphite)
+  template:
+    src: "{{ item }}"
+    dest: "{{ basedir }}/{{ item }}"
+  with_items:
+    - etc/icinga/conf.d/api-users.conf
+    - etc/icinga/conf.d/commands2.conf
+    - etc/icinga/conf.d/groups.conf
+    - etc/icinga/conf.d/hosts.conf
+#    - etc/icinga/conf.d/notifications_pushover.conf
+    - etc/icinga/conf.d/notifications.conf
+    - etc/icinga/conf.d/services_backup.conf
+    - etc/icinga/conf.d/services_container.conf
+    - etc/icinga/conf.d/services_domains.conf
+    - etc/icinga/conf.d/services_exporters.conf
+    - etc/icinga/conf.d/services_mail.conf
+    - etc/icinga/conf.d/services_manual.conf
+#    - etc/icinga/conf.d/services_mqttsensors.conf
+    - etc/icinga/conf.d/services_system.conf
+    - etc/icinga/conf.d/services.conf
+    - etc/icinga/conf.d/templates.conf
+    - etc/icinga/conf.d/users_groups.conf
+    - etc/icinga/conf.d/users_sample.conf
+    - etc/icingaweb2/authentication.ini
+    - etc/icingaweb2/groups.ini
+    - etc/icingaweb2/resources.ini
+    - etc/icingaweb2/roles.ini
+    - graphite-conf/storage-schemas.conf
+  notify: restart icinga docker
+
+  
+- name: "start {{ servicename }} docker"
+  community.docker.docker_compose_v2:
+    project_src: "{{ basedir }}"
+    state: present
\ No newline at end of file
diff --git a/testserver/docker_icinga/templates/Dockerfile b/testserver/docker_icinga/templates/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..c76b06c1c00db530d81659b8d88698d83c40022c
--- /dev/null
+++ b/testserver/docker_icinga/templates/Dockerfile
@@ -0,0 +1,50 @@
+FROM jordan/icinga2:2.14.0
+
+# Install additional Packages 
+RUN apt-get update \
+ && apt-get install -y -q --no-install-recommends \
+    curl \ 
+    dnsutils \
+    git \
+    jq \
+    libdata-validate-domain-perl \
+    libdata-validate-ip-perl \
+    libmonitoring-plugin-perl \
+    libnet-dns-perl \
+    libnet-ip-perl \
+    perl \
+    python3-requests \
+    python3 \
+    python3-paho-mqtt \
+ && apt-get autoremove -y \
+ && apt-get clean \
+ && rm -rf /tmp/* /var/lib/apt/lists/* /var/cache/debconf/*-old
+
+# Helper Scripe  
+COPY check_rbl_helper.sh /opt 
+COPY notify_by_pushover.sh /opt 
+RUN chmod +x /opt/*.sh
+
+# check_mqtt
+RUN cd /opt/ \
+ && git clone https://github.com/jpmens/check-mqtt.git \
+ && cd /opt/check-mqtt/ \
+ && git checkout v3.0
+
+# check_rbl
+RUN cd /opt/ \
+ && git clone https://github.com/matteocorti/check_rbl.git \
+ && cd /opt/check_rbl/ \
+ && git checkout v1.5.7
+
+# prom2json -- needed for check_metric_value
+RUN cd /opt/ \
+ && wget https://github.com/prometheus/prom2json/releases/download/v1.3.0/prom2json-1.3.0.linux-amd64.tar.gz \
+ && tar --strip-components=1 -xzvf prom2json-1.3.0.linux-amd64.tar.gz \
+ && chmod ugo+x /opt/prom2json
+ 
+# check_metric_value - commit from 16.12.2020
+RUN cd /opt/ \
+ && git clone https://github.com/elberfeld/check_metric_value.git \
+ && cd /opt/check_metric_value/ \
+ && git checkout b94d3c3e78497a05e3b4520d33421f37e4d77985
\ No newline at end of file
diff --git a/testserver/docker_icinga/templates/check_rbl_helper.sh b/testserver/docker_icinga/templates/check_rbl_helper.sh
new file mode 100644
index 0000000000000000000000000000000000000000..09cd70fcd7de53e54fd9a7ec8d2cc420f22ef905
--- /dev/null
+++ b/testserver/docker_icinga/templates/check_rbl_helper.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+/usr/bin/perl /opt/check_rbl/check_rbl --extra-opts=rbl@/opt/check_rbl/check_rbl.ini $@
diff --git a/testserver/docker_icinga/templates/debuglog_disable.sh b/testserver/docker_icinga/templates/debuglog_disable.sh
new file mode 100644
index 0000000000000000000000000000000000000000..ce6d4ed18ef9452cd0b04edf7a85607cded9613a
--- /dev/null
+++ b/testserver/docker_icinga/templates/debuglog_disable.sh
@@ -0,0 +1,6 @@
+#!/bin/sh 
+
+cd /srv/icinga 
+docker-compose exec app icinga2 feature disable debuglog
+docker-compose restart 
+rm log/icinga2/debug.log
diff --git a/testserver/docker_icinga/templates/debuglog_enable.sh b/testserver/docker_icinga/templates/debuglog_enable.sh
new file mode 100644
index 0000000000000000000000000000000000000000..187440dc5d1d868aad9ac107ee37173e766de84b
--- /dev/null
+++ b/testserver/docker_icinga/templates/debuglog_enable.sh
@@ -0,0 +1,6 @@
+#!/bin/sh 
+
+cd /srv/icinga 
+docker-compose exec app icinga2 feature enable debuglog
+docker-compose restart 
+tail -f log/icinga2/debug.log
diff --git a/testserver/docker_icinga/templates/docker-compose.yml b/testserver/docker_icinga/templates/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..998f5859842d6ca1159e328179dc0024b363edc9
--- /dev/null
+++ b/testserver/docker_icinga/templates/docker-compose.yml
@@ -0,0 +1,122 @@
+
+version: "2.4"
+
+services:
+  
+  app:
+
+    build: .
+    restart: always
+    ports:
+      - "{{ api_port }}:5665"
+    volumes:
+      - "{{ basedir }}/data:/var/lib/icinga2"
+      - "{{ basedir }}/etc/locale.gen:/etc/locale.gen"
+      - "{{ basedir }}/etc/oauth_header.conf:/etc/apache2/conf-enabled/oauth_header.conf"
+      - "{{ basedir }}/etc/icinga:/etc/icinga2"
+      - "{{ basedir }}/etc/icingaweb2:/etc/icingaweb2"
+      - "{{ basedir }}/log/apache2:/var/log/apache2"
+      - "{{ basedir }}/log/icinga2:/var/log/icinga2"
+      - "{{ basedir }}/log/icingaweb2:/var/log/icingaweb2"
+    depends_on:
+      - db
+      - graphite
+    environment:
+      APACHE2_HTTP: BOTH
+      MYSQL_ROOT_PASSWORD: "{{ mysql_admin_pass }}"
+      MYSQL_PASSWORD: "{{ mysql_user_pass }}"
+      MYSQL_DATABASE: icinga
+      MYSQL_USER: icinga
+      DEFAULT_MYSQL_HOST: db
+      DEFAULT_MYSQL_USER: icinga
+      DEFAULT_MYSQL_PASS: "{{ mysql_user_pass }}"
+      ICINGAWEB2_ADMIN_PASS: "{{ icinga_admin_pass }}"
+      ICINGA2_FEATURE_GRAPHITE: 1
+      ICINGA2_FEATURE_GRAPHITE_HOST: graphite
+      ICINGA2_FEATURE_GRAPHITE_PORT: 2003
+      ICINGA2_FEATURE_DIRECTOR: 0
+    labels:
+      - com.centurylinklabs.watchtower.enable=false
+      - traefik.enable=true
+      - traefik.http.routers.{{ servicename }}.middlewares={{ servicename }}-auth
+      - traefik.http.routers.{{ servicename }}.rule=Host(`{{ domain }}`)
+      - traefik.http.routers.{{ servicename }}.entrypoints=websecure
+      - traefik.http.services.{{ servicename }}.loadbalancer.server.port=80      
+    networks:
+      - default
+      - web
+
+
+  # TODO: Evaluate alternatives, possibly: mesosphere/traefik-forward-auth
+  auth:
+    image: thomseddon/traefik-forward-auth:2.2
+    restart: always
+    environment: 
+      LOG_LEVEL: info
+      DEFAULT_ACTION: auth
+      DEFAULT_PROVIDER: generic-oauth
+      SECRET: {{ forward_auth_secret }}
+      PROVIDERS_GENERIC_OAUTH_AUTH_URL: {{ oauth_global.authorize_url }}
+      PROVIDERS_GENERIC_OAUTH_TOKEN_URL: {{ oauth_global.token_url }}
+      PROVIDERS_GENERIC_OAUTH_USER_URL: {{ oauth_global.userinfo_url }}
+      PROVIDERS_GENERIC_OAUTH_CLIENT_ID: {{ servicename }}
+      PROVIDERS_GENERIC_OAUTH_CLIENT_SECRET: {{ oauth_client_secret }}
+      PROVIDERS_GENERIC_OAUTH_SCOPE: profile
+      PROVIDERS_GENERIC_OAUTH_TOKEN_STYLE: header
+    labels:
+      - com.centurylinklabs.watchtower.enable=false
+      - traefik.enable=true
+      - traefik.http.middlewares.{{ servicename }}-auth.forwardauth.address=http://auth:4181
+      - traefik.http.middlewares.{{ servicename }}-auth.forwardauth.authResponseHeaders=X-Forwarded-User
+      - traefik.http.services.{{ servicename }}-auth.loadbalancer.server.port=4181
+    networks:
+      - default
+      - web
+
+
+  db:
+
+    image: mariadb:10.7.1
+    restart: always
+    ports:
+      - "{{ int_ip4 }}:{{mysql_port}}:3306"
+    volumes:
+      - "{{ basedir }}/db:/var/lib/mysql"
+    environment:
+      MYSQL_ROOT_PASSWORD: "{{ mysql_admin_pass }}"
+      MYSQL_PASSWORD: "{{ mysql_user_pass }}"
+      MYSQL_DATABASE: icinga
+      MYSQL_USER: icinga
+    networks:
+      - default
+
+
+  graphite:
+    
+    image: graphiteapp/graphite-statsd:1.1.8-7
+    restart: always
+    volumes:
+      - "{{ basedir }}/graphite-conf:/opt/graphite/conf"
+      - "{{ basedir }}/graphite-storage:/opt/graphite/storage"
+    environment:
+      GRAPHITE_TIME_ZONE: "Europe/Berlin"
+      GRAPHITE_DATE_FORMAT: "%d.%m.%y"
+      GRAPHITE_LOG_FILE_INFO: "-"
+      GRAPHITE_LOG_FILE_EXCEPTION: "-"
+      GRAPHITE_LOG_FILE_CACHE: "-"
+      GRAPHITE_LOG_FILE_RENDERING: "-"
+    networks:
+      - default
+
+
+networks:
+  web:
+    external: true    
+  default:
+    driver: bridge
+    enable_ipv6: true
+    ipam:
+      driver: default
+      config:
+        # must be a ULA range
+        - subnet: fd00:dead:beef:{{ api_port }}::/64
\ No newline at end of file
diff --git a/testserver/docker_icinga/templates/etc/icinga/conf.d/api-users.conf b/testserver/docker_icinga/templates/etc/icinga/conf.d/api-users.conf
new file mode 100644
index 0000000000000000000000000000000000000000..7a9e0f23ed7e348c957e4832d4725af47833947d
--- /dev/null
+++ b/testserver/docker_icinga/templates/etc/icinga/conf.d/api-users.conf
@@ -0,0 +1,7 @@
+/**
+ * The ApiUser objects are used for authentication against the API.
+ */
+object ApiUser "{{icinga_api_user}}" {
+  password = "{{icinga_api_pass}}"
+  permissions = [ "*" ]
+}
diff --git a/testserver/docker_icinga/templates/etc/icinga/conf.d/commands2.conf b/testserver/docker_icinga/templates/etc/icinga/conf.d/commands2.conf
new file mode 100644
index 0000000000000000000000000000000000000000..d1c3cbe066aa2f11280dd98939fe3c0362217a08
--- /dev/null
+++ b/testserver/docker_icinga/templates/etc/icinga/conf.d/commands2.conf
@@ -0,0 +1,128 @@
+
+/**
+ * Check MQTT values
+ */
+
+object CheckCommand "check_mqtt" {
+  import "plugin-check-command"
+
+  command = [ "/opt/check-mqtt/check-mqtt.py" ] 
+
+  arguments = {
+    "-H" = "$mqtt_host$"
+    "-u" = "$mqtt_user$"
+    "-p" = "$mqtt_password$"
+    "-P" = "$mqtt_port$"
+    "-a" = "$mqtt_cafile$"
+    "-C" = "$mqtt_certfile$"
+    "-k" = "$mqtt_keyfile$"
+    "-t" = "$mqtt_topic$"
+    "-m" = {
+      set_if = "$mqtt_max$"
+      value = "$mqtt_max$"
+    }
+
+    "-l" = "$mqtt_payload$"
+    "-v" = "$mqtt_value$"
+    "-o" = "$mqtt_operator$"
+
+    "-r" = {
+      set_if = "$mqtt_readonly$"
+      description = "Don't write."
+    }
+    "-n" = {
+      set_if = "$mqtt_insecure$"
+      description = "suppress TLS hostname check"
+    }
+  }
+}
+
+/**
+ * Check for Mail Blacklisting
+ */
+
+object CheckCommand "check_mail_blacklist" {
+  import "plugin-check-command"
+
+  command = [ "/opt/check_rbl_helper.sh" ] 
+
+  arguments = {
+    "-H" = "$rbl_host$"
+    "-c" = "$rbl_critical$"
+    "-w" = "$rbl_warning$"
+  }
+}
+
+/**
+ * Check for Prometheus values 
+ */
+
+object CheckCommand "check_metric_value" {
+  import "plugin-check-command"
+
+  command = [ "/opt/check_metric_value/check_metric_value.py" ] 
+
+  arguments = {
+    "-P" = "/opt/prom2json"
+    "-U" = "$metric_url$"
+    "-M" = "$metric_name$"
+    "-n" = "$metric_labelname$"
+    "-v" = "$metric_labelvalue$"
+    "-o" = "$metric_operator$"
+    "-u" = "$metric_unit$"
+    "-w" = "$metric_warn$"
+    "-c" = "$metric_crit$"
+  }
+}
+
+/**
+ * Matrix Notification 
+ */
+
+object NotificationCommand "matrix-host-notification" {
+  import "plugin-notification-command"
+
+  command = [ "/opt/icinga2-matrix-bot/icinga2/matrix-host-notification.sh" ]
+
+  env = {
+    "NOTIFICATIONTYPE" = "$notification.type$"
+    "HOSTALIAS" = "$host.display_name$",
+    "HOSTADDRESS" = "$address$",
+    "HOSTNAME" = "$host.name$",
+    "HOSTSTATE" = "$host.state$",
+    "LONGDATETIME" = "$icinga.long_date_time$",
+    "HOSTOUTPUT" = "$host.output$",
+    "NOTIFICATIONAUTHORNAME" = "$notification.author$",
+    "NOTIFICATIONCOMMENT" = "$notification.comment$",
+    "HOSTDISPLAYNAME" = "$host.display_name$",
+    "ICINGA_WEBURL" = "$notification_icingaweb2url$",
+    "MATRIX_SERVER" = "$user.vars.matrix.server$",
+    "MATRIX_TOKEN" = "$user.vars.matrix.token$",
+    "MATRIX_CHANNEL" = "$user.vars.matrix.channel$",
+  }
+}
+
+object NotificationCommand "matrix-service-notification" {
+  import "plugin-notification-command"
+
+  command = [ "/opt/icinga2-matrix-bot/icinga2/matrix-service-notification.sh" ]
+
+  env = {
+    "NOTIFICATIONTYPE" = "$notification.type$"
+    "SERVICEDESC" = "$service.name$"
+    "HOSTALIAS" = "$host.display_name$",
+    "HOSTNAME" = "$host.name$",
+    "HOSTADDRESS" = "$address$",
+    "SERVICESTATE" = "$service.state$",
+    "LONGDATETIME" = "$icinga.long_date_time$",
+    "SERVICEOUTPUT" = "$service.output$",
+    "NOTIFICATIONAUTHORNAME" = "$notification.author$",
+    "NOTIFICATIONCOMMENT" = "$notification.comment$",
+    "HOSTDISPLAYNAME" = "$host.display_name$",
+    "SERVICEDISPLAYNAME" = "$service.display_name$",
+    "ICINGA_WEBURL" = "$notification_icingaweb2url$",
+    "MATRIX_SERVER" = "$user.vars.matrix.server$",
+    "MATRIX_TOKEN" = "$user.vars.matrix.token$",
+    "MATRIX_CHANNEL" = "$user.vars.matrix.channel$",
+  }
+}
diff --git a/testserver/docker_icinga/templates/etc/icinga/conf.d/groups.conf b/testserver/docker_icinga/templates/etc/icinga/conf.d/groups.conf
new file mode 100644
index 0000000000000000000000000000000000000000..1fe91cbfbf533eea877dc7e1a42dd9396c8e74d9
--- /dev/null
+++ b/testserver/docker_icinga/templates/etc/icinga/conf.d/groups.conf
@@ -0,0 +1,81 @@
+/**
+ * Host groups 
+ */
+
+object HostGroup "linux-servers" {
+  display_name = "Linux Servers"
+
+  assign where host.vars.os == "Linux"
+}
+
+/*
+object HostGroup "windows-servers" {
+  display_name = "Windows Servers"
+
+  assign where host.vars.os == "Windows"
+}
+*/
+
+object HostGroup "network" {
+  display_name = "Network Devices"
+}
+
+object HostGroup "other" {
+  display_name = "Other Devices"
+}
+
+/**
+ * Service groups by check command
+ */
+
+object ServiceGroup "ping" {
+  display_name = "Ping Checks"
+
+  assign where match("ping*", service.name)
+}
+
+object ServiceGroup "http" {
+  display_name = "HTTP Checks"
+
+  assign where match("http*", service.check_command)
+}
+
+object ServiceGroup "dns" {
+  display_name = "DNS Checks"
+
+  assign where match("dig*", service.check_command)
+}
+
+object ServiceGroup "mqtt" {
+  display_name = "MQTT Checks"
+
+  assign where match("check_mqtt*", service.check_command)
+}
+
+/**
+ * Service Goups assigned in Services
+ */
+
+object ServiceGroup "backup" {
+  display_name = "Backup Checks"
+}
+
+object ServiceGroup "container" {
+  display_name = "Docker Container Checks"
+}
+
+object ServiceGroup "ldap" {
+  display_name = "LDAP Checks"
+}
+
+object ServiceGroup "certificate" {
+  display_name = "Certificate Checks"
+}
+
+object ServiceGroup "mail" {
+  display_name = "Mail Checks"
+}
+
+object ServiceGroup "exporter" {
+  display_name = "Metrics Exporter Checks"
+}
diff --git a/testserver/docker_icinga/templates/etc/icinga/conf.d/hosts.conf b/testserver/docker_icinga/templates/etc/icinga/conf.d/hosts.conf
new file mode 100644
index 0000000000000000000000000000000000000000..db49029be3bb535ec25d637a9b1661020e97c4e7
--- /dev/null
+++ b/testserver/docker_icinga/templates/etc/icinga/conf.d/hosts.conf
@@ -0,0 +1,35 @@
+
+{% for host in groups['test'] %}
+{% if hostvars[host].alert is defined and hostvars[host].alert %}
+
+
+object Host "{{ host }}" {
+  import "generic-host"
+
+  address = "{{ hostvars[host].int_ip4 }}"
+
+  {% if hostvars[host].ext_ip4 is defined %}
+  vars.ext_ip4 = "{{ hostvars[host].ext_ip4 }}"
+  {% endif %}
+
+  {% if hostvars[host].ext_ip6 is defined %}
+  vars.ext_ip6 = "{{ hostvars[host].ext_ip6 }}"
+  {% endif %}
+
+  vars.os = "Linux"
+  vars.prometheus = true
+}
+
+{% endif %}
+{% endfor %}
+
+{% for host in monitoring.external_dns_servers %}
+
+object Host "ext_dns_{{ host.name }}" {
+  import "generic-host"
+
+  address = "{{ host.ip }}"
+  vars.is_dnsserver = "True"
+}
+
+{% endfor %}
diff --git a/testserver/docker_icinga/templates/etc/icinga/conf.d/notifications.conf b/testserver/docker_icinga/templates/etc/icinga/conf.d/notifications.conf
new file mode 100644
index 0000000000000000000000000000000000000000..eadaa8ea3ebe47aeddf8d57b3de97a5c03d27287
--- /dev/null
+++ b/testserver/docker_icinga/templates/etc/icinga/conf.d/notifications.conf
@@ -0,0 +1,22 @@
+
+apply Notification "matrix" to Host {
+  import "matrix-host-notification"
+
+  users = [ "matrix" ]
+
+  interval = 4h
+
+  assign where host.address && host.vars.enable_nofitications != false
+}
+
+
+apply Notification "matrix" to Service {
+  import "matrix-service-notification"
+
+  users = [ "matrix" ]
+
+  interval = 4h
+
+  assign where service.name && service.vars.enable_nofitications != false
+}
+
diff --git a/testserver/docker_icinga/templates/etc/icinga/conf.d/notifications_pushover.conf b/testserver/docker_icinga/templates/etc/icinga/conf.d/notifications_pushover.conf
new file mode 100644
index 0000000000000000000000000000000000000000..db34c6b70f923b925bde22a70e2ec7701b562df7
--- /dev/null
+++ b/testserver/docker_icinga/templates/etc/icinga/conf.d/notifications_pushover.conf
@@ -0,0 +1,67 @@
+
+object NotificationCommand "pushover-host-notification" { 
+  import "plugin-notification-command" 
+
+  command = [ "/opt/notify_by_pushover.sh" ] 
+
+  env = { 
+      PUSHOVERUSER = "$user.vars.pushover_user$" 
+      PUSHOVERTOKEN = "$user.vars.pushover_token$" 
+      PUSHOVERTITLE = "Icinga @ {{ inventory_hostname }}" 
+      PUSHOVERMESSAGE = "$notification.type$ $host.display_name$ $host.state$ $icinga.long_date_time$" 
+    } 
+} 
+
+object NotificationCommand "pushover-service-notification" { 
+  import "plugin-notification-command" 
+
+  command = [ "/opt/notify_by_pushover.sh" ] 
+
+  env = { 
+    PUSHOVERUSER = "$user.vars.pushover_user$" 
+    PUSHOVERTOKEN = "$user.vars.pushover_token$" 
+    PUSHOVERTITLE = "Icinga @ {{ inventory_hostname }}" 
+    PUSHOVERMESSAGE = "$notification.type$ $host.display_name$ $service.display_name$ $service.state$ $icinga.long_date_time$" 
+  } 
+} 
+
+template Notification "pushover-host-notification" { 
+  command = "pushover-host-notification" 
+
+  states = [ Up, Down ] 
+  types = [ Problem, FlappingStart ] 
+
+  period = "24x7" 
+} 
+
+template Notification "pushover-service-notification" { 
+  command = "pushover-service-notification" 
+
+  states = [ OK, Critical, Unknown ] 
+  types = [ Problem, FlappingStart ] 
+
+  period = "24x7" 
+} 
+
+apply Notification "pushover-icingaadmins" to Host { 
+  import "pushover-host-notification" 
+
+  user_groups = ["icingaadmins"] 
+
+  interval = 4h
+  times.begin = 15m
+
+  assign where host.address 
+} 
+
+apply Notification "pushover-icingaadmins" to Service { 
+  import "pushover-service-notification" 
+
+  user_groups = ["icingaadmins"] 
+
+  interval = 4h
+  times.begin = 15m
+
+  assign where service.name
+} 
+
diff --git a/testserver/docker_icinga/templates/etc/icinga/conf.d/services.conf b/testserver/docker_icinga/templates/etc/icinga/conf.d/services.conf
new file mode 100644
index 0000000000000000000000000000000000000000..f16e0d33f6ba30cf58327d9098ebcd702c2850bd
--- /dev/null
+++ b/testserver/docker_icinga/templates/etc/icinga/conf.d/services.conf
@@ -0,0 +1,53 @@
+
+apply Service "ping" {
+  import "generic-service"
+
+  check_command = "ping4"
+
+  vars.ping_wrta = "200"
+  vars.ping_crta = "500"
+  vars.ping_wpl = "60"
+  vars.ping_cpl = "90"
+
+  assign where host.address
+}
+
+apply Service "ping_ext_ip4" {
+  import "generic-service"
+
+  check_command = "ping4"
+
+  vars.ping_address = "$host.vars.ext_ip4$"
+
+  vars.ping_wrta = "100"
+  vars.ping_crta = "300"
+  vars.ping_wpl = "20"
+  vars.ping_cpl = "50"
+
+  assign where host.vars.ext_ip4
+}
+
+#apply Service "ping_ext_ip6" {
+#  import "generic-service"
+#
+#  check_command = "ping6"
+#
+#  vars.ping_address = "$host.vars.ext_ip6$"
+#
+#  vars.ping_wrta = "100"
+#  vars.ping_crta = "300"
+#  vars.ping_wpl = "20"
+#  vars.ping_cpl = "50"
+#
+#  assign where host.vars.ext_ip6
+#}
+
+apply Service "ssh" {
+  import "generic-service"
+
+  check_command = "ssh"
+
+  assign where host.address && host.vars.os == "Linux"
+}
+
+
diff --git a/testserver/docker_icinga/templates/etc/icinga/conf.d/services_backup.conf b/testserver/docker_icinga/templates/etc/icinga/conf.d/services_backup.conf
new file mode 100644
index 0000000000000000000000000000000000000000..56a343717529cf8d3c3ce614da6c2f9f0376af10
--- /dev/null
+++ b/testserver/docker_icinga/templates/etc/icinga/conf.d/services_backup.conf
@@ -0,0 +1,51 @@
+
+{% for host in groups['test'] %}
+
+  {% if hostvars[host].borgbackup_repos is defined %}
+  {% for repo in hostvars[host].borgbackup_repos %}
+  {% if hostvars[host].borgbackup_repos[repo].alert is defined and hostvars[host].borgbackup_repos[repo].alert %}
+
+apply Service "borgbackup_age - {{repo}}" {
+  import "generic-service"
+
+  check_command = "check_metric_value"
+  enable_perfdata = true
+
+  vars.metric_url = "http://{{hostvars[host].int_ip4}}:9100/metrics"
+  vars.metric_name = "borgbackup_lastbackup"
+  vars.metric_labelname = "repo"
+  vars.metric_labelvalue = "{{repo}}"
+  vars.metric_operator = "lt-date"
+  vars.metric_unit = "hours"
+  vars.metric_warn = "{{hostvars[host].borgbackup_repos[repo].warning_age}}" 
+  vars.metric_crit = "{{hostvars[host].borgbackup_repos[repo].critical_age}}" 
+
+  groups = [ "backup" ]
+
+  assign where host.name == "{{host}}"
+}
+
+apply Service "borgbackup_count - {{repo}}" {
+  import "generic-service"
+
+  check_command = "check_metric_value"
+  enable_perfdata = true
+
+  vars.metric_url = "http://{{hostvars[host].int_ip4}}:9100/metrics"
+  vars.metric_name = "borgbackup_count"
+  vars.metric_labelname = "repo"
+  vars.metric_labelvalue = "{{repo}}"
+  vars.metric_operator = "lt"
+  vars.metric_warn = "{{hostvars[host].borgbackup_repos[repo].warning_count}}" 
+  vars.metric_crit = "{{hostvars[host].borgbackup_repos[repo].critical_count}}" 
+
+  groups = [ "backup" ]
+
+  assign where host.name == "{{host}}"
+}
+
+  {% endif %}
+  {% endfor %}
+  {% endif %}
+
+{% endfor %}
diff --git a/testserver/docker_icinga/templates/etc/icinga/conf.d/services_container.conf b/testserver/docker_icinga/templates/etc/icinga/conf.d/services_container.conf
new file mode 100644
index 0000000000000000000000000000000000000000..66ccb33e16d568b8e5626e9199b3cc2be1adb67c
--- /dev/null
+++ b/testserver/docker_icinga/templates/etc/icinga/conf.d/services_container.conf
@@ -0,0 +1,118 @@
+
+{% for host in groups['test'] %}
+{% if hostvars[host].alert is defined and hostvars[host].alert %}
+
+  {% if hostvars[host].alert.containers is defined %}
+
+apply Service "docker_metrics" {
+  import "generic-service"
+
+  check_command = "http"
+  enable_perfdata = true
+
+  vars.http_address = "{{hostvars[host].int_ip4}}"
+  vars.http_port = 9323
+  vars.http_uri = "/metrics"
+
+  assign where host.name == "{{host}}" && host.vars.prometheus == true 
+}
+
+apply Service "docker_container_count_low" {
+  import "generic-service"
+
+  check_command = "check_metric_value"
+  enable_perfdata = true
+
+  vars.metric_url = "http://{{hostvars[host].int_ip4}}:9323/metrics"
+  vars.metric_name = "engine_daemon_container_states_containers"
+  vars.metric_labelname = "state"
+  vars.metric_labelvalue = "running"
+  vars.metric_operator = "lt"
+  vars.metric_warn = "{{ hostvars[host].alert.containers|length }}"
+  vars.metric_crit = "{{ hostvars[host].alert.containers|length }}"
+
+  groups = [ "container" ]
+
+  assign where host.name == "{{host}}" && host.vars.prometheus == true && host.vars.os == "Linux"
+}
+
+apply Service "docker_container_count_high" {
+  import "generic-service"
+
+  check_command = "check_metric_value"
+  enable_perfdata = true
+
+  vars.metric_url = "http://{{hostvars[host].int_ip4}}:9323/metrics"
+  vars.metric_name = "engine_daemon_container_states_containers"
+  vars.metric_labelname = "state"
+  vars.metric_labelvalue = "running"
+  vars.metric_operator = "gt"
+  vars.metric_warn = "{{ hostvars[host].alert.containers|length }}"
+  vars.metric_crit = "9999"
+
+  groups = [ "container" ]
+
+  assign where host.name == "{{host}}" && host.vars.prometheus == true && host.vars.os == "Linux"
+}
+
+apply Service "dockerstats_metrics" {
+  import "generic-service"
+
+  check_command = "http"
+  enable_perfdata = true
+
+  vars.http_address = "{{hostvars[host].int_ip4}}"
+  vars.http_port = 9487
+  vars.http_uri = "/metrics"
+
+  assign where host.name == "{{host}}" && host.vars.prometheus == true 
+}
+
+
+    {% for  container in hostvars[host].alert.containers %}
+
+
+apply Service "{{ container.name }} CPU" {
+  import "generic-service"
+
+  check_command = "check_metric_value"
+  enable_perfdata = true
+
+  vars.metric_url = "http://{{hostvars[host].int_ip4}}:9487/metrics"
+  vars.metric_name = "dockerstats_cpu_usage_ratio"
+  vars.metric_labelname = "name"
+  vars.metric_labelvalue = "{{container.name}}"
+  vars.metric_operator = "gt"
+  vars.metric_warn = "80" 
+  vars.metric_crit = "95" 
+
+  groups = [ "container" ]
+
+  assign where host.name == "{{host}}" && host.vars.prometheus == true && host.vars.os == "Linux"
+}
+
+apply Service "{{ container.name }} MEM" {
+  import "generic-service"
+
+  check_command = "check_metric_value"
+  enable_perfdata = true
+
+  vars.metric_url = "http://{{hostvars[host].int_ip4}}:9487/metrics"
+  vars.metric_name = "dockerstats_memory_usage_ratio"
+  vars.metric_labelname = "name"
+  vars.metric_labelvalue = "{{container.name}}"
+  vars.metric_operator = "gt"
+  vars.metric_warn = "80" 
+  vars.metric_crit = "95" 
+
+  groups = [ "container" ]
+
+  assign where host.name == "{{host}}" && host.vars.prometheus == true && host.vars.os == "Linux"
+}
+
+    {% endfor %}
+
+  {% endif %}
+
+{% endif %}
+{% endfor %}
diff --git a/testserver/docker_icinga/templates/etc/icinga/conf.d/services_domains.conf b/testserver/docker_icinga/templates/etc/icinga/conf.d/services_domains.conf
new file mode 100644
index 0000000000000000000000000000000000000000..e0218e99fd8e3273d484d2fa7641d642bbc45e40
--- /dev/null
+++ b/testserver/docker_icinga/templates/etc/icinga/conf.d/services_domains.conf
@@ -0,0 +1,195 @@
+
+{% for host in groups['test'] %}
+
+  {% if hostvars[host].ext_ip4 is defined and hostvars[host].ext_ip6 is defined and hostvars[host].webserver_domains is defined %}
+  {% for domain in hostvars[host].webserver_domains %}
+
+apply Service "http_ok - {{domain}}" {
+  import "generic-service"
+
+  check_command = "http"
+  enable_perfdata = false
+
+  vars.http_address = "{{domain}}"
+  vars.http_vhost = "{{domain}}"
+  vars.http_port = 80
+
+  assign where host.name == "{{host}}"
+}
+
+apply Service "http_301 - {{domain}}" {
+  import "generic-service"
+
+  check_command = "http"
+  enable_perfdata = false
+
+  vars.http_address = "{{domain}}"
+  vars.http_vhost = "{{domain}}"
+  vars.http_port = 80
+  vars.http_expect = "301 Moved Permanently"
+
+  assign where host.name == "{{host}}"
+}
+
+apply Service "https_ok - {{domain}}" {
+  import "generic-service"
+
+  check_command = "http"
+  enable_perfdata = false
+
+  vars.http_address = "{{domain}}"
+  vars.http_vhost = "{{domain}}"
+  vars.http_port = 443
+  vars.http_ssl = true
+  vars.http_sni = true
+
+  assign where host.name == "{{host}}"
+}
+
+apply Service "https_cert - {{domain}}" {
+  import "generic-service"
+
+  check_command = "http"
+  enable_perfdata = false
+
+  vars.http_address = "{{domain}}"
+  vars.http_vhost = "{{domain}}"
+  vars.http_port = 443
+  vars.http_ssl = true
+  vars.http_sni = true
+  vars.http_certificate = "10,5"
+
+  groups = [ "certificate" ]
+
+  assign where host.name == "{{host}}"
+}
+
+apply Service "dig(4) - {{domain}}" {
+  import "generic-service"
+
+  check_command = "dig"
+  enable_perfdata = false
+
+  vars.dig_lookup = "{{domain}}"
+  vars.dig_record_type = "A"
+  vars.dig_expected_address = "{{ hostvars[host].ext_ip4 }}"
+  vars.dig_arguments = "+tcp"
+
+  assign where host.address && host.vars.is_dnsserver == "True"
+}
+
+apply Service "dig(6) - {{domain}}" {
+  import "generic-service"
+
+  check_command = "dig"
+  enable_perfdata = false
+
+  vars.dig_lookup = "{{domain}}"
+  vars.dig_record_type = "AAAA"
+  vars.dig_expected_address = "{{ hostvars[host].ext_ip6 }}"
+  vars.dig_arguments = "+tcp"
+
+  assign where host.address && host.vars.is_dnsserver == "True"
+}
+
+  {% endfor %}
+  {% endif %}
+
+{% endfor %}
+
+
+{% for domain in global_domains %}
+
+apply Service "CAA record - {{ global_domains[domain].domain }}" {
+  import "generic-service"
+
+  check_command = "dig"
+  enable_perfdata = false
+
+  vars.dig_lookup = "{{ global_domains[domain].domain }}"
+  vars.dig_record_type = "CAA"
+  vars.dig_expected_address = "letsencrypt.org"
+  vars.dig_arguments = "+tcp"
+
+  assign where host.address && host.vars.is_dnsserver == "True"
+}
+
+{% endfor %}
+
+
+{% for maildomain in mail_domains %}
+
+apply Service "mx record - {{ mail_domains[maildomain].maildomain }}" {
+  import "generic-service"
+
+  check_command = "dig"
+  enable_perfdata = false
+
+  vars.dig_lookup = "{{ mail_domains[maildomain].maildomain }}"
+  vars.dig_record_type = "MX"
+  vars.dig_expected_address = "{{ mail_domains[maildomain].mxserver }}"
+  vars.dig_arguments = "+tcp"
+
+  groups = [ "mail" ]
+
+  assign where host.address && host.vars.is_dnsserver == "True"
+}
+
+apply Service "spf record - {{ mail_domains[maildomain].maildomain }}" {
+  import "generic-service"
+
+  check_command = "dig"
+  enable_perfdata = false
+
+  vars.dig_lookup = "{{ mail_domains[maildomain].maildomain }}"
+  vars.dig_record_type = "TXT"
+  vars.dig_expected_address = "{{ mail_domains[maildomain].spf }}"
+  vars.dig_arguments = "+tcp"
+
+  groups = [ "mail" ]
+
+  assign where host.address && host.vars.is_dnsserver == "True"
+}
+
+  {% if mail_domains[maildomain].dmarc is defined %}
+
+apply Service "DMARC record - {{ mail_domains[maildomain].maildomain }}" {
+  import "generic-service"
+
+  check_command = "dig"
+  enable_perfdata = false
+
+  vars.dig_lookup = "_dmarc.{{ mail_domains[maildomain].maildomain }}"
+  vars.dig_record_type = "TXT"
+  vars.dig_expected_address = "{{ mail_domains[maildomain].dmarc }}"
+  vars.dig_arguments = "+tcp"
+
+  groups = [ "mail" ]
+
+  assign where host.address && host.vars.is_dnsserver == "True"
+}
+  {% endif %}
+
+  {% if mail_domains[maildomain].dkim is defined %}
+  {% for entry in mail_domains[maildomain].dkim %}
+
+apply Service "DKIM {{entry.selector}} record - {{ mail_domains[maildomain].maildomain }}" {
+  import "generic-service"
+
+  check_command = "dig"
+  enable_perfdata = false
+
+  vars.dig_lookup = "{{entry.selector}}._domainkey.{{ mail_domains[maildomain].maildomain }}"
+  vars.dig_record_type = "TXT"
+  vars.dig_expected_address = "{{ entry.value | replace("\"","\\\"") }}"
+  vars.dig_arguments = "+tcp"
+
+  groups = [ "mail" ]
+
+  assign where host.address && host.vars.is_dnsserver == "True"
+}
+
+  {% endfor %}
+  {% endif %}
+
+{% endfor %}
diff --git a/testserver/docker_icinga/templates/etc/icinga/conf.d/services_exporters.conf b/testserver/docker_icinga/templates/etc/icinga/conf.d/services_exporters.conf
new file mode 100644
index 0000000000000000000000000000000000000000..55ea364e459daaf4f719e97b4f1ec9cb3c62fec1
--- /dev/null
+++ b/testserver/docker_icinga/templates/etc/icinga/conf.d/services_exporters.conf
@@ -0,0 +1,97 @@
+
+{% for host in groups['test'] %}
+{% if hostvars[host].alert is defined and hostvars[host].alert %}
+
+apply Service "node-exporter" {
+  import "generic-service"
+
+  check_command = "http"
+  enable_perfdata = false
+
+  vars.http_address = "{{ hostvars[host].int_ip4 }}"
+  vars.http_port = 9100
+  vars.http_uri = "/metrics"
+
+  groups = [ "exporter" ]
+
+  assign where host.name == "{{host}}"
+}
+
+  {% if hostvars[host].docker.prometheus_metrics is defined %}
+
+apply Service "docker_metrics_exporter" {
+  import "generic-service"
+
+  check_command = "http"
+  enable_perfdata = false
+
+  vars.http_address = "{{ hostvars[host].int_ip4 }}"
+  vars.http_port = 9323
+  vars.http_uri = "/metrics"
+
+  groups = [ "exporter" ]
+
+  assign where host.name == "{{host}}" 
+}
+
+  {% endif %}
+
+  {% if hostvars[host].docker.prometheus_stats is defined %}
+
+apply Service "dockerstats_exporter" {
+  import "generic-service"
+
+  check_command = "http"
+  enable_perfdata = false
+
+  vars.http_address = "{{ hostvars[host].int_ip4 }}"
+  vars.http_port = 9487
+  vars.http_uri = "/metrics"
+
+  groups = [ "exporter" ]
+
+  assign where host.name == "{{host}}" 
+}
+
+  {% endif %}
+
+  {% if hostvars[host].ldap_local.prometheus_metrics is defined %}
+
+apply Service "ldap_metrics_exporter" {
+  import "generic-service"
+
+  check_command = "http"
+  enable_perfdata = false
+
+  vars.http_address = "{{ hostvars[host].int_ip4 }}"
+  vars.http_port = 9328
+  vars.http_uri = "/metrics"
+
+  groups = [ "exporter","ldap" ]
+
+  assign where host.name == "{{host}}" 
+}
+
+  {% endif %}
+
+  {% if host == "webserver2" %}
+
+apply Service "postfix_metrics_exporter" {
+  import "generic-service"
+
+  check_command = "http"
+  enable_perfdata = false
+
+  vars.http_address = "{{ hostvars[host].int_ip4 }}"
+  vars.http_port = 9154
+  vars.http_uri = "/metrics"
+
+  groups = [ "exporter","mail" ]
+
+  assign where host.name == "{{host}}" 
+}
+
+  {% endif %}
+  
+{% endif %}
+{% endfor %}
diff --git a/testserver/docker_icinga/templates/etc/icinga/conf.d/services_mail.conf b/testserver/docker_icinga/templates/etc/icinga/conf.d/services_mail.conf
new file mode 100644
index 0000000000000000000000000000000000000000..d9854354f6f8f5f9f2b5d6abf6afa134bde179cc
--- /dev/null
+++ b/testserver/docker_icinga/templates/etc/icinga/conf.d/services_mail.conf
@@ -0,0 +1,92 @@
+
+{% for maildomain in mail_domains %}
+
+apply Service "mail-smtp - {{ mail_domains[maildomain].maildomain }}" {
+  import "generic-service"
+
+  check_command = "smtp"
+
+  vars.smtp_address = "{{ mail_domains[maildomain].mxserver }}"
+  vars.smtp_port = 25
+
+  groups = [ "mail" ]
+
+  assign where host.name == "{{ mail_domains[maildomain].mxhostname }}"
+}
+
+apply Service "mail-smtp-starttls - {{ mail_domains[maildomain].maildomain }}" {
+  import "generic-service"
+
+  check_command = "smtp"
+
+  vars.smtp_address = "{{ mail_domains[maildomain].mxserver }}"
+  vars.smtp_port = 25
+  vars.smtp_starttls = true
+  vars.smtp_certificate_age = 3
+
+  groups = [ "mail","certificate" ]
+
+  assign where host.name == "{{ mail_domains[maildomain].mxhostname }}"
+}
+
+apply Service "global-smtps - {{ mail_domains[maildomain].maildomain }}" {
+  import "generic-service"
+
+  check_command = "tcp"
+
+  vars.tcp_address = "{{ mail_domains[maildomain].mxserver }}"
+  vars.tcp_port = 465
+
+  groups = [ "mail","certificate" ]
+
+  assign where host.name == "{{ mail_domains[maildomain].mxhostname }}"
+}
+
+apply Service "mail-submission - {{ mail_domains[maildomain].maildomain }}" {
+  import "generic-service"
+
+  check_command = "smtp"
+
+  vars.smtp_address = "{{ mail_domains[maildomain].mxserver }}"
+  vars.smtp_port = 587
+  vars.smtp_starttls = true
+  vars.smtp_certificate_age = 3
+
+  groups = [ "mail","certificate" ]
+
+  assign where host.name == "{{ mail_domains[maildomain].mxhostname }}"
+}
+
+apply Service "mail-imaps - {{ mail_domains[maildomain].maildomain }}" {
+  import "generic-service"
+
+  check_command = "imap"
+
+  vars.imap_address = "{{ mail_domains[maildomain].mxserver }}"
+  vars.imap_port = 993
+  vars.imap_ssl = true
+  vars.imap_certificate_age = 3
+
+  groups = [ "mail","certificate" ]
+
+  assign where host.name == "{{ mail_domains[maildomain].mxhostname }}"
+}
+
+apply Service "mail-blacklist - {{ mail_domains[maildomain].maildomain }}" {
+  import "generic-service"
+
+  check_command = "check_mail_blacklist"
+  check_interval = 5m
+  retry_interval = 3m
+  check_timeout = 1m
+
+  vars.rbl_host = "{{ mail_domains[maildomain].mxserver }}"
+  vars.rbl_warning = 1
+  vars.rbl_critical = 3
+
+  groups = [ "mail" ]
+
+  assign where host.name == "{{ mail_domains[maildomain].mxhostname }}"
+}
+
+{% endfor %}
diff --git a/testserver/docker_icinga/templates/etc/icinga/conf.d/services_manual.conf b/testserver/docker_icinga/templates/etc/icinga/conf.d/services_manual.conf
new file mode 100644
index 0000000000000000000000000000000000000000..3b7fd2af884aed800c75d78fbaf4a355e921dc2d
--- /dev/null
+++ b/testserver/docker_icinga/templates/etc/icinga/conf.d/services_manual.conf
@@ -0,0 +1,44 @@
+apply Service "wz-uplink-globe" {
+  import "generic-service"
+
+  check_command = "ping4"
+
+  vars.ping_address = "212.124.34.242"
+
+  vars.ping_wrta = "100"
+  vars.ping_crta = "300"
+  vars.ping_wpl = "20"
+  vars.ping_cpl = "50"
+
+  assign where host.name == "wz-router"
+}
+
+apply Service "wz-uplink-webdiscount-1" {
+  import "generic-service"
+
+  check_command = "ping4"
+
+  vars.ping_address = "212.3.64.45"
+
+  vars.ping_wrta = "100"
+  vars.ping_crta = "300"
+  vars.ping_wpl = "20"
+  vars.ping_cpl = "50"
+
+  assign where host.name == "wz-router"
+}
+
+apply Service "wz-uplink-webdiscount-2" {
+  import "generic-service"
+
+  check_command = "ping4"
+
+  vars.ping_address = "212.3.80.222"
+
+  vars.ping_wrta = "100"
+  vars.ping_crta = "300"
+  vars.ping_wpl= "20"
+  vars.ping_cpl = "50"
+
+  assign where host.name == "wz-router"
+}
diff --git a/testserver/docker_icinga/templates/etc/icinga/conf.d/services_mqttsensors.conf b/testserver/docker_icinga/templates/etc/icinga/conf.d/services_mqttsensors.conf
new file mode 100644
index 0000000000000000000000000000000000000000..61650544a0c1616588856dcf1d44e44d3d689a90
--- /dev/null
+++ b/testserver/docker_icinga/templates/etc/icinga/conf.d/services_mqttsensors.conf
@@ -0,0 +1,18 @@
+
+{% for device in esphome_devices %}
+
+apply Service "esphome-{{ device.id }}-status" {
+  import "generic-service"
+
+  check_command = "check_mqtt"
+
+  vars.mqtt_host = "{{ mqtt.ip }}"
+  vars.mqtt_topic = "ESPHome/esphome_{{ device.id }}/status"
+  vars.mqtt_value = "online"
+  vars.mqtt_operator = "equal"
+  vars.mqtt_readonly = true
+
+  assign where host.name == "intserver"
+}
+
+{% endfor %}
\ No newline at end of file
diff --git a/testserver/docker_icinga/templates/etc/icinga/conf.d/services_system.conf b/testserver/docker_icinga/templates/etc/icinga/conf.d/services_system.conf
new file mode 100644
index 0000000000000000000000000000000000000000..01d0ae78032c6b1246e90a7820dc3a1d0cb8bd29
--- /dev/null
+++ b/testserver/docker_icinga/templates/etc/icinga/conf.d/services_system.conf
@@ -0,0 +1,133 @@
+
+{% for host in groups['test'] %}
+{% if hostvars[host].alert is defined and hostvars[host].alert %}
+
+apply Service "node_metrics" {
+  import "generic-service"
+
+  check_command = "http"
+  enable_perfdata = true
+
+  vars.http_address = "{{hostvars[host].int_ip4}}"
+  vars.http_port = 9100
+  vars.http_uri = "/metrics"
+
+  assign where host.name == "{{host}}" && host.vars.prometheus == true 
+}
+
+apply Service "node_load1" {
+  import "generic-service"
+
+  check_command = "check_metric_value"
+  enable_perfdata = true
+
+  vars.metric_url = "http://{{hostvars[host].int_ip4}}:9100/metrics"
+  vars.metric_name = "node_load1"
+  vars.metric_operator = "gt"
+  vars.metric_warn = "{{ hostvars[host].alert.load.warn }}"
+  vars.metric_crit = "{{ hostvars[host].alert.load.crit }}"
+
+  assign where host.name == "{{host}}" && host.vars.prometheus == true && host.vars.os == "Linux"
+}
+
+apply Service "node_load5" {
+  import "generic-service"
+
+  check_command = "check_metric_value"
+  enable_perfdata = true
+
+  vars.metric_url = "http://{{hostvars[host].int_ip4}}:9100/metrics"
+  vars.metric_name = "node_load5"
+  vars.metric_operator = "gt"
+  vars.metric_warn = "{{ hostvars[host].alert.load.warn }}"
+  vars.metric_crit = "{{ hostvars[host].alert.load.crit }}"
+
+  assign where host.name == "{{host}}" && host.vars.prometheus == true && host.vars.os == "Linux"
+}
+
+apply Service "node_load15" {
+  import "generic-service"
+
+  check_command = "check_metric_value"
+  enable_perfdata = true
+
+  vars.metric_url = "http://{{hostvars[host].int_ip4}}:9100/metrics"
+  vars.metric_name = "node_load15"
+  vars.metric_operator = "gt"
+  vars.metric_warn = "{{ hostvars[host].alert.load.warn }}"
+  vars.metric_crit = "{{ hostvars[host].alert.load.crit }}"
+
+  assign where host.name == "{{host}}" && host.vars.prometheus == true && host.vars.os == "Linux"
+}
+
+apply Service "node_reboot_required" {
+  import "generic-service"
+
+  check_command = "check_metric_value"
+  enable_perfdata = true
+
+  vars.metric_url = "http://{{hostvars[host].int_ip4}}:9100/metrics"
+  vars.metric_name = "node_reboot_required"
+  vars.metric_operator = "gt"
+  vars.metric_warn = "0"
+  vars.metric_crit = "1"
+
+  assign where host.name == "{{host}}" && host.vars.prometheus == true && host.vars.os == "Linux"
+}
+
+apply Service "apt_upgrades_pending" {
+  import "generic-service"
+
+  check_command = "check_metric_value"
+  enable_perfdata = true
+
+  vars.metric_url = "http://{{hostvars[host].int_ip4}}:9100/metrics"
+  vars.metric_name = "apt_upgrades_pending"
+  vars.metric_operator = "gt"
+  vars.metric_warn = "1"
+  vars.metric_crit = "25"
+
+  assign where host.name == "{{host}}" && host.vars.prometheus == true && host.vars.os == "Linux"
+}
+
+  {% for disk in hostvars[host].alert.disks %}
+
+apply Service "node_filesystem_free_bytes - {{disk.mountpoint}}" {
+  import "generic-service"
+
+  check_command = "check_metric_value"
+  enable_perfdata = true
+
+  vars.metric_url = "http://{{hostvars[host].int_ip4}}:9100/metrics"
+  vars.metric_name = "node_filesystem_free_bytes"
+  vars.metric_labelname = "mountpoint"
+  vars.metric_labelvalue = "{{disk.mountpoint}}"
+  vars.metric_operator = "lt"
+  vars.metric_warn = "{{disk.warn | human_to_bytes }}" 
+  vars.metric_crit = "{{disk.crit | human_to_bytes }}" 
+
+  assign where host.name == "{{host}}" && host.vars.prometheus == true && host.vars.os == "Linux"
+}
+
+apply Service "node_filesystem_device_error - {{disk.mountpoint}}" {
+  import "generic-service"
+
+  check_command = "check_metric_value"
+  enable_perfdata = true
+
+  vars.metric_url = "http://{{hostvars[host].int_ip4}}:9100/metrics"
+  vars.metric_name = "node_filesystem_device_error"
+  vars.metric_labelname = "mountpoint"
+  vars.metric_labelvalue = "{{disk.mountpoint}}"
+  vars.metric_operator = "gt"
+  vars.metric_warn = "0" 
+  vars.metric_crit = "0" 
+
+  assign where host.name == "{{host}}" && host.vars.prometheus == true && host.vars.os == "Linux"
+}
+
+  {% endfor %}
+
+
+{% endif %}
+{% endfor %}
diff --git a/testserver/docker_icinga/templates/etc/icinga/conf.d/templates.conf b/testserver/docker_icinga/templates/etc/icinga/conf.d/templates.conf
new file mode 100644
index 0000000000000000000000000000000000000000..4cc6d9e0f17b510a589252cc4034256a9dd69e1c
--- /dev/null
+++ b/testserver/docker_icinga/templates/etc/icinga/conf.d/templates.conf
@@ -0,0 +1,110 @@
+/*
+ * Generic template examples.
+ */
+
+
+/**
+ * Provides default settings for hosts. By convention
+ * all hosts should import this template.
+ *
+ * The CheckCommand object `hostalive` is provided by
+ * the plugin check command templates.
+ * Check the documentation for details.
+ */
+template Host "generic-host" {
+  max_check_attempts = 3
+  check_interval = 1m
+  retry_interval = 30s
+
+  check_command = "hostalive"
+}
+
+/**
+ * Provides default settings for services. By convention
+ * all services should import this template.
+ */
+template Service "generic-service" {
+  max_check_attempts = 5
+  check_interval = 1m
+  retry_interval = 30s
+}
+
+/**
+ * Provides default settings for users. By convention
+ * all users should inherit from this template.
+ */
+
+template User "generic-user" {
+
+}
+
+/**
+ * Provides default settings for host notifications.
+ * By convention all host notifications should import
+ * this template.
+ */
+template Notification "mail-host-notification" {
+  command = "mail-host-notification"
+
+  states = [ Up, Down ]
+  types = [ Problem, Acknowledgement, Recovery, Custom,
+            FlappingStart, FlappingEnd,
+            DowntimeStart, DowntimeEnd, DowntimeRemoved ]
+
+  vars += {
+    // notification_icingaweb2url = "https://www.example.com/icingaweb2"
+    // notification_from = "Icinga 2 Host Monitoring <icinga@example.com>"
+    notification_logtosyslog = false
+  }
+
+  period = "24x7"
+}
+
+/**
+ * Provides default settings for service notifications.
+ * By convention all service notifications should import
+ * this template.
+ */
+template Notification "mail-service-notification" {
+  command = "mail-service-notification"
+
+  states = [ OK, Warning, Critical, Unknown ]
+  types = [ Problem, Acknowledgement, Recovery, Custom,
+            FlappingStart, FlappingEnd,
+            DowntimeStart, DowntimeEnd, DowntimeRemoved ]
+
+  vars += {
+    // notification_icingaweb2url = "https://www.example.com/icingaweb2"
+    // notification_from = "Icinga 2 Service Monitoring <icinga@example.com>"
+    notification_logtosyslog = false
+  }
+
+  period = "24x7"
+}
+
+/**
+ * Provides default settings for Matrix.org service notifications.
+ */
+
+template Notification "matrix-host-notification" {
+    command = "matrix-host-notification"
+
+    states = [ Up, Down ]
+    types = [ Problem, Acknowledgement, Custom, FlappingStart, FlappingEnd ]
+    period = "24x7"
+    vars += {
+        notification_icingaweb2url = "https://{{ domain }}/icingaweb2"
+    }
+}
+
+template Notification "matrix-service-notification" {
+    command = "matrix-service-notification"
+
+    states = [ OK, Critical, Unknown ]
+    types = [ Problem, Acknowledgement, Custom, FlappingStart, FlappingEnd ]
+    period = "24x7"
+    vars += {
+        notification_icingaweb2url = "https://{{ domain }}/icingaweb2"
+    }
+}
+
diff --git a/testserver/docker_icinga/templates/etc/icinga/conf.d/users_groups.conf b/testserver/docker_icinga/templates/etc/icinga/conf.d/users_groups.conf
new file mode 100644
index 0000000000000000000000000000000000000000..c16c7ea70af8c76166a5e24274d178999a02947d
--- /dev/null
+++ b/testserver/docker_icinga/templates/etc/icinga/conf.d/users_groups.conf
@@ -0,0 +1,20 @@
+
+object UserGroup "icingaadmins" {
+  display_name = "Icinga 2 Admin Group"
+}
+
+object User "matrix" {
+  import "generic-user"
+
+  display_name = "Matrix User"
+  vars.matrix = {
+    token = "{{ matrix_notification_access_token }}"
+    channel = "{{ matrix.notifications_room_id }}"
+    server = "{{ matrix.public_url }}"
+  }
+}
+
+object UserGroup "matrix" {
+  display_name = "Matrix Group"
+  assign where user.vars.matrix
+}
diff --git a/testserver/docker_icinga/templates/etc/icinga/conf.d/users_sample.conf b/testserver/docker_icinga/templates/etc/icinga/conf.d/users_sample.conf
new file mode 100644
index 0000000000000000000000000000000000000000..f093dafe8f39c0004ea1a9d5176b9836da6e2d89
--- /dev/null
+++ b/testserver/docker_icinga/templates/etc/icinga/conf.d/users_sample.conf
@@ -0,0 +1,17 @@
+/**
+ * Users are created on the Server directly and not managed by Ansible
+ */
+
+/*
+object User "sample-user" {
+  import "generic-user"
+
+  display_name = "Icinga 2 Admin"
+  groups = [ "icingaadmins" ]
+
+  email = "root@localhost"
+
+  vars.pushover_user = "xxxxxxxxxxxxxxxxx"
+  vars.pushover_token = "yyyyyyyyyyyyyyyyyy"
+}
+*/
diff --git a/testserver/docker_icinga/templates/etc/icingaweb2/authentication.ini b/testserver/docker_icinga/templates/etc/icingaweb2/authentication.ini
new file mode 100644
index 0000000000000000000000000000000000000000..3ff4ecf53c6e3d8e48ef1929b43995f2c58a0e4b
--- /dev/null
+++ b/testserver/docker_icinga/templates/etc/icingaweb2/authentication.ini
@@ -0,0 +1,7 @@
+
+[autologin]
+backend = external
+
+[auth_db]
+backend  = db
+resource = icingaweb_db
diff --git a/testserver/docker_icinga/templates/etc/icingaweb2/groups.ini b/testserver/docker_icinga/templates/etc/icingaweb2/groups.ini
new file mode 100644
index 0000000000000000000000000000000000000000..5e5341acfa146364431b2f4e4da6aa6497b5081e
--- /dev/null
+++ b/testserver/docker_icinga/templates/etc/icingaweb2/groups.ini
@@ -0,0 +1,5 @@
+
+[icingaweb2]
+backend = "db"
+resource = "icingaweb_db"
+
diff --git a/testserver/docker_icinga/templates/etc/icingaweb2/resources.ini b/testserver/docker_icinga/templates/etc/icingaweb2/resources.ini
new file mode 100644
index 0000000000000000000000000000000000000000..324c3c5dfa543007f0a83b70ce3e6a1a29b64902
--- /dev/null
+++ b/testserver/docker_icinga/templates/etc/icingaweb2/resources.ini
@@ -0,0 +1,23 @@
+[icingaweb_db]
+type = "db"
+db = "mysql"
+host = db
+port = 3306
+dbname = icingaweb2
+username = icinga
+password = "{{ mysql_user_pass }}"
+prefix = "icingaweb_"
+charset = "utf8"
+persistent = "0"
+
+[icinga_ido]
+type = "db"
+db = "mysql"
+host = db
+port = 3306
+dbname = icinga2idomysql
+username = icinga
+password = "{{ mysql_user_pass }}"
+charset = "utf8"
+persistent = "0"
+
diff --git a/testserver/docker_icinga/templates/etc/icingaweb2/roles.ini b/testserver/docker_icinga/templates/etc/icingaweb2/roles.ini
new file mode 100644
index 0000000000000000000000000000000000000000..b01bb3be859322253bc13ce44e4a2b8a7057098d
--- /dev/null
+++ b/testserver/docker_icinga/templates/etc/icingaweb2/roles.ini
@@ -0,0 +1,11 @@
+
+[Administrators]
+users = "icingaadmin"
+permissions = "*"
+groups = "Administrators"
+
+[Users]
+users = "*"
+groups = admin
+permissions = "application/*, module/*, monitoring/*"
+
diff --git a/testserver/docker_icinga/templates/etc/locale.gen b/testserver/docker_icinga/templates/etc/locale.gen
new file mode 100644
index 0000000000000000000000000000000000000000..906268dc040b6b1fe14ce28105576e02bf555eca
--- /dev/null
+++ b/testserver/docker_icinga/templates/etc/locale.gen
@@ -0,0 +1,7 @@
+# This file lists locales that you wish to have built. You can find a list
+# of valid supported locales at /usr/share/i18n/SUPPORTED, and you can add
+# user defined locales to /usr/local/share/i18n/SUPPORTED. If you change
+# this file, you need to rerun locale-gen.
+
+de_DE.UTF-8 UTF-8
+en_US.UTF-8 UTF-8
diff --git a/testserver/docker_icinga/templates/etc/oauth_header.conf b/testserver/docker_icinga/templates/etc/oauth_header.conf
new file mode 100644
index 0000000000000000000000000000000000000000..e640e9934224efaa1c75916974d5a68a245a45af
--- /dev/null
+++ b/testserver/docker_icinga/templates/etc/oauth_header.conf
@@ -0,0 +1,8 @@
+
+# Integratin der vorgeschalteten OAuth Anmeldung
+# Umgebungsvariable REMOTE_USER aus dem Header X-Forwarded-User setzen, damit das Autologin funktioniert
+# Der User wird in der Datenbank automatisch angelegt
+SetEnvIfNoCase X-Forwarded-User "(.*)" REMOTE_USER=$1
+
+# Abmelden Seite auf Abmelden im SSO umbiegen 
+Redirect "/icingaweb2/authentication/logout" {{ oauth_global.logout_url }}
diff --git a/testserver/docker_icinga/templates/graphite-conf/storage-schemas.conf b/testserver/docker_icinga/templates/graphite-conf/storage-schemas.conf
new file mode 100644
index 0000000000000000000000000000000000000000..0c6cb27c5242564cc27d8c6f844b87bd2188dc82
--- /dev/null
+++ b/testserver/docker_icinga/templates/graphite-conf/storage-schemas.conf
@@ -0,0 +1,33 @@
+
+# Schema definitions for Whisper files. Entries are scanned in order,
+# and first match wins. This file is scanned for changes every 60 seconds.
+#
+# Definition Syntax:
+#
+#    [name]
+#    pattern = regex
+#    retentions = timePerPoint:timeToStore, timePerPoint:timeToStore, ...
+#
+# Remember: To support accurate aggregation from higher to lower resolution
+#           archives, the precision of a longer retention archive must be
+#           cleanly divisible by precision of next lower retention archive.
+#
+#           Valid:    60s:7d,300s:30d (300/60 = 5)
+#           Invalid:  180s:7d,300s:30d (300/180 = 3.333)
+#
+
+# Carbon's internal metrics. This entry should match what is specified in
+# CARBON_METRIC_PREFIX and CARBON_METRIC_INTERVAL settings
+[carbon]
+pattern = ^carbon\.
+retentions = 10s:6h,1m:90d
+
+[default]
+pattern = .*
+retentions = 10s:6h,1m:90d
+
+[icinga2_default]
+pattern = .*
+retentions = 1m:2d,5m:10d,30m:90d,60m:1y
+
+
diff --git a/testserver/docker_icinga/templates/logrotate b/testserver/docker_icinga/templates/logrotate
new file mode 100644
index 0000000000000000000000000000000000000000..391bc41e223aad56556f0c64ed1edb2762218521
--- /dev/null
+++ b/testserver/docker_icinga/templates/logrotate
@@ -0,0 +1,28 @@
+/srv/icinga/log/apache2/*.log {
+  rotate 12
+  monthly
+  compress
+  missingok
+  notifempty
+}
+/srv/icinga/log/icinga2/*.log {
+  rotate 12
+  monthly
+  compress
+  missingok
+  notifempty
+}
+/srv/icinga/log/icingaweb2/*.log {
+  rotate 12
+  monthly
+  compress
+  missingok
+  notifempty
+}
+/srv/icinga/graphite-log/*.log {
+  rotate 12
+  monthly
+  compress
+  missingok
+  notifempty
+}
\ No newline at end of file
diff --git a/testserver/docker_icinga/templates/notify_by_pushover.sh b/testserver/docker_icinga/templates/notify_by_pushover.sh
new file mode 100644
index 0000000000000000000000000000000000000000..9a4ccf8f0bddf9749320b8c050d1d42765e6b8e9
--- /dev/null
+++ b/testserver/docker_icinga/templates/notify_by_pushover.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+response=$(curl --write-out %{http_code} --silent \
+-F "token=$PUSHOVERTOKEN" \
+-F "user=$PUSHOVERUSER" \
+-F "title=$PUSHOVERTITLE" \
+-F "message=$PUSHOVERMESSAGE" \
+https://api.pushover.net/1/messages)
+if [[ "$response" == *200 ]]
+then
+    echo Pushover message sent succesfully
+    exit 0
+else
+    echo Activation of Pushover service failed. This is the response from Pushover: $response
+    exit 1
+fi
\ No newline at end of file
diff --git a/testserver/docker_mail/tasks/main.yaml b/testserver/docker_mail/tasks/main.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c9d324eeae4f03c95927ce028437498f0f374336
--- /dev/null
+++ b/testserver/docker_mail/tasks/main.yaml
@@ -0,0 +1,112 @@
+---
+
+- include_tasks: ../functions/get_secret.yml
+  with_items:
+   - { path: "{{ basedir }}/secrets/mailu_secret_key",  length: 32 }
+   - { path: "{{ basedir }}/secrets/mailu_admin_pass",  length: 32 }
+   - { path: "{{ basedir }}/secrets/mailu_api_token",  length: 32 }
+   - { path: "{{ basedir }}/secrets/mailu_db_pass",  length: 28 }
+   - { path: "{{ basedir }}/secrets/roundcube_db_pass",  length: 28 }
+   - { path: "{{ basedir }}/secrets/hyperkitty_api_key",  length: 28 }
+   - { path: "{{ basedir }}/secrets/mailman_db_pass",  length: 28 }
+   - { path: "{{ basedir }}/secrets/mailman_secret_key",  length: 28 }
+   - { path: "{{ basedir }}/secrets/mailman_restapi_pass",  length: 28 }
+   - { path: "{{ basedir }}/secrets/mysql_root_pass",  length: 28 }
+
+
+# - name: pakete installieren
+#   apt:
+#     pkg: ['logrotate']
+#     update_cache: no
+#     state: present
+
+
+- name: "create folder struct for {{ servicename }}"
+  file:
+    path: "{{ item }}"
+    state: "directory"
+  with_items:
+    - "{{ basedir }}"
+    - "{{ basedir }}/secrets"
+    - "{{ basedir }}/db"
+    - "{{ basedir }}/db-init"
+    - "{{ basedir }}/mailu"
+    - "{{ basedir }}/mailu/overrides"
+    - "{{ basedir }}/mailu/overrides/postfix"
+    - "{{ basedir }}/mailman-core"
+    - "{{ basedir }}/mailman-core/var"
+    - "{{ basedir }}/mailman-core/var/data"
+    - "{{ basedir }}/mailman-web"
+#    - "{{ basedir }}/mailman-db"
+
+
+# - name: "create folder struct for {{ servicename }} with rights"
+#   file:
+#     path: "{{ item }}"
+#     state: "directory"
+#     owner: "5000"
+#     group: "5000"
+#     mode: "ugo+rwx"
+#   with_items:
+#   - "{{ basedir }}/data/crypt"
+#   - "{{ basedir }}/data/vmail"
+#   - "{{ basedir }}/data/vmail-index"
+
+
+
+- name: "deploy {{ servicename }} config files"
+  template:
+    dest:  "{{ basedir }}/{{ item }}"
+    src: "{{ item }}"
+    mode: 0644
+  with_items:
+    - docker-compose.yml
+    - mailu.env
+    - mailman.env
+    - mailman-nginx.conf
+    - db-init/mailman.sql
+    - db-init/roundcube.sql
+    - mailu/overrides/postfix/postfix.cf
+  register: config
+
+- name: "set local dns record"
+  become: true
+  blockinfile:
+    path: /etc/hosts
+    create: yes
+    block: |
+      {{ ext_ip4 }} mailserver.warpzone.ms
+
+# - name: deploy LogRotate configs
+#   template:
+#     src: "logrotate/{{item}}"
+#     dest: "/etc/logrotate.d/{{item}}"
+#   with_items:
+#     - mailman-core
+#     - mailman-web
+
+
+# Start containers
+- name: "stop {{ servicename }} docker"
+  community.docker.docker_compose_v2:
+    project_src: "{{ basedir }}"
+    state: absent
+  when: config.changed
+
+- name: "start {{ servicename }} docker"
+  community.docker.docker_compose_v2:
+    project_src: "{{ basedir }}"
+    state: present
+
+
+# Start mailman containers
+# - name: "stop {{ servicename }} (mailman) docker"
+#   community.docker.docker_compose_v2:
+#     project_src: "{{ basedir }}/docker-mailman"
+#     state: absent
+#   when: config_mailcow.changed
+
+# - name: "start {{ servicename }} (mailman) docker"
+#   community.docker.docker_compose_v2:
+#     project_src: "{{ basedir }}/docker-mailman"
+#     state: present
diff --git a/testserver/docker_mail/templates/db-init/mailman.sql b/testserver/docker_mail/templates/db-init/mailman.sql
new file mode 100644
index 0000000000000000000000000000000000000000..27ff11b022f639467d9da9686b81477be370d439
--- /dev/null
+++ b/testserver/docker_mail/templates/db-init/mailman.sql
@@ -0,0 +1,4 @@
+CREATE DATABASE IF NOT EXISTS mailman;
+CREATE USER IF NOT EXISTS mailman@'%' IDENTIFIED BY '{{ mailman_db_pass }}';
+GRANT ALL ON mailman.* TO mailman@'%';
+FLUSH PRIVILEGES;
diff --git a/testserver/docker_mail/templates/db-init/roundcube.sql b/testserver/docker_mail/templates/db-init/roundcube.sql
new file mode 100644
index 0000000000000000000000000000000000000000..32e4983adfe2d9ae4976b9383d0feb1330c14e73
--- /dev/null
+++ b/testserver/docker_mail/templates/db-init/roundcube.sql
@@ -0,0 +1,4 @@
+CREATE DATABASE IF NOT EXISTS roundcube;
+CREATE USER IF NOT EXISTS roundcube@'%' IDENTIFIED BY '{{ roundcube_db_pass }}';
+GRANT ALL ON roundcube.* TO roundcube@'%';
+FLUSH PRIVILEGES;
diff --git a/testserver/docker_mail/templates/docker-compose.yml b/testserver/docker_mail/templates/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..2d8e493774c2fb7792e76daa17633afd6dcc9536
--- /dev/null
+++ b/testserver/docker_mail/templates/docker-compose.yml
@@ -0,0 +1,218 @@
+version: '2.2'
+
+services:
+
+  # External dependencies
+  redis:
+    image: redis:7-alpine
+    restart: always
+    volumes:
+      - "{{ basedir }}/mailu/redis:/data"
+    depends_on:
+      - resolver
+    dns:
+      - 192.168.203.254
+
+  # Certdumper
+  certdumper:
+    image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}traefik-certdumper:${MAILU_VERSION:-2.0}
+    restart: always
+    environment:
+      - DOMAIN={{ mailserver }}
+      - TRAEFIK_VERSION=v2
+    volumes:
+      - "/srv/traefik:/traefik"
+      - "{{ basedir }}/mailu/certs:/output"
+
+  # Core services
+  front:
+    image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}nginx:${MAILU_VERSION:-2.0}
+    restart: always
+    depends_on:
+      - db
+      - resolver
+    env_file: mailu.env
+    ports:
+      - "25:25" #smtp
+      - "465:465" #submissions
+      - "587:587" #submission
+      - "143:143" #imap
+      - "993:993" #imaps
+    volumes:
+      - "{{ basedir }}/mailu/certs:/certs"
+      - "{{ basedir }}/mailu/overrides/nginx:/overrides:ro"
+    labels:
+      - "traefik.enable=true"
+      - "traefik.http.routers.{{ servicename }}.entrypoints=websecure"
+      - "traefik.http.routers.{{ servicename }}.rule=Host(`{{ mailserver }}`)"
+      - "traefik.http.routers.{{ servicename }}.tls"
+      - "traefik.http.routers.{{ servicename }}.tls.certresolver=letsencrypt"
+      - "traefik.http.routers.{{ servicename }}.tls.domains[0].main={{ domain }}"
+      - "traefik.http.routers.{{ servicename }}.tls.domains[0].sans={{ mailserver }},imap.test-warpzone.de,smtp.test-warpzone.de"
+      - "traefik.http.routers.{{ servicename }}.service={{ servicename }}"
+      - "traefik.http.services.{{ servicename }}.loadbalancer.server.port=80"
+    networks:
+      - default
+      - web
+    dns:
+      - 192.168.203.254
+
+  resolver:
+    image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}unbound:${MAILU_VERSION:-2.0}
+    env_file: mailu.env
+    restart: always
+    networks:
+      default:
+        ipv4_address: 192.168.203.254
+
+  admin:
+    image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}admin:${MAILU_VERSION:-2.0}
+    restart: always
+    depends_on:
+      - db
+      - redis
+      - resolver
+    env_file: mailu.env
+    volumes:
+      - "{{ basedir }}/mailu/data:/data"
+      - "{{ basedir }}/mailu/dkim:/dkim"
+    dns:
+      - 192.168.203.254
+
+  imap:
+    image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}dovecot:${MAILU_VERSION:-2.0}
+    restart: always
+    depends_on:
+      - db
+      - front
+      - resolver
+    env_file: mailu.env
+    volumes:
+      - "{{ basedir }}/mailu/mail:/mail"
+      - "{{ basedir }}/mailu/overrides/dovecot:/overrides:ro"
+    dns:
+      - 192.168.203.254
+
+  smtp:
+    image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}postfix:${MAILU_VERSION:-2.0}
+    restart: always
+    depends_on:
+      - db
+      - front
+      - resolver
+      - mailman-core
+    env_file: mailu.env
+    volumes:
+      - "{{ basedir }}/mailu/mailqueue:/queue"
+      - "{{ basedir }}/mailu/overrides/postfix:/overrides:ro"
+      - "{{ basedir }}/mailman-core/var/data:/opt/mailman:ro"
+    dns:
+      - 192.168.203.254
+
+  oletools:
+    image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}oletools:${MAILU_VERSION:-2.0}
+    hostname: oletools
+    restart: always
+    depends_on:
+      - resolver
+    networks:
+      - noinet
+    dns:
+      - 192.168.203.254
+
+  antispam:
+    image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}rspamd:${MAILU_VERSION:-2.0}
+    hostname: antispam
+    restart: always
+    depends_on:
+      - front
+      - redis
+      - oletools
+      - resolver
+    env_file: mailu.env
+    volumes:
+      - "{{ basedir }}/mailu/filter:/var/lib/rspamd"
+      - "{{ basedir }}/mailu/overrides/rspamd:/overrides:ro"
+    networks:
+      default:
+        ipv4_address: 192.168.203.253
+      noinet:
+    dns:
+      - 192.168.203.254
+
+  # Optional mailu services: Database
+  db:
+    image: mariadb:11
+    command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
+    restart: always
+    volumes:
+      - "{{ basedir }}/db:/var/lib/mysql"
+      - "{{ basedir }}/db-init:/docker-entrypoint-initdb.d:ro"
+    environment:
+      - MYSQL_DATABASE=mailu
+      - MYSQL_USER=mailu
+      - MYSQL_PASSWORD={{ mailu_db_pass }}
+      - MYSQL_ROOT_PASSWORD={{ mysql_root_pass }}
+
+  # Optional mailu services: Webmail
+  webmail:
+    image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}webmail:${MAILU_VERSION:-2.0}
+    restart: always
+    depends_on:
+      - front
+    env_file: mailu.env
+    volumes:
+      - "{{ basedir }}/mailu/webmail:/data"
+      - "{{ basedir }}/mailu/overrides/roundcube:/overrides:ro"
+
+  # Additional Services: mailman
+  mailman-core:
+    image: maxking/mailman-core:0.4
+    restart: always
+    env_file: mailman.env
+    depends_on:
+      - db
+    volumes:
+      - "{{ basedir }}/mailman-core:/opt/mailman:rw,z"
+
+  mailman-web:
+    image: maxking/mailman-web:0.4
+    restart: always
+    env_file: mailman.env
+    depends_on:
+      - db
+    volumes:
+      - "{{ basedir }}/mailman-web:/opt/mailman-web-data:rw,z"
+
+  mailman-nginx:
+    image: nginx:1.25
+    restart: always
+    depends_on:
+      - mailman-web
+    volumes:
+      - "{{ basedir }}/mailman-web/:/opt/mailman-web-data:ro,z"
+      - "{{ basedir }}/mailman-nginx.conf:/etc/nginx/conf.d/default.conf:ro" 
+    labels:
+      - traefik.enable=true
+      - traefik.http.routers.{{ servicename }}-mailman.rule=Host(`{{ listserver }}`)
+      - traefik.http.routers.{{ servicename }}-mailman.entrypoints=websecure
+      - traefik.http.services.{{ servicename }}-mailman.loadbalancer.server.port=80
+    networks:
+      - default
+      - web
+
+networks:
+  default:
+    driver: bridge
+    enable_ipv6: true
+    ipam:
+      driver: default
+      config:
+        # must be a ULA range
+        - subnet: fd00:dead:beef:25::/64
+        - subnet: 192.168.203.0/24
+  noinet:
+    driver: bridge
+    internal: true
+  web:
+    external: true
diff --git a/webserver/docker_mail/templates/docker-mailman/nginx.conf b/testserver/docker_mail/templates/mailman-nginx.conf
similarity index 100%
rename from webserver/docker_mail/templates/docker-mailman/nginx.conf
rename to testserver/docker_mail/templates/mailman-nginx.conf
diff --git a/testserver/docker_mail/templates/mailman.env b/testserver/docker_mail/templates/mailman.env
new file mode 100644
index 0000000000000000000000000000000000000000..7ade751389ef13db6a94193c0bd67c65314f6ace
--- /dev/null
+++ b/testserver/docker_mail/templates/mailman.env
@@ -0,0 +1,32 @@
+# Admin User 
+MAILMAN_ADMIN_USER=listadmin
+MAILMAN_ADMIN_EMAIL=listadmin@warpzone.ms
+
+# MTA to use 
+MTA=postfix
+
+# SMTP Host and Port 
+SMTP_HOST=smtp
+SMTP_PORT=25
+
+# External Domain for Mailman web Interface
+SERVE_FROM_DOMAIN={{ listserver }}
+
+# Mailman Secret Key 
+SECRET_KEY={{ mailman_secret_key }}
+
+# Database for mailman and Hyperkitty 
+DATABASE_URL=mysql://mailman:{{ mailman_db_pass }}@db/mailman?charset=utf8mb4
+
+# Internal hostname of the Mailman Core Container 
+MM_HOSTNAME=mailman-core
+
+# User and Password for Mailman API
+MAILMAN_REST_USER=mailman
+MAILMAN_REST_PASSWORD={{ mailman_restapi_pass }}
+
+# internal URL and API Key for Hyperkitty 
+HYPERKITTY_URL=http://mailman-web:8000/hyperkitty
+HYPERKITTY_API_KEY={{ hyperkitty_api_key }}
+
+
diff --git a/testserver/docker_mail/templates/mailu.env b/testserver/docker_mail/templates/mailu.env
new file mode 100644
index 0000000000000000000000000000000000000000..208d611ee04c26ba56a5dddb9dbf4fdf3414e61d
--- /dev/null
+++ b/testserver/docker_mail/templates/mailu.env
@@ -0,0 +1,181 @@
+###################################
+# Additional Setings 
+###################################
+
+# Set Version 
+MAILU_VERSION=2.0.37
+
+# enable IPv6
+SUBNET6=fd00:dead:beef:25::/64
+
+# Autocreate Admin User 
+INITIAL_ADMIN_ACCOUNT=mailadmin
+INITIAL_ADMIN_DOMAIN={{ domain }}
+INITIAL_ADMIN_PW={{ mailu_admin_pass }}
+INITIAL_ADMIN_MODE=ifmissing
+
+# force internel connect to rspamd with ipv4
+ANTISPAM_ADDRESS=192.168.203.253
+
+# Use Mysql as Database
+SQLALCHEMY_DATABASE_URI=mysql+mysqlconnector://mailu:{{ mailu_db_pass }}@db/mailu
+
+# Use Mysql as Database
+SQLALCHEMY_DATABASE_URI_ROUNDCUBE=mysql://roundcube:{{ roundcube_db_pass }}@db/roundcube
+
+###################################
+# Common configuration variables
+###################################
+
+# Set to a randomly generated 16 bytes string
+SECRET_KEY={{ mailu_secret_key }}
+
+# Subnet of the docker network. This should not conflict with any networks to which your system is connected. (Internal and external!)
+SUBNET=192.168.203.0/24
+
+# Main mail domain
+DOMAIN={{ domain }}
+
+# Hostnames for this server, separated with comas
+HOSTNAMES={{ mailserver }}
+
+# Postmaster local part (will append the main mail domain)
+POSTMASTER=admin
+
+# Choose how secure connections will behave (value: letsencrypt, cert, notls, mail, mail-letsencrypt)
+TLS_FLAVOR=mail
+
+# Authentication rate limit per IP (per /24 on ipv4 and /48 on ipv6)
+AUTH_RATELIMIT_IP=60/hour
+
+# Authentication rate limit per user (regardless of the source-IP)
+AUTH_RATELIMIT_USER=100/day
+
+# Opt-out of statistics, replace with "True" to opt out
+DISABLE_STATISTICS=True
+
+###################################
+# Optional features
+###################################
+
+# Expose the admin interface (value: true, false)
+ADMIN=true
+
+# Choose which webmail to run if any (values: roundcube, snappymail, none)
+WEBMAIL=roundcube
+
+# Expose the API interface (value: true, false)
+API=false
+
+# Dav server implementation (value: radicale, none)
+WEBDAV=none
+
+# Antivirus solution (value: clamav, none)
+ANTIVIRUS=none
+
+# Scan Macros solution (value: true, false)
+SCAN_MACROS=true
+
+###################################
+# Mail settings
+###################################
+
+# Message size limit in bytes
+# Default: accept messages up to 50MB
+# Max attachment size will be 33% smaller
+MESSAGE_SIZE_LIMIT=50000000
+
+# Message rate limit (per user)
+MESSAGE_RATELIMIT=200/day
+
+# Networks granted relay permissions
+# Use this with care, all hosts in this networks will be able to send mail without authentication!
+RELAYNETS=
+
+# Will relay all outgoing mails if configured
+RELAYHOST=
+
+# Enable fetchmail
+FETCHMAIL_ENABLED=False
+
+# Fetchmail delay
+FETCHMAIL_DELAY=600
+
+# Recipient delimiter, character used to delimiter localpart from custom address part
+# must be set to + for mailman
+RECIPIENT_DELIMITER=+
+
+# DMARC rua and ruf email
+DMARC_RUA=admin
+DMARC_RUF=admin
+
+# Welcome email, enable and set a topic and body if you wish to send welcome
+# emails to all users.
+WELCOME=false
+WELCOME_SUBJECT=Welcome to your new email account
+WELCOME_BODY=Welcome to your new email account, if you can read this, then it is configured properly!
+
+# Maildir Compression
+# choose compression-method, default: none (value: gz, bz2)
+COMPRESSION=
+# change compression-level, default: 6 (value: 1-9)
+COMPRESSION_LEVEL=
+
+# IMAP full-text search is enabled by default. Set the following variable to off in order to disable the feature.
+FULL_TEXT_SEARCH=on
+
+###################################
+# Web settings
+###################################
+
+# Path to redirect / to
+WEBROOT_REDIRECT=/webmail
+
+# Path to the admin interface if enabled
+WEB_ADMIN=/admin
+
+# Path to the webmail if enabled
+WEB_WEBMAIL=/webmail
+
+# Path to the API interface if enabled
+WEB_API=
+
+# Website name
+SITENAME=warpzone mail
+
+# Linked Website URL
+WEBSITE=https://listserver.{{ domain }}
+
+
+
+###################################
+# Advanced settings
+###################################
+
+# Docker-compose project name, this will prepended to containers names.
+COMPOSE_PROJECT_NAME=mailu
+
+# Number of rounds used by the password hashing scheme
+CREDENTIAL_ROUNDS=12
+
+# Header to take the real ip from
+REAL_IP_HEADER=X-Real-Ip
+
+# IPs for nginx set_real_ip_from (CIDR list separated by commas)
+REAL_IP_FROM=0.0.0.0/0
+
+# choose wether mailu bounces (no) or rejects (yes) mail when recipient is unknown (value: yes, no)
+REJECT_UNLISTED_RECIPIENT=
+
+# Log level threshold in start.py (value: CRITICAL, ERROR, WARNING, INFO, DEBUG, NOTSET)
+LOG_LEVEL=WARNING
+
+# Timezone for the Mailu containers. See this link for all possible values https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
+TZ=Europe/Berlin
+
+# Default spam threshold used for new users
+DEFAULT_SPAM_THRESHOLD=80
+
+# API token required for authenticating to the RESTful API.
+# This is a mandatory setting for using the RESTful API.
+API_TOKEN={{ mailu_api_token }}
diff --git a/testserver/docker_mail/templates/mailu/overrides/postfix/postfix.cf b/testserver/docker_mail/templates/mailu/overrides/postfix/postfix.cf
new file mode 100644
index 0000000000000000000000000000000000000000..7c0123e79805c85732436ebb7c34c66ec48de90c
--- /dev/null
+++ b/testserver/docker_mail/templates/mailu/overrides/postfix/postfix.cf
@@ -0,0 +1,14 @@
+
+# Overrides for mailman3 integration 
+# see https://patrick.georgi.family/2019/01/12/combining-mailman-3-with-mailu/
+
+always_add_missing_headers = yes
+append_at_myorigin=no
+append_dot_mydomain=no
+local_header_rewrite_clients = permit_sasl_authenticated
+owner_request_special = no
+unknown_local_recipient_reject_code = 550
+
+local_recipient_maps = regexp:/opt/mailman/postfix_lmtp
+transport_maps = regexp:/opt/mailman/postfix_lmtp, lmdb:/etc/postfix/transport.map, \${podop}transport
+virtual_mailbox_maps = regexp:/opt/mailman/postfix_lmtp, \${podop}mailbox
diff --git a/testserver/docker_mail/templates/mailu/overrides/postfix/transport.map b/testserver/docker_mail/templates/mailu/overrides/postfix/transport.map
new file mode 100644
index 0000000000000000000000000000000000000000..80a3d9e5e568fa2a380ebef229108794d66574f2
--- /dev/null
+++ b/testserver/docker_mail/templates/mailu/overrides/postfix/transport.map
@@ -0,0 +1,9 @@
+yahoo.com	polite:
+hotmail.com	polite:
+outlook.com	polite:
+exchange.com	polite:
+microsoft.com	polite:
+1und1.de	polite:
+t-online.de	polite:
+web.de		polite:
+gmail.com	polite:
diff --git a/testserver/docker_traefik/tasks/certificate.yml b/testserver/docker_traefik/tasks/certificate.yml
new file mode 100644
index 0000000000000000000000000000000000000000..599d43c64fab3d9228d0e0ffa672beca36b41d08
--- /dev/null
+++ b/testserver/docker_traefik/tasks/certificate.yml
@@ -0,0 +1,98 @@
+
+# Eigene CA und Server Zertifikat erstellen, falls diese noch nicht existiert   
+
+- name: "Install Packages"
+  apt:
+    name: "{{ packages }}"
+    state: present
+  vars:
+    packages:
+      - python3-cryptography
+
+
+- name: "Check if SelfSigned CA key exists"
+  stat:
+    path: "{{ basedir }}/ca.key"
+  register: ca_key_stat_result
+
+- name: "Create SelfSigned CA key"
+  community.crypto.openssl_privatekey:
+    path: "{{ basedir }}/ca.key"
+  when: not ca_key_stat_result.stat.exists
+
+- name: "Check if SelfSigned CA cert exists"
+  stat:
+    path: "{{ basedir }}/ca.pem"
+  register: ca_cert_stat_result
+
+- name: "Check if SelfSigned CA cert CSR"
+  community.crypto.openssl_csr_pipe:
+    privatekey_path: "{{ basedir }}/ca.key"
+    common_name: "{{ selfSignedCN }} CA"
+    use_common_name_for_san: false  # since we do not specify SANs, don't use CN as a SAN
+    basic_constraints:
+      - 'CA:TRUE'
+    basic_constraints_critical: true
+    key_usage:
+      - keyCertSign
+    key_usage_critical: true
+  register: ca_csr
+  when: not ca_cert_stat_result.stat.exists
+
+- name: "Create SelfSigned CA cert from CSR"
+  community.crypto.x509_certificate:
+    path: "{{ basedir }}/ca.pem"
+    csr_content: "{{ ca_csr.csr }}"
+    privatekey_path: "{{ basedir }}/ca.key"
+    provider: selfsigned
+  when: not ca_cert_stat_result.stat.exists
+
+
+- name: "Check if ServerCert key exists"
+  stat:
+    path: "{{ basedir }}/cert.key"
+  register: cert_key_stat_result
+
+- name: "Create ServerCert key"
+  community.crypto.openssl_privatekey:
+    path: "{{ basedir }}/cert.key"
+  when: not cert_key_stat_result.stat.exists
+
+- name: "Check if ServerCert cert exists"
+  stat:
+    path: "{{ basedir }}/cert.pem"
+  register: cert_cert_stat_result
+
+- name: "Create ServerCert CSR"
+  community.crypto.openssl_csr_pipe:
+    privatekey_path: "{{ basedir }}/cert.key"
+    subject_alt_name:
+      - "DNS:{{ selfSignedDomain }}"
+      - "DNS:{{ domain }}"
+  register: cert_csr
+  when: not cert_cert_stat_result.stat.exists
+
+- name: "Create ServerCert from CSR"
+  community.crypto.x509_certificate_pipe:
+    csr_content: "{{ cert_csr.csr }}"
+    provider: ownca
+    ownca_path: "{{ basedir }}/ca.pem"
+    ownca_privatekey_path: "{{ basedir }}/ca.key"
+    ownca_not_after: +9999d  # long lifetime 
+    ownca_not_before: "-1d"  # valid since yesterday
+  register: cert 
+  when: not cert_cert_stat_result.stat.exists
+
+- name: "Create ServerCert chain"
+  community.crypto.certificate_complete_chain:
+    input_chain: "{{ cert.certificate  }}"
+    root_certificates:
+    - "{{ basedir }}/ca.pem"
+  register: cert_chain
+  when: not cert_cert_stat_result.stat.exists
+
+- name: "Create ServerCert chain"
+  copy:
+    dest: "{{ basedir }}/cert.pem"
+    content: "{{ ''.join(cert_chain.complete_chain) }}"
+  when: not cert_cert_stat_result.stat.exists
diff --git a/testserver/docker_traefik/tasks/main.yml b/testserver/docker_traefik/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..54b26f8b8ee7a38f8965c45229d0f8514931a5ab
--- /dev/null
+++ b/testserver/docker_traefik/tasks/main.yml
@@ -0,0 +1,63 @@
+
+- include_tasks: ../functions/get_secret.yml
+  with_items:
+    - { path: "{{ basedir }}/letsencrypt_notification_email",  length: -1 }
+  when: selfSignedCN is not defined 
+
+- name: "create folder struct for {{ servicename }}"
+  file:
+    path: "{{ item }}"
+    state: "directory"
+  with_items:
+    - "{{ basedir }}"
+    - "{{ basedir }}/dynamic"
+
+- name: "Check if CertStore exists"
+  stat:
+    path: "{{ basedir }}/acme.json"
+  register: acme_stat_result
+
+- name: "Create CertStore if needed and set permissions"
+  file:
+    path: "{{ basedir }}/acme.json"
+    owner: root
+    group: root
+    mode: '600'
+    state: touch
+  when: not acme_stat_result.stat.exists
+
+- name: "Create SelfSigned CA and Cert"
+  ansible.builtin.include_tasks: certificate.yml
+  when: selfSignedCN is defined 
+  
+
+- name: Docker Compose Konfig-Datei erstellen
+  template:
+    src: "{{ item }}"
+    dest: "{{ basedir }}/{{ item }}"
+  with_items:
+    - docker-compose.yml
+    - traefik.yml
+    - dynamic/tls.yml
+  register: config
+
+- name: redirect-default ersstellen, wenn domain_default definiert ist
+  template:
+    src: "{{ item }}"
+    dest: "{{ basedir }}/{{ item }}"
+  with_items:
+    - dynamic/redirect-default.yml
+  when: domain_default is defined
+  register: config
+
+- name: "stop {{ servicename}} docker"
+  community.docker.docker_compose_v2:
+    project_src: "{{ basedir }}"
+    state: absent
+  when: config.changed
+
+- name: "start {{ servicename}} docker"
+  community.docker.docker_compose_v2:
+    project_src: "{{ basedir }}"
+    state: present
+    
diff --git a/testserver/docker_traefik/templates/docker-compose.yml b/testserver/docker_traefik/templates/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..51b6d70811177a7b3ac36a67c52535a641b26508
--- /dev/null
+++ b/testserver/docker_traefik/templates/docker-compose.yml
@@ -0,0 +1,53 @@
+version: '2.4'
+
+services:
+
+    app:
+        image: traefik:3.0
+        restart: always
+        ports:
+            - "80:80"
+            - "443:443"
+{% if matrix_federation is defined and matrix_federation == true %}            - "8448:8448"
+{% endif %}
+            - "{{ int_ip4 }}:8081:8080"
+        volumes:
+            - "/srv/traefik/traefik.yml:/etc/traefik/traefik.yml:ro"
+            - "/srv/traefik/dynamic:/etc/traefik/dynamic:ro"
+            - "/srv/traefik/acme.json:/acme.json"
+            - "/var/run/docker.sock:/var/run/docker.sock"
+{% if selfSignedCN is defined %}
+            - "{{ basedir }}/cert.pem:/cert.pem:ro"
+            - "{{ basedir }}/cert.key:/cert.key:ro"
+{% endif %}
+        networks:
+            - default
+            - web
+        healthcheck:
+            test: ['CMD', 'traefik', 'healthcheck']
+            interval: 30s
+            timeout: 10s
+            retries: 3
+
+# for debugging only
+#    whoami:
+#        image: containous/whoami
+#        labels:
+#            - traefik.enable=true
+#            - traefik.http.routers.{{ servicename }}.rule=Host(`{ domain }`)
+#            - traefik.http.routers.{{ servicename }}.entrypoints=websecure
+#            - traefik.http.services.{{ servicename }}.loadbalancer.server.port=80
+#        networks:
+#            - web
+
+networks:
+  web:
+    external: true
+  default:
+    driver: bridge
+    enable_ipv6: true
+    ipam:
+      driver: default
+      config:
+        # must be a ULA range
+        - subnet: fd00:dead:beef:80::/64
diff --git a/testserver/docker_traefik/templates/dynamic/redirect-default.yml b/testserver/docker_traefik/templates/dynamic/redirect-default.yml
new file mode 100644
index 0000000000000000000000000000000000000000..c196f5253ff07ef89bf00db022e7fe416081fe4c
--- /dev/null
+++ b/testserver/docker_traefik/templates/dynamic/redirect-default.yml
@@ -0,0 +1,22 @@
+http:
+    routers:
+        router-default:
+            entrypoints:
+                - websecure
+            rule: "Host(`{{ domain }}`)"
+            middlewares: 
+                - redirect-default
+            service: service-default
+
+    services:
+        service-default:
+            loadBalancer:
+                servers: 
+                    - url: http://noop-dummy
+                            
+    middlewares:
+        redirect-default:
+            redirectRegex:
+                regex: "^https://{{ domain }}/(.*)"
+                replacement: "https://{{ domain_default }}/$1"
+
diff --git a/testserver/docker_traefik/templates/dynamic/tls.yml b/testserver/docker_traefik/templates/dynamic/tls.yml
new file mode 100644
index 0000000000000000000000000000000000000000..0909bb1f47c3e55aa47b46aec72a3e4f9dbca74d
--- /dev/null
+++ b/testserver/docker_traefik/templates/dynamic/tls.yml
@@ -0,0 +1,28 @@
+
+# TLS Options 
+tls:
+
+{% if selfSignedCN is defined %}
+
+    # use local certificate 
+    certificates:
+        - certFile: "/cert.pem"
+          keyFile: "/cert.key"
+
+{% endif %}
+
+    options:
+        default:
+            sniStrict: true
+            minVersion: "VersionTLS12"
+            curvePreferences:
+                - "secp521r1"
+                - "secp384r1"
+            cipherSuites:
+                - "TLS_AES_128_GCM_SHA256"
+                - "TLS_AES_256_GCM_SHA384"
+                - "TLS_CHACHA20_POLY1305_SHA256"
+                - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
+                - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
+                - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
+
diff --git a/testserver/docker_traefik/templates/traefik.yml b/testserver/docker_traefik/templates/traefik.yml
new file mode 100644
index 0000000000000000000000000000000000000000..f96aa28efd39719a39e535b1b9244189693bb7db
--- /dev/null
+++ b/testserver/docker_traefik/templates/traefik.yml
@@ -0,0 +1,86 @@
+
+# Global settings
+global:
+    checkNewVersion: true
+
+    
+# Entrypoints 
+entryPoints:
+
+    # HTTP, redirect all to HTTPS
+    web:
+        address: ":80"
+        http:
+            redirections:
+                entryPoint:
+                    to: "websecure"
+                    scheme: "https"
+                    permanent: true   
+
+    # HTTPS, get certificates from letsencrypt
+    websecure:
+        address: ":443"
+        http:
+            tls:
+                certResolver: "letsencrypt"
+
+
+{% if matrix_federation is defined and matrix_federation == true %}
+
+    # additional entrypoint for matrix-federation 
+    matrix_federation:
+        address: ":8448"
+        http:
+            tls:
+                certResolver: "letsencrypt"
+
+{% endif %}
+
+# Discover configuration via docker 
+# use network 'web' for interconnect  
+providers:
+    docker:
+        watch: true
+        endpoint: "unix:///var/run/docker.sock"
+        network: "web"
+        exposedByDefault: false
+    file:
+        directory: "/etc/traefik/dynamic"
+        watch: true
+
+
+# Traefik API and dashboard 
+api:
+    insecure: true
+    dashboard: true
+    debug: false
+
+
+# Enable Ping endpoint for docker healthcheck 
+ping: {}
+
+
+# Enable prometheus metrics
+metrics: 
+    prometheus: 
+        addEntryPointsLabels: true 
+        addServicesLabels: true 
+
+
+# Logging 
+log:
+    level: "INFO"
+    format: "common"
+
+
+{% if selfSignedCN is not defined %}
+
+# get certificates from letsEncrypt 
+certificatesResolvers:
+    letsencrypt:
+        acme:
+            email: "{{ letsencrypt_notification_email }}"
+            storage: "/acme.json"
+            tlsChallenge: true
+
+{% endif %}
diff --git a/testserver/docker_uffd/tasks/main.yml b/testserver/docker_uffd/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..01a9118198ca53edadbc7d7cfdac5bd085fd43fa
--- /dev/null
+++ b/testserver/docker_uffd/tasks/main.yml
@@ -0,0 +1,40 @@
+---
+
+- include_tasks: ../functions/get_secret.yml
+  with_items:
+    - { path: "{{ basedir }}/secrets/mysql_admin_pass",  length: 24 }
+    - { path: "{{ basedir }}/secrets/mysql_user_pass",  length: 24 }
+    - { path: "{{ basedir }}/secrets/uffd_admin_pass",  length: 24 }
+    - { path: "{{ basedir }}/secrets/uffd_secret_key",  length: 64 }
+    - { path: "{{ basedir }}/secrets/uffd_mail_pass",   length: 12 }
+
+- name: create folder struct for {{servicename}}
+  file: 
+    path: "{{ item }}"
+    state: "directory"
+  with_items:
+    - "{{ basedir }}"
+    - "{{ basedir }}/secrets"
+    - "{{ basedir }}/db/"   
+
+- name: create config files
+  template: 
+    src: "{{ item }}" 
+    dest: "{{ basedir }}/{{ item }}"
+  with_items:
+    - "Dockerfile"
+    - "entrypoint.sh"
+    - "docker-compose.yml"
+    - "uffd.cfg"
+  register: config
+
+- name: stop {{ servicename }} docker
+  community.docker.docker_compose_v2:
+    project_src: "{{ basedir }}"
+    state: absent
+  when: config.changed
+
+- name: start {{servicename}} docker
+  community.docker.docker_compose_v2:
+    project_src: "{{ basedir }}"
+    state: present
diff --git a/testserver/docker_uffd/templates/Dockerfile b/testserver/docker_uffd/templates/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..36bcfcdf9da7cbc35a60ac5829af5ff540e3dad1
--- /dev/null
+++ b/testserver/docker_uffd/templates/Dockerfile
@@ -0,0 +1,77 @@
+FROM debian:bookworm AS build-stage
+
+ENV DEBIAN_FRONTEND=noninteractive
+ENV PYBUILD_INSTALL_ARGS="--install-lib=/usr/share/uffd/ --install-scripts=/usr/share/uffd/"
+ENV PACKAGE_VERSION=v2.3.1.r21
+
+RUN set -x && \
+    apt update && \
+    apt install -y --no-install-recommends \
+        lsb-release \
+        curl \
+        ca-certificates \
+        locales-all \
+        git \
+        python3 \
+        python3-venv \
+        python3-coverage \
+        python3-ldap3 \
+        python3-flask \
+        python3-flask-sqlalchemy \
+        python3-flask-migrate \
+        python3-pip \
+        python3-qrcode \
+        python3-fido2 \
+        python3-oauthlib \
+        python3-flask-babel \
+        python3-argon2 \
+        python3-pytest \
+        python3-all \
+        python3-pip \
+        git-buildpackage \
+        debhelper \
+        build-essential \
+        dh-python \
+        python3-mysqldb \
+        python3-requests-oauthlib \
+        python3-git \
+        python3-prometheus-client \
+        libffi-dev \
+        python3-build \
+        twine && \
+    apt -qq clean
+
+RUN git clone https://git.cccv.de/uffd/uffd.git
+WORKDIR /uffd
+RUN git checkout 3f41d2fb7f686c12a1f09577e5b96da89ff46e07
+
+RUN set -x && \
+    ./debian/create_changelog.py uffd > debian/changelog && \
+    dpkg-buildpackage -us -uc && \
+    dpkg-deb -I /*.deb && \
+    dpkg-deb -c /*.deb && \
+    mv /*.deb /uffd/uffd.deb
+
+FROM debian:bookworm as app-stage
+
+COPY --from=build-stage /uffd/uffd.deb /uffd.deb
+
+RUN set -x && \
+    apt update && \
+    apt install -y --no-install-recommends /uffd.deb python3-psycopg2 python3-pymysql && \
+    rm -rf /var/lib/apt/lists/* && \
+    rm /uffd.deb && \
+    cat /etc/uffd/uffd.cfg | grep -v "SECRET_KEY=" > /etc/uffd/uffd.cfg.tmp && \
+    mv /etc/uffd/uffd.cfg.tmp /etc/uffd/uffd.cfg && \
+    mkdir --parents /var/www/uffd && \
+    chown root:uffd /var/www/uffd
+
+COPY entrypoint.sh /entrypoint.sh
+
+USER uffd
+USER root
+
+EXPOSE 3031/tcp
+EXPOSE 9191/tcp
+
+CMD bash /entrypoint.sh
diff --git a/testserver/docker_uffd/templates/docker-compose.yml b/testserver/docker_uffd/templates/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b6cd606f978733398ab149dc575c95844bdbd578
--- /dev/null
+++ b/testserver/docker_uffd/templates/docker-compose.yml
@@ -0,0 +1,42 @@
+version: "3"
+
+services:
+  db:
+    image: mariadb:11.2.2
+    restart: always
+    command: ['mariadbd', '--character-set-server=utf8mb4', '--collation-server=utf8mb4_nopad_bin']
+    volumes:
+      - "{{ basedir }}/db/:/var/lib/mysql"
+    environment:
+      MYSQL_ROOT_PASSWORD: "{{ mysql_admin_pass }}"
+      MYSQL_PASSWORD: "{{ mysql_user_pass }}"
+      MYSQL_DATABASE: "uffd"
+      MYSQL_USER: "uffd"
+    networks:
+        - default
+  app:
+    build: .
+    image: uffd:v2.3.1.r21
+    restart: always
+    depends_on:
+      - db
+    volumes:
+      - "{{ basedir }}/uffd.cfg/:/etc/uffd/uffd.cfg"
+    environment:
+      TZ: "Europe/Berlin"
+      UFFD_INITIAL_ADMIN_USER: "uffdadmin"
+      UFFD_INITIAL_ADMIN_PW: "{{ uffd_admin_pass }}"
+      UFFD_INITIAL_ADMIN_MAIL: "uffdadmin@jabertwo.de"
+    labels:
+      - com.centurylinklabs.watchtower.enable=false
+      - traefik.enable=true
+      - traefik.http.routers.{{ servicename }}.rule=Host(`{{ domain }}`)
+      - traefik.http.routers.{{ servicename }}.entrypoints=websecure
+      - traefik.http.services.{{ servicename }}.loadbalancer.server.port=3031
+    networks:
+        - default
+        - web
+
+networks:
+  web:
+    external: true
diff --git a/testserver/docker_uffd/templates/entrypoint.sh b/testserver/docker_uffd/templates/entrypoint.sh
new file mode 100644
index 0000000000000000000000000000000000000000..81e92a9a3dfe9dc88c6bf999678b0a48bb37b26f
--- /dev/null
+++ b/testserver/docker_uffd/templates/entrypoint.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+# Modded to Dockerfile
+#echo "Copying static files ..."
+#cp -r /usr/share/uffd/uffd/static /var/www/uffd
+
+db_ready="false"
+count=0
+while [ $count -lt 32 ] && [ "$db_ready" != "true" ] ;do
+  if uffd-admin db current >> /dev/null 2>&1 ;then
+    db_ready="true"
+  else
+    echo "Waiting for db to become ready..."
+    ((duration=2**$count))
+    sleep $duration
+    ((count=$count+1))
+  fi
+done
+
+if [ "$db_ready" == "true" ] ;then
+  echo "Running datbase migrations ..."
+  uffd-admin db upgrade
+
+  if [ -n "$UFFD_INITIAL_ADMIN_PW" ] && [ "$(uffd-admin user list)" == "" ]; then
+    echo "Creating groups and roles for initial admin user ..."
+    if ! uffd-admin group show 'uffd_admin' >> /dev/null 2>&1 ;then
+      uffd-admin group create 'uffd_admin' --description 'Admin access to uffd'
+    fi
+    if ! uffd-admin group show 'uffd_access' >> /dev/null 2>&1 ;then
+      uffd-admin group create 'uffd_access' --description 'Access to Single-Sign-On and Selfservice'
+    fi
+    if ! uffd-admin role show 'uffd_admin' >> /dev/null 2>&1 ;then
+      uffd-admin role create 'uffd_admin' --add-group 'uffd_admin' --add-group 'uffd_access'
+    fi
+    if [ -z "$UFFD_INITIAL_ADMIN_USER" ] ;then
+      UFFD_INITIAL_ADMIN_USER='uffd_admin'
+    fi
+    if [ -z "$UFFD_INITIAL_ADMIN_MAIL" ] ;then
+      UFFD_INITIAL_ADMIN_MAIL='uffd_admin@localhost'
+    fi
+    echo "Creating initial admin user ..."
+    uffd-admin user create "$UFFD_INITIAL_ADMIN_USER" --password "$UFFD_INITIAL_ADMIN_PW" --mail "$UFFD_INITIAL_ADMIN_MAIL" --displayname 'uffd Admin' --add-role 'uffd_admin'
+  fi
+else
+  echo "WARNING: Database is not ready yet, skipping migration and initialization"
+fi
+
+echo "Starting server ..."
+runuser --preserve-environment -u uffd -- \
+  uwsgi --ini /etc/uwsgi/apps-enabled/uffd.ini --http-socket 0.0.0.0:3031 --master --stats 0.0.0.0:9191
diff --git a/testserver/docker_uffd/templates/uffd.cfg b/testserver/docker_uffd/templates/uffd.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..6de25a93f469c5b409298f14cac77d15e4f84b8f
--- /dev/null
+++ b/testserver/docker_uffd/templates/uffd.cfg
@@ -0,0 +1,123 @@
+
+LANGUAGES={
+	# Language identifier (see Accept-Language HTTP header) -> Display Name
+	"en": "EN",
+	"de": "DE",
+}
+
+# Uffd Admins Group
+ACL_ADMIN_GROUP="uffd_admin"
+# Group required to access selfservice functions (view selfservice, change profile/password/roles)
+ACL_SELFSERVICE_GROUP="uffd_access"
+# Group required to login
+ACL_ACCESS_GROUP="uffd_access"
+# Members can create invite links for signup
+ACL_SIGNUP_GROUP="uffd_signup"
+
+MAIL_SERVER='mail.test-warpzone.de' 
+MAIL_PORT=587
+MAIL_USERNAME='noreply-uffd@test-warpzone.de' 
+MAIL_PASSWORD='{{ uffd_mail_pass }}'
+MAIL_USE_STARTTLS=True
+MAIL_FROM_ADDRESS='noreply-uffd@test-warpzone.de'
+
+# Do not enable this on a public service! There is no spam protection implemented at the moment.
+SELF_SIGNUP=False
+
+# Max Lifetime for invites
+INVITE_MAX_VALID_DAYS=21
+
+# Blocked Loginnames
+LOGINNAME_BLOCKLIST=['^admin$', '^root$']
+
+#MFA_ICON_URL = 'https://example.com/logo.png'
+#MFA_RP_ID = 'example.com' # If unset, hostname from current request is used
+MFA_RP_NAME = 'Uffd Test Service' # Service name passed to U2F/FIDO2 authenticators
+
+
+FOOTER_LINKS=[{"url": "https://example.com", "title": "example"}]
+
+# The default page after login or clicking the top left home button is the self-service
+# page. If you would like it to be the services list instead, set this to True.
+DEFAULT_PAGE_SERVICES=True
+
+# Service overview page (disabled if empty)
+SERVICES=[
+#	# Title is mandatory, all other fields are optional.
+#	# For permission_levels/groups/infos/links all fields are mandatory aside from required_group.
+#	{
+#		'title': 'Service Title',
+#		'subtitle': 'Service Subtitle',
+#		'description': 'Short description of the service as plain text',
+#		'url': 'https://example.com/',
+#		'logo_url': 'https://example.com/logo.png',
+#		# Basic access group name, service is accessible to everyone if empty
+#		'required_group': 'users',
+#		# Non-basic permission levels, the last matching entry is selected.
+#		# Users with a matching permission level are considered to have
+#		# access to the service (as if they have the basic access group).
+#		'permission_levels': [
+#			{'name': 'Moderator', 'required_group': 'moderators'},
+#			{'name': 'Admin', 'required_group': 'uffd_admin'},
+#		],
+#		# Per default all services are listed publicly (but grayed out for
+#		# guests/users without access). Confidential services are only visible
+#		# to users with access rights to the service.
+#		'confidential': True,
+#		# In-service groups, all matching items are visible
+#		'groups': [
+#			{'name': 'Group "crew_crew"', 'required_group': 'users'},
+#			{'name': 'Group "crew_logistik"', 'required_group': 'uffd_admin'},
+#		],
+#		# Infos are small/medium amounts of information displayed in a modal
+#		# dialog. All matching items are visible.
+#		'infos': [
+#			{
+#				'title': 'uffd',
+#				'button_text': 'Documentation', # Defaults to the title if not set
+#				'html': '<p>Some information about the service as html</p>',
+#				'required_group': 'users',
+#			},
+#		],
+#		# Links to external sites, all matching items are visible
+#		'links': [
+#			{'title': 'Link to an external site', 'url': '#', 'required_group': 'users'},
+#		]
+#	},
+
+    {
+		'title': 'Icinga',
+		'url': 'https://icinga.test-warpzone.de',
+		'logo_url': 'https://icinga.test-warpzone.de/icingaweb2/img/favicon.png'
+    }
+
+]
+
+# A banner text that will be displayed above the services list
+SERVICES_BANNER='Available Services'
+
+# If the banner should be shown to users who are not logged in
+SERVICES_BANNER_PUBLIC=False
+
+# Enable the service overview page for users who are not logged in
+SERVICES_PUBLIC=False
+
+# An optional banner that will be displayed above the login form
+LOGIN_BANNER='Always check the URL. Never enter your SSO password on any other site.'
+
+BRANDING_LOGO_URL='/static/empty.png'
+SITE_TITLE='uffd @ test-warpzone.de'
+
+# Name and contact mail address are displayed to users in a few places (plain text only!)
+ORGANISATION_NAME='test-warpzone.de'
+ORGANISATION_CONTACT='uffd@test-warpzone.de'
+
+# Optional text included in account registration mails (plain text only!)
+WELCOME_TEXT='See https://docs.example.com/ for further information.'
+
+
+# DO set in production
+FLASK_ENV="production"
+SQLALCHEMY_DATABASE_URI="mysql+pymysql://uffd:{{ mysql_user_pass }}@db/uffd?charset=utf8mb4"
+SECRET_KEY="{{ uffd_secret_key }}"
+DEBUG=False
diff --git a/verwaltung/docker_gitea/tasks/main.yml b/verwaltung/docker_gitea/tasks/main.yml
index 749217442187e097b288ffb01561f5883e5ffa46..780d091904ca60070506a546a3723c85bfe174f4 100644
--- a/verwaltung/docker_gitea/tasks/main.yml
+++ b/verwaltung/docker_gitea/tasks/main.yml
@@ -1,6 +1,6 @@
 ---
 # Get secrets 
-- include: ../functions/get_secret.yml
+- include_tasks: ../functions/get_secret.yml
   with_items:
     - { path: /srv/gitea/mysql_root_pw, length: 24 }
     - { path: /srv/gitea/mysql_user_pw, length: 12 }
@@ -23,7 +23,7 @@
     - "docker-compose.yml"
 
 - name: start gitea docker
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: /srv/gitea/
     state: present
   
diff --git a/verwaltung/docker_gitea/templates/docker-compose.yml b/verwaltung/docker_gitea/templates/docker-compose.yml
index 00c6b4b424bca995bc0c76ad9df63ae3582be8a9..d1eef0b164256e3e214f10abc3f167b13f6940e4 100644
--- a/verwaltung/docker_gitea/templates/docker-compose.yml
+++ b/verwaltung/docker_gitea/templates/docker-compose.yml
@@ -4,7 +4,7 @@ version: "2.4"
 services:
 
   app:
-    image: gitea/gitea:1.17.3
+    image: gitea/gitea:1
     restart: always
     depends_on:
       - db
@@ -37,7 +37,7 @@ services:
 
 
   db:
-    image: mariadb:10.10.2
+    image: mariadb:11
     restart: always
     volumes:
       - /srv/gitea/db/:/var/lib/mysql
@@ -46,6 +46,8 @@ services:
       MYSQL_PASSWORD: "{{ mysql_user_pw }}"
       MYSQL_DATABASE: "gitea"
       MYSQL_USER: "gitea"
+      MARIADB_AUTO_UPGRADE: "1"
+      MARIADB_INITDB_SKIP_TZINFO: "1"
     networks:
       - default
 
diff --git a/verwaltung/docker_jameica/tasks/main.yml b/verwaltung/docker_jameica/tasks/main.yml
index 9f43c196b4de53871c2eed0166888b58f17619f7..f8056c7b3224cb36f7b8c352259f0683f019af4a 100644
--- a/verwaltung/docker_jameica/tasks/main.yml
+++ b/verwaltung/docker_jameica/tasks/main.yml
@@ -23,7 +23,7 @@
     - "nginx.conf"
 
 - name: start jameica docker
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: /srv/jameica-vnc/
     state: present
     
diff --git a/verwaltung/docker_jameica/templates/Dockerfile b/verwaltung/docker_jameica/templates/Dockerfile
index e90149e7ebf9a3103dc126d4a828f80213c79714..f6c0b4ac31eaa605a94a7492c0aa6172855ff3a5 100644
--- a/verwaltung/docker_jameica/templates/Dockerfile
+++ b/verwaltung/docker_jameica/templates/Dockerfile
@@ -4,7 +4,8 @@ FROM theasp/novnc:latest
 RUN set -ex; \
     apt-get update; \
     apt-get install -y \
-      openjdk-11-jre
+      openjdk-17-jre \
+      libswt-gtk-4-java
 
 COPY jameica.conf /app/conf.d/
 COPY jameica.sh  /app/
diff --git a/verwaltung/docker_jameica/templates/docker-compose.yml b/verwaltung/docker_jameica/templates/docker-compose.yml
index 4deda5f4abe7d89e50737da853cbce31e7691ee5..93f34e2e27cee2166269ea9fc09f43668b044f22 100644
--- a/verwaltung/docker_jameica/templates/docker-compose.yml
+++ b/verwaltung/docker_jameica/templates/docker-compose.yml
@@ -18,7 +18,7 @@ services:
 
 
   ldap_auth:
-    image: pinepain/ldap-auth-proxy:0.2.0
+    image: pinepain/ldap-auth-proxy:latest
     restart: always
     environment:
       LOG_LEVEL: "info"
@@ -36,7 +36,7 @@ services:
 
 
   nginx:
-    image: nginx:1.19
+    image: nginx:1
     restart: always
     depends_on:
       - vnc
diff --git a/verwaltung/docker_mysql/tasks/main.yml b/verwaltung/docker_mysql/tasks/main.yml
index d121017341e81c8107210d265fc20cee1261dc74..a6088d77fc0f20d0f701517b176145e98cc57ef7 100644
--- a/verwaltung/docker_mysql/tasks/main.yml
+++ b/verwaltung/docker_mysql/tasks/main.yml
@@ -1,6 +1,6 @@
 ---
 # Get secrets
-- include: ../functions/get_secret.yml
+- include_tasks: ../functions/get_secret.yml
   with_items:
     - { path: /srv/mysql/mysql_root_pw, length: 24 }
     - { path: /srv/mysql/mysql_user_pw, length: 12 }
diff --git a/verwaltung/docker_mysql/templates/docker-compose.yml b/verwaltung/docker_mysql/templates/docker-compose.yml
index d162e74fa74b3badc717949e331493ef2a84a201..ad2b0fdb6ca7985cb397e61bdc58e41a375f6623 100644
--- a/verwaltung/docker_mysql/templates/docker-compose.yml
+++ b/verwaltung/docker_mysql/templates/docker-compose.yml
@@ -5,7 +5,7 @@ services:
 
   app:                                                                                                                                                            
 
-    image: mariadb:10.10.2                                                                                                                                                    
+    image: mariadb:11                                                                                                                                                 
     restart: always
     ports:
       - 127.0.0.1:3306:3306                                                                                      
diff --git a/verwaltung/docker_nextcloud/tasks/main.yml b/verwaltung/docker_nextcloud/tasks/main.yml
index 69f01390563c8d93858ae4089136c98d72cdbe3c..5b51f6a926919850d0eb033529c6f11d0a5026a5 100644
--- a/verwaltung/docker_nextcloud/tasks/main.yml
+++ b/verwaltung/docker_nextcloud/tasks/main.yml
@@ -1,6 +1,6 @@
 ---
 
-- include: ../functions/get_secret.yml
+- include_tasks: ../functions/get_secret.yml
   with_items:
     - { path: /srv/nextcloud/nextcloud_admin_pass,  length: 24 }
     - { path: /srv/nextcloud/mysql_admin_pass,  length: 24 }
@@ -30,7 +30,7 @@
 
 
 - name: start nextcloud docker
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: /srv/nextcloud/
     state: present
 
diff --git a/verwaltung/docker_nextcloud/templates/docker-compose.yml b/verwaltung/docker_nextcloud/templates/docker-compose.yml
index 10dde2be78ef88ff03cf466d1d5b1c5ab15ec97b..b3ed764617be33d944a0f11383f1b99e9e7ab419 100644
--- a/verwaltung/docker_nextcloud/templates/docker-compose.yml
+++ b/verwaltung/docker_nextcloud/templates/docker-compose.yml
@@ -4,7 +4,7 @@ services:
 
   redis:
 
-    image: redis:7.0.5
+    image: redis:7-alpine
     restart: always
     networks:
       - default
@@ -12,7 +12,7 @@ services:
 
   mysql:
 
-    image: mariadb:10.10.2
+    image: mariadb:11
     restart: always
     volumes:
       - /srv/nextcloud/db/:/var/lib/mysql
@@ -27,7 +27,7 @@ services:
 
   app:
 
-    image: nextcloud:25.0.1-apache
+    image: nextcloud:28-apache
     restart: always
     volumes:
       - /srv/nextcloud/data/:/var/www/html/
@@ -42,6 +42,10 @@ services:
       MYSQL_HOST: mysql
       NEXTCLOUD_ADMIN_USER: "admin"
       NEXTCLOUD_ADMIN_PASSWORD: "{{nextcloud_admin_pass}}"
+      OVERWRITEPROTOCOL: https
+      OVERWRITECLIURL: https://{{ domain }}
+      OVERWRITEHOST: {{ domain }}
+      APPIMAGE_EXTRACT_AND_RUN: 1
     labels:
       - traefik.enable=true
       - traefik.http.routers.{{ servicename }}.rule=Host(`{{ domain }}`)
diff --git a/verwaltung/docker_vaultwarden/tasks/main.yml b/verwaltung/docker_vaultwarden/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..8d3981860e1a46af672b8909301ab918af8da708
--- /dev/null
+++ b/verwaltung/docker_vaultwarden/tasks/main.yml
@@ -0,0 +1,39 @@
+---
+
+- include_tasks: ../functions/get_secret.yml
+  with_items:
+    - { path: "{{ basedir }}/secrets/vaultwarden_admin_token", length: 40 }
+    - { path: /srv/shared/noreply_email_pass,  length: -1 }
+
+
+- name: "create folder struct for {{ servicename }}"
+  file:
+    path: "{{ item }}"
+    state: "directory"
+  with_items:
+    - "{{ basedir }}"
+    - "{{ basedir }}/secrets"
+    - "{{ basedir }}/data"
+    - "{{ basedir }}/backup"
+
+
+- name: deploy {{ servicename }} config
+  template:
+    dest:  "{{ basedir }}/{{ item }}"
+    src: "{{ item }}"
+  with_items:
+    - docker-compose.yml
+  register: config
+
+
+- name: "stop {{ servicename }} docker"
+  community.docker.docker_compose_v2:
+    project_src: "{{ basedir }}"
+    state: absent
+  when: config.changed
+
+
+- name: "start {{ servicename }} docker"
+  community.docker.docker_compose_v2:
+    project_src: "{{ basedir }}"
+    state: present
diff --git a/verwaltung/docker_vaultwarden/templates/docker-compose.yml b/verwaltung/docker_vaultwarden/templates/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..19daa0d272a9ff3aa9ac1c4f49f64d27b997d533
--- /dev/null
+++ b/verwaltung/docker_vaultwarden/templates/docker-compose.yml
@@ -0,0 +1,56 @@
+version: '3'
+
+services:
+
+  app:
+
+    image: vaultwarden/server:latest
+    restart: always
+    labels:
+      - traefik.enable=true
+      - traefik.http.routers.{{ servicename }}.rule=Host(`{{ domain }}`)
+      - traefik.http.routers.{{ servicename }}.entrypoints=websecure
+      - traefik.http.services.{{ servicename }}.loadbalancer.server.port=80
+    environment:
+      - ADMIN_TOKEN={{ vaultwarden_admin_token }}
+      - DOMAIN=https://{{ domain }}    
+      - INVITATIONS_ALLOWED=false
+      - INVITATION_ORG_NAME=warpzone
+      - LOG_LEVEL=warn
+      - SENDS_ALLOWED=true
+      - SIGNUPS_ALLOWED=false
+      - SMTP_HOST={{ smtp_host }}
+      - SMTP_FROM={{ noreply_email_user }}
+      - SMTP_PORT=587
+      - SMTP_SECURITY=starttls
+      - SMTP_USERNAME={{ noreply_email_user }}
+      - SMTP_PASSWORD={{ noreply_email_pass }}
+      - SIGNUPS_VERIFY=true
+      - SHOW_PASSWORD_HINT=false
+      - TZ=Europe/Berlin
+      - WEBSOCKET_ENABLED=false
+    volumes:
+      - {{ basedir }}/data:/data
+    networks:
+      - web
+      - default
+
+  backup:
+    image: bruceforce/vaultwarden-backup:latest
+    restart: always
+    init: true
+    depends_on:
+      - app
+    volumes:
+      - {{ basedir }}/data:/data/
+      - {{ basedir }}/backup:/backup/
+    environment:
+      - TZ=Europe/Berlin
+      - DELETE_AFTER=30
+      - TIMESTAMP=true
+      - GID=1000
+      - UID=1000
+
+networks:
+  web:
+    external: true
diff --git a/verwaltung/jameica/tasks/main.yml b/verwaltung/jameica/tasks/main.yml
index 6638dbda4eb096d67face8081c33c2f3fffb774d..f1afc4bfc9305e26b0a633189f209aece14669de 100644
--- a/verwaltung/jameica/tasks/main.yml
+++ b/verwaltung/jameica/tasks/main.yml
@@ -12,7 +12,7 @@
       - openjdk-11-jre
 
 # Get secrets 
-- include: ../functions/get_secret.yml
+- include_tasks: ../functions/get_secret.yml
   with_items:
     - { path: /srv/mysql/mysql_user_pw, length: 12 }
    
diff --git a/webserver/docker_autodiscover/templates/docker-compose.yml b/webserver/docker_autodiscover/templates/docker-compose.yml
deleted file mode 100644
index d8e72989f5e1fc28bddc68560852af46cb9159ea..0000000000000000000000000000000000000000
--- a/webserver/docker_autodiscover/templates/docker-compose.yml
+++ /dev/null
@@ -1,35 +0,0 @@
-version: '2.1'
-
-services:
-
-{% for domain in mail_domains %}
-
-  {{ domain }}:
-    image: monogramm/autodiscover-email-settings:1.4.0
-    restart: always
-    environment:
-      - DOMAIN={{ mail_domains[domain].maildomain }}
-      - IMAP_HOST={{ mail_domains[domain].mxserver }}
-      - IMAP_PORT=993
-      - IMAP_SOCKET=SSL
-      - POP_HOST={{ mail_domains[domain].mxserver }}
-      - POP_PORT=995
-      - POP_SOCKET=SSL
-      - SMTP_HOST={{ mail_domains[domain].mxserver }}
-      - SMTP_PORT=587
-      - SMTP_SOCKET=STARTTLS
-    labels:
-      - traefik.enable=true
-      - traefik.http.routers.{{ servicename }}-{{ domain }}.rule=Host(`autodiscover.{{ mail_domains[domain].maildomain }}`) || Host(`autoconfig.{{ mail_domains[domain].maildomain }}`)
-      - traefik.http.routers.{{ servicename }}-{{ domain }}.entrypoints=websecure
-      - traefik.http.services.{{ servicename }}-{{ domain }}.loadbalancer.server.port=8000
-    networks:
-      - default 
-      - web
-
-{% endfor %}
-
-networks:
-  web:
-    external: true
-
diff --git a/webserver/docker_coturn/tasks/main.yml b/webserver/docker_coturn/tasks/main.yml
index 5d6643412750f53ba44f20d44de85aa8e28bce8d..6211299701fc39b9e5a40f028bdb8248b4c5080b 100644
--- a/webserver/docker_coturn/tasks/main.yml
+++ b/webserver/docker_coturn/tasks/main.yml
@@ -21,12 +21,12 @@
   register: config
 
 - name: "stop {{servicename}} docker"
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: /srv/{{servicename}}/
     state: absent
   when: config.changed
 
 - name: "start {{servicename}} docker"
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: /srv/{{servicename}}/
     state: present
diff --git a/webserver/docker_coturn/templates/docker-compose.yml b/webserver/docker_coturn/templates/docker-compose.yml
index b0091990ed2a273909919a3f7170cd76ca7eae76..20e56a3735a87ee2140fa52f14fc84fe0fc0a4eb 100644
--- a/webserver/docker_coturn/templates/docker-compose.yml
+++ b/webserver/docker_coturn/templates/docker-compose.yml
@@ -3,7 +3,7 @@ version: "3"
 services:
 
   coturn:
-    image: coturn/coturn:4.5.2
+    image: coturn/coturn:latest
     restart: always
     command:
       - turnserver
diff --git a/webserver/docker_dokuwiki/tasks/main.yml b/webserver/docker_dokuwiki/tasks/main.yml
index 698b075e65f38595767c284a913f4b324ae06a35..e392551aee68a32748f1ac5176592d74ec2fbf99 100644
--- a/webserver/docker_dokuwiki/tasks/main.yml
+++ b/webserver/docker_dokuwiki/tasks/main.yml
@@ -9,29 +9,36 @@
     path: "{{item}}"
     state: "directory"
   with_items:
-    - /srv/dokuwiki/
-    - /srv/dokuwiki/data
-    - /srv/dokuwiki/pdftemplate
+    - "{{ basedir }}"
+    - "{{ basedir }}/data"
+    - "{{ basedir }}/pdftemplate"
 
 - name: Docker Compose Konfig-Datei erstellen
   template:
     src: "{{item}}"
-    dest: "/srv/dokuwiki/{{item}}"
+    dest: "{{ basedir }}/{{item}}"
   with_items:
     - docker-compose.yml
     - Dockerfile
     - sendmail_plenum.py
+  register: config
 
-- name: start dokuwiki docker
-  docker_compose:
-    project_src: /srv/dokuwiki/
-    state: present
-
-- name: Cronjob für Mailversand Plenumsmail (disbled until proper fix)
+- name: Cronjob für Mailversand Plenumsmail
   cron: 
     name: "sendmail_plenum" 
     weekday: "0" 
     hour: "20" 
     minute: "0" 
-    job: "/usr/bin/python3 /srv/dokuwiki/sendmail_plenum.py"
+    job: "/usr/bin/python3 {{ basedir }}/sendmail_plenum.py"
     disabled: false
+
+- name: "stop {{ servicename}} docker"
+  community.docker.docker_compose_v2:
+    project_src: "{{ basedir }}"
+    state: absent
+  when: config.changed
+
+- name: "start {{ servicename}} docker"
+  community.docker.docker_compose_v2:
+    project_src: "{{ basedir }}"
+    state: present
diff --git a/webserver/docker_dokuwiki/templates/Dockerfile b/webserver/docker_dokuwiki/templates/Dockerfile
index 7af4c0dba2c0bf2df629b20652aaf932579f6b23..fd13f5c69738aaa9f9c00df667d5a02a633bf085 100644
--- a/webserver/docker_dokuwiki/templates/Dockerfile
+++ b/webserver/docker_dokuwiki/templates/Dockerfile
@@ -1,4 +1,4 @@
-FROM php:7.4.33-apache-bullseye
+FROM php:8.3.2-apache-bookworm
 
 # php-gd modul für dw2pdf plugin
 RUN apt-get update && apt-get install -y \
diff --git a/webserver/docker_dokuwiki/templates/docker-compose.yml b/webserver/docker_dokuwiki/templates/docker-compose.yml
index bc9e0295c6ce62605b0eb5cc9bfb11296d525e03..f7d425f9ac92b956f979a466a58b85f9bf039a49 100644
--- a/webserver/docker_dokuwiki/templates/docker-compose.yml
+++ b/webserver/docker_dokuwiki/templates/docker-compose.yml
@@ -3,6 +3,7 @@ version: "3"
 services:
 
   app:
+    # values set in configuration: noreply_email_user - noreply_email_pass - smtp_host - smtp_port 
     build: .
     image: "dokuwiki--{{ ansible_date_time.date }}--{{ ansible_date_time.hour }}-{{ ansible_date_time.minute }}-{{ ansible_date_time.second }}"
     restart: always
@@ -10,17 +11,15 @@ services:
       - /srv/dokuwiki/data/:/var/www/html
       - /srv/dokuwiki/pdftemplate/:/var/www/html/lib/plugins/dw2pdf/tpl/warpzone/
     labels:
+      - com.centurylinklabs.watchtower.enable=false
       - traefik.enable=true
       - traefik.http.routers.{{ servicename }}.rule=Host(`{{ domain }}`)
       - traefik.http.routers.{{ servicename }}.entrypoints=websecure
       - traefik.http.services.{{ servicename }}.loadbalancer.server.port=80      
     networks:
       - default      
-      - mail
       - web  
-
+    
 networks:
-  mail:
-    external: true    
   web:
     external: true    
diff --git a/webserver/docker_dokuwiki/templates/sendmail_plenum.py b/webserver/docker_dokuwiki/templates/sendmail_plenum.py
index 9d6a752eabb26f6b2fe349c7625d3321a4d01575..ed5dc3297ff838e2da2626ae89476c86708d7c59 100644
--- a/webserver/docker_dokuwiki/templates/sendmail_plenum.py
+++ b/webserver/docker_dokuwiki/templates/sendmail_plenum.py
@@ -1,72 +1,77 @@
 import smtplib
 import datetime
 from email.message import EmailMessage
-
-with open("/srv/dokuwiki/data/data/pages/intern/diskussionsthemen.txt") as fp:
-    raw = fp.read().split('\n')
-
-    # Extract Themen 
-    firstline = 0
-    lastline = 0
-    for index, line in enumerate(raw):
-        # Start marker
-        if "====== 1." in line:
-            firstline = index + 1
-            continue
+from email.utils import formatdate
+import requests
+
+def do_work():
+    with open("/srv/dokuwiki/data/data/pages/intern/diskussionsthemen.txt") as fp:
+        raw = fp.read().split('\n')
+
+        # Extract Themen 
+        firstline = 0
+        lastline = 0
+        for index, line in enumerate(raw):
+            # Start marker
+            if "====== 1." in line:
+                firstline = index + 1
+                continue
+            
+            # End marker
+            if "====== 2." in line:
+                lastline = index
+                break
         
-        # End marker
-        if "====== 2." in line:
-            lastline = index
-            break
-    
-    # Remove empty lines from topics
-    topics = []
-    for extracted in raw[firstline:lastline-1]:
-        if extracted != '':
-            topics.append(extracted)
-
-    # There are no topics - just exit
-    if (len(topics) == 0):
-        exit()
-
-    # calculate date of next tuesday
-    d = datetime.date.today()
-    while d.strftime('%a') != 'Tue':
-        d += datetime.timedelta(1)
-
-    # mail template 
-    mail = f"""
-Liebe Zonies,
-    
-es gibt wieder Themen die im Plenum besprochen werden sollen. Der nächste
-Reguläre Termin ist am nächsten Dienstag ({str(d)}).
-Im Wiki (https://wiki.warpzone.ms/intern:diskussionsthemen#diskussionsthemen_naechstes_plenum_automatische_einladung)
-stehen folgende Themen:
-
-{chr(10).join(topics)}
-
-Die Teilnahme ist natürlich auch remote möglich unter
-https://jitsi.dorf-post.de/warpzone-plenum möglich.
-
-Viele Grüße und bis Dienstag,
-
-sendmail_plenum.py
-"""
-
-    msg = EmailMessage()
-    msg['Subject'] = 'Aktuelle Plenumsthemen für den kommenden Dienstag 20:00'
-    msg['From'] = '{{noreply_email_user}}'
-    msg['To'] = 'intern@warpzone.ms'
-    msg.set_content(mail)
-    
-    server = smtplib.SMTP('{{smtp_host}}', {{smtp_port}})
-    server.starttls()
-    server.login("{{noreply_email_user}}", "{{noreply_email_pass}}")
-    server.send_message(msg)
-    server.quit()
-
+        # Remove empty lines from topics
+        topics = []
+        for extracted in raw[firstline:lastline]:
+            if extracted != '':
+                topics.append(extracted)
+
+        # There are no topics - just exit
+        if (len(topics) == 0):
+            return True
+
+        # calculate date of next tuesday
+        d = datetime.date.today()
+        while d.strftime('%a') != 'Tue':
+            d += datetime.timedelta(1)
+
+        # mail template 
+        mail = f"""
+    Liebe Zonies,
+        
+    es gibt wieder Themen die im Plenum besprochen werden sollen. Der nächste
+    Reguläre Termin ist am nächsten Dienstag ({str(d)}) um 20:00.
+    Im Wiki (https://wiki.warpzone.ms/intern:diskussionsthemen#diskussionsthemen_naechstes_plenum_automatische_einladung)
+    stehen folgende Themen:
 
+    {chr(10).join(topics)}
 
+    Die Teilnahme ist natürlich auch remote möglich unter
+    https://jitsi.dorf-post.de/warpzone-plenum möglich.
 
+    Viele Grüße und bis Dienstag,
 
+    sendmail_plenum.py
+    """
 
+        msg = EmailMessage()
+        msg['Subject'] = f'Aktuelle Plenumsthemen für Dienstag ({str(d)} 20:00)'
+        msg['From'] = '{{noreply_email_user}}'
+        msg['To'] = 'intern@warpzone.ms'
+        msg['Date'] = formatdate(localtime=True)
+        msg.set_content(mail)
+        
+        server = smtplib.SMTP('{{smtp_host}}', {{smtp_port}})
+        server.starttls()
+        server.login("{{noreply_email_user}}", "{{noreply_email_pass}}")
+        server.send_message(msg)
+        server.quit()
+    return True
+
+success = False
+try:
+    success = do_work()
+finally:
+    requests.get("{{ healthchecks_url }}" if success else "{{ healthchecks_url }}" + "/fail")
diff --git a/webserver/docker_gitlab/tasks/main.yml b/webserver/docker_gitlab/tasks/main.yml
index 5091020b76bad47f8219002978a4cb03496143f6..36dbab8ee61499229f7655c0705cd10408984979 100644
--- a/webserver/docker_gitlab/tasks/main.yml
+++ b/webserver/docker_gitlab/tasks/main.yml
@@ -34,12 +34,12 @@
 
 
 - name: stop gitlab docker
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: /srv/gitlab/
     state: absent
   when: configs.changed
 
 - name: start gitlab docker
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: /srv/gitlab/
     state: present
diff --git a/webserver/docker_gitlab/templates/conf/gitlab.rb b/webserver/docker_gitlab/templates/conf/gitlab.rb
index 55fdc6da3201f2879aca153cee94d19a7cc4303a..d893132b7e40b1b6d1d19676ffb80a6c440a2661 100644
--- a/webserver/docker_gitlab/templates/conf/gitlab.rb
+++ b/webserver/docker_gitlab/templates/conf/gitlab.rb
@@ -116,14 +116,12 @@ gitlab_rails['gitlab_email_enabled'] = true
 # gitlab_rails['gitlab_email_smime_key_file'] = '/etc/gitlab/ssl/gitlab_smime.key'
 # gitlab_rails['gitlab_email_smime_cert_file'] = '/etc/gitlab/ssl/gitlab_smime.crt'
 # gitlab_rails['gitlab_email_smime_ca_certs_file'] = '/etc/gitlab/ssl/gitlab_smime_cas.crt'
-gitlab_rails['gitlab_email_from'] = '{{ noreply_email_user }}'
-gitlab_rails['gitlab_email_display_name'] = 'Gitlab Warpzone'
+gitlab_rails['gitlab_email_from'] = 'gitlab@{{ smtp_domain }}'
+gitlab_rails['gitlab_email_display_name'] = 'Warpzone Gitlab'
 gitlab_rails['gitlab_email_reply_to'] = '{{ noreply_email_user }}'
 
 ### GitLab user privileges
-# gitlab_rails['gitlab_default_can_create_group'] = true
 # gitlab_rails['gitlab_username_changing_enabled'] = true
-gitlab_rails['gitlab_default_can_create_group'] = false
 gitlab_rails['gitlab_username_changing_enabled'] = false
 
 ### Default Theme
@@ -1426,17 +1424,27 @@ nginx['proxy_set_headers'] = {
 ################################################################################
 
 # logging['svlogd_size'] = 200 * 1024 * 1024 # rotate after 200 MB of log data
+logging['svlogd_size'] = 200 * 1024 * 1024
 # logging['svlogd_num'] = 30 # keep 30 rotated log files
+logging['svlogd_num'] = 30
 # logging['svlogd_timeout'] = 24 * 60 * 60 # rotate after 24 hours
+logging['svlogd_timeout'] = 24 * 60 * 60
 # logging['svlogd_filter'] = "gzip" # compress logs with gzip
+logging['svlogd_filter'] = "gzip"
 # logging['svlogd_udp'] = nil # transmit log messages via UDP
 # logging['svlogd_prefix'] = nil # custom prefix for log messages
 # logging['logrotate_frequency'] = "daily" # rotate logs daily
+logging['logrotate_frequency'] = "daily"
 # logging['logrotate_maxsize'] = nil # rotate logs when they grow bigger than size bytes even before the specified time interval (daily, weekly, monthly, or yearly)
+logging['logrotate_maxsize'] = "200M"
 # logging['logrotate_size'] = nil # do not rotate by size by default
+logging['logrotate_size'] = "50M"
 # logging['logrotate_rotate'] = 30 # keep 30 rotated logs
+logging['logrotate_rotate'] = 30
 # logging['logrotate_compress'] = "compress" # see 'man logrotate'
+logging['logrotate_compress'] = "compress"
 # logging['logrotate_method'] = "copytruncate" # see 'man logrotate'
+logging['logrotate_method'] = "copytruncate"
 # logging['logrotate_postrotate'] = nil # no postrotate command by default
 # logging['logrotate_dateformat'] = nil # use date extensions for rotated files rather than numbers e.g. a value of "-%Y-%m-%d" would give rotated files like production.log-2016-03-09.gz
 
@@ -1458,7 +1466,7 @@ nginx['proxy_set_headers'] = {
 ##! Docs: https://docs.gitlab.com/omnibus/settings/logs.html#logrotate
 ##! You can disable built in logrotate feature.
 ################################################################################
-# logrotate['enable'] = true
+logrotate['enable'] = true
 # logrotate['log_directory'] = "/var/log/gitlab/logrotate"
 
 ################################################################################
diff --git a/webserver/docker_gitlab/templates/docker-compose.yml b/webserver/docker_gitlab/templates/docker-compose.yml
index 0ef35cbc83ec37ef57d3ed127f00be133a830313..6b623c7f18aaf70db3252bc1a9a9266f40cebd50 100644
--- a/webserver/docker_gitlab/templates/docker-compose.yml
+++ b/webserver/docker_gitlab/templates/docker-compose.yml
@@ -5,7 +5,7 @@ services:
 
   app:
 
-    image: gitlab/gitlab-ce:15.9.3-ce.0
+    image: gitlab/gitlab-ce:latest
     restart: always
     ports:
       - "444:22"
@@ -35,7 +35,7 @@ services:
 
   dind:
 
-    image: docker:20-dind
+    image: docker:25-dind
     restart: always
     privileged: true
     environment:
diff --git a/webserver/docker_hackmd/tasks/main.yml b/webserver/docker_hackmd/tasks/main.yml
index 717a3dff51a4ddd7c0f25eb472ff4874ef8382f1..f67c1426cfe09d5595c50e4745ff97bf8e9dd5d6 100644
--- a/webserver/docker_hackmd/tasks/main.yml
+++ b/webserver/docker_hackmd/tasks/main.yml
@@ -24,8 +24,15 @@
   with_items:
     - docker-compose.yml
     - mysql-utf8.cnf
+  register: configs
+
+- name: stop hackmd docker
+  community.docker.docker_compose_v2:
+    project_src: /srv/hackmd
+    state: absent
+  when: configs.changed
 
 - name: start hackmd docker
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: /srv/hackmd/
     state: present
diff --git a/webserver/docker_hackmd/templates/docker-compose.yml b/webserver/docker_hackmd/templates/docker-compose.yml
index 192f720d2afab346df15741196fe1e90312d7a3a..9cef21717d7832305484cbff709eb7880e2a5724 100644
--- a/webserver/docker_hackmd/templates/docker-compose.yml
+++ b/webserver/docker_hackmd/templates/docker-compose.yml
@@ -3,7 +3,7 @@ version: "3"
 services:
 
   app:
-    image: quay.io/hedgedoc/hedgedoc:1.9.7-debian
+    image: quay.io/hedgedoc/hedgedoc:latest
     restart: always
     depends_on:
       - db
@@ -11,7 +11,7 @@ services:
       CMD_DOMAIN: "{{ domain }}"
       CMD_PROTOCOL_USESSL: "true"
       CMD_URL_ADDPORT: "false"
-      CMD_DB_URL: "mysql://hackmd:{{ mysql_user_pass }}@db:3306/hackmd"
+      CMD_DB_URL: "mariadb://hackmd:{{ mysql_user_pass }}@db:3306/hackmd"
       CMD_SESSION_SECRET: "{{ hackmd_session_secret }}"
       CMD_ALLOW_ANONYMOUS: "true"
       CMD_ALLOW_ANONYMOUS_EDITS: "true"
@@ -35,9 +35,8 @@ services:
       - default
       - web
 
-  # do not upgrade to 10.11.2
   db:
-    image: mariadb:10.5.13
+    image: mariadb:11.2.2
     restart: always
     volumes:
       - /srv/hackmd/db:/var/lib/mysql
diff --git a/webserver/docker_icinga/handlers/main.yml b/webserver/docker_icinga/handlers/main.yml
index 068770a8c8aaaa0f8455be9761145cf94584a9f9..d93deaf5c93d0f00632ecf25796a2d15a3d39f1d 100644
--- a/webserver/docker_icinga/handlers/main.yml
+++ b/webserver/docker_icinga/handlers/main.yml
@@ -1,7 +1,6 @@
 ---
 
 - name: restart icinga docker
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: /srv/icinga/
-    state: present
-    restarted: yes
+    state: restarted
diff --git a/webserver/docker_icinga/tasks/main.yml b/webserver/docker_icinga/tasks/main.yml
index 284f8a7c643cc2d286349eea64badf2b1863fba8..6319c40e154826e4440dc270ca396e98802a9371 100644
--- a/webserver/docker_icinga/tasks/main.yml
+++ b/webserver/docker_icinga/tasks/main.yml
@@ -1,6 +1,6 @@
 ---
 
-- include: ../functions/get_secret.yml
+- include_tasks: ../functions/get_secret.yml
   with_items:
     - { path: /srv/ldap/secret/ldap_readonly_pass, length: -1 }
     - { path: "{{ basedir }}/icinga_admin_pass",  length: 12 }
@@ -8,6 +8,7 @@
     - { path: "{{ basedir }}/icinga_api_pass",  length: 8 }
     - { path: "{{ basedir }}/mysql_admin_pass",  length: 12 }
     - { path: "{{ basedir }}/mysql_user_pass",  length: 12 }
+    - { path: "{{ basedir }}/matrix_notification_access_token",  length: -1 }
 
 
 - name: pakete installieren
@@ -56,7 +57,7 @@
   register: configured
 
 - name: "start {{ servicename }} docker (init)"
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: "{{ basedir }}"
     state: present
   when: configured.stat.exists == False
@@ -67,7 +68,7 @@
   when: configured.stat.exists == False
 
 - name: "stop {{ servicename }} docker (init)"
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: "{{ basedir }}"
     state: absent
   when: configured.stat.exists == False
@@ -116,7 +117,6 @@
 
   
 - name: "start {{ servicename }} docker"
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: "{{ basedir }}"
-    state: present
-    build: "{{ dockerconfig.changed }}"
+    state: present
\ No newline at end of file
diff --git a/webserver/docker_icinga/templates/Dockerfile b/webserver/docker_icinga/templates/Dockerfile
index 093fec9328bbfc219be695b2135389e092e8999a..88e650c2ff89f432d4a8f79b5fad93ce8548c900 100644
--- a/webserver/docker_icinga/templates/Dockerfile
+++ b/webserver/docker_icinga/templates/Dockerfile
@@ -1,4 +1,4 @@
-FROM jordan/icinga2:2.13.6
+FROM jordan/icinga2:2.14.0
 
 # Install additional Packages
 RUN apt-get update \
@@ -13,9 +13,10 @@ RUN apt-get update \
     libnet-dns-perl \
     libnet-ip-perl \
     perl \
-    python-requests \
     python3 \
-    python3-paho-mqtt \
+    python3-pip \
+    python3-requests \
+    virtualenv \
  && apt-get autoremove -y \
  && apt-get clean \
  && rm -rf /tmp/* /var/lib/apt/lists/* /var/cache/debconf/*-old
@@ -48,3 +49,17 @@ RUN cd /opt/ \
  && git clone https://github.com/elberfeld/check_metric_value.git \
  && cd /opt/check_metric_value/ \
  && git checkout b94d3c3e78497a05e3b4520d33421f37e4d77985
+
+# icinga2-matrix-bot - commit from 10.06.2018
+# create a symlink to emulate virtualenv 
+# patch matrix-service-notification.sh
+RUN cd /opt/ \
+ && git clone https://github.com/symptog/icinga2-matrix-bot.git \
+ && cd /opt/icinga2-matrix-bot/ \
+ && git checkout 86d03ed8884950eb2b883a9a94ecf93460b8e0bb \
+ && pip install -r requirements.txt \
+ && mkdir /opt/icinga2-matrix-bot/.venv \
+ && mkdir /opt/icinga2-matrix-bot/.venv/bin \
+ && ln -s /usr/bin/python3 /opt/icinga2-matrix-bot/.venv/bin/python \
+ && sed -i 's/matrix-host-state/matrix-service-state/' icinga2/matrix-service-notification.sh
+ 
\ No newline at end of file
diff --git a/webserver/docker_icinga/templates/docker-compose.yml b/webserver/docker_icinga/templates/docker-compose.yml
index 222f5df07ed5f110e0562108710651554f774383..e59e92b2c85733b2a6a4b060d82e789489fbac09 100644
--- a/webserver/docker_icinga/templates/docker-compose.yml
+++ b/webserver/docker_icinga/templates/docker-compose.yml
@@ -31,6 +31,7 @@ services:
       MYSQL_PASSWORD: "{{ mysql_user_pass }}"
       MYSQL_DATABASE: icinga
       MYSQL_USER: icinga
+      MARIADB_AUTO_UPGRADE: 1
       DEFAULT_MYSQL_HOST: db
       DEFAULT_MYSQL_USER: icinga
       DEFAULT_MYSQL_PASS: "{{ mysql_user_pass }}"
@@ -40,6 +41,7 @@ services:
       ICINGA2_FEATURE_GRAPHITE_PORT: 2003
       ICINGA2_FEATURE_DIRECTOR: 0
     labels:
+      - com.centurylinklabs.watchtower.enable=false
       - traefik.enable=true
       - traefik.http.routers.{{ servicename }}.rule=Host(`{{ domain }}`)
       - traefik.http.routers.{{ servicename }}.entrypoints=websecure
@@ -50,7 +52,7 @@ services:
 
   db:
 
-    image: mariadb:10.7.1
+    image: mariadb:11.2.2
     restart: always
     ports:
       - "{{ int_ip4 }}:{{mysql_port}}:3306"
diff --git a/webserver/docker_icinga/templates/etc/icinga/conf.d/commands2.conf b/webserver/docker_icinga/templates/etc/icinga/conf.d/commands2.conf
index 7ff9ab0d544d5689baea88c30be40116ac6db9ba..d1c3cbe066aa2f11280dd98939fe3c0362217a08 100644
--- a/webserver/docker_icinga/templates/etc/icinga/conf.d/commands2.conf
+++ b/webserver/docker_icinga/templates/etc/icinga/conf.d/commands2.conf
@@ -1,4 +1,8 @@
 
+/**
+ * Check MQTT values
+ */
+
 object CheckCommand "check_mqtt" {
   import "plugin-check-command"
 
@@ -33,6 +37,10 @@ object CheckCommand "check_mqtt" {
   }
 }
 
+/**
+ * Check for Mail Blacklisting
+ */
+
 object CheckCommand "check_mail_blacklist" {
   import "plugin-check-command"
 
@@ -45,6 +53,9 @@ object CheckCommand "check_mail_blacklist" {
   }
 }
 
+/**
+ * Check for Prometheus values 
+ */
 
 object CheckCommand "check_metric_value" {
   import "plugin-check-command"
@@ -62,4 +73,56 @@ object CheckCommand "check_metric_value" {
     "-w" = "$metric_warn$"
     "-c" = "$metric_crit$"
   }
-}
\ No newline at end of file
+}
+
+/**
+ * Matrix Notification 
+ */
+
+object NotificationCommand "matrix-host-notification" {
+  import "plugin-notification-command"
+
+  command = [ "/opt/icinga2-matrix-bot/icinga2/matrix-host-notification.sh" ]
+
+  env = {
+    "NOTIFICATIONTYPE" = "$notification.type$"
+    "HOSTALIAS" = "$host.display_name$",
+    "HOSTADDRESS" = "$address$",
+    "HOSTNAME" = "$host.name$",
+    "HOSTSTATE" = "$host.state$",
+    "LONGDATETIME" = "$icinga.long_date_time$",
+    "HOSTOUTPUT" = "$host.output$",
+    "NOTIFICATIONAUTHORNAME" = "$notification.author$",
+    "NOTIFICATIONCOMMENT" = "$notification.comment$",
+    "HOSTDISPLAYNAME" = "$host.display_name$",
+    "ICINGA_WEBURL" = "$notification_icingaweb2url$",
+    "MATRIX_SERVER" = "$user.vars.matrix.server$",
+    "MATRIX_TOKEN" = "$user.vars.matrix.token$",
+    "MATRIX_CHANNEL" = "$user.vars.matrix.channel$",
+  }
+}
+
+object NotificationCommand "matrix-service-notification" {
+  import "plugin-notification-command"
+
+  command = [ "/opt/icinga2-matrix-bot/icinga2/matrix-service-notification.sh" ]
+
+  env = {
+    "NOTIFICATIONTYPE" = "$notification.type$"
+    "SERVICEDESC" = "$service.name$"
+    "HOSTALIAS" = "$host.display_name$",
+    "HOSTNAME" = "$host.name$",
+    "HOSTADDRESS" = "$address$",
+    "SERVICESTATE" = "$service.state$",
+    "LONGDATETIME" = "$icinga.long_date_time$",
+    "SERVICEOUTPUT" = "$service.output$",
+    "NOTIFICATIONAUTHORNAME" = "$notification.author$",
+    "NOTIFICATIONCOMMENT" = "$notification.comment$",
+    "HOSTDISPLAYNAME" = "$host.display_name$",
+    "SERVICEDISPLAYNAME" = "$service.display_name$",
+    "ICINGA_WEBURL" = "$notification_icingaweb2url$",
+    "MATRIX_SERVER" = "$user.vars.matrix.server$",
+    "MATRIX_TOKEN" = "$user.vars.matrix.token$",
+    "MATRIX_CHANNEL" = "$user.vars.matrix.channel$",
+  }
+}
diff --git a/webserver/docker_icinga/templates/etc/icinga/conf.d/hosts.conf b/webserver/docker_icinga/templates/etc/icinga/conf.d/hosts.conf
index be828f7279a8a9c04cbe7dd6393485b03c5c7b48..deb6886a24bc7e14e7721695950c41d318c66fd9 100644
--- a/webserver/docker_icinga/templates/etc/icinga/conf.d/hosts.conf
+++ b/webserver/docker_icinga/templates/etc/icinga/conf.d/hosts.conf
@@ -1,5 +1,5 @@
 
-{% for host in groups['all'] %}
+{% for host in groups['prod'] %}
 {% if hostvars[host].alert is defined and hostvars[host].alert %}
 
 
diff --git a/webserver/docker_icinga/templates/etc/icinga/conf.d/hosts_manual.conf b/webserver/docker_icinga/templates/etc/icinga/conf.d/hosts_manual.conf
index 1923ab4ed0999c464a7c274fb8ba9cf1c808dca5..d1f7c2a8deb2ff0018286d160004e2afc6b88b25 100644
--- a/webserver/docker_icinga/templates/etc/icinga/conf.d/hosts_manual.conf
+++ b/webserver/docker_icinga/templates/etc/icinga/conf.d/hosts_manual.conf
@@ -1,5 +1,5 @@
 
-object Host "warpfire" {
+object Host "wz-router" {
   import "generic-host"
 
   address = "192.168.0.1"
@@ -7,11 +7,77 @@ object Host "warpfire" {
   groups = [ "network" ]
 }
 
-object Host "switch-sw01-hp" {
+object Host "wz-sw-core" {
   import "generic-host"
 
-  address = "192.168.0.100"
+  address = "192.168.0.2"
 
   groups = [ "network" ]
 }
 
+object Host "wz-sw-access" {
+  import "generic-host"
+
+  address = "192.168.0.3"
+  
+  # Keine Notifications, da der Switch aus ist wenn die Zone geschlossen ist 
+  vars.enable_nofitications = false
+
+  groups = [ "network" ]
+}
+
+object Host "wz-sw-dach" {
+  import "generic-host"
+
+  address = "192.168.0.4"
+
+  groups = [ "network" ]
+}
+
+object Host "wz-ap-dach" {
+  import "generic-host"
+
+  address = "192.168.0.13"
+
+  groups = [ "network" ]
+}
+
+object Host "wz-ap-eingang" {
+  import "generic-host"
+
+  address = "192.168.0.14"
+
+  groups = [ "network" ]
+}
+
+object Host "wz-ap-lounge" {
+  import "generic-host"
+
+  address = "192.168.0.10"
+
+  groups = [ "network" ]
+}
+
+object Host "wz-ap-vortrag" {
+  import "generic-host"
+
+  address = "192.168.0.12"
+
+  groups = [ "network" ]
+}
+
+object Host "wz-ap-werkstatt" {
+  import "generic-host"
+
+  address = "192.168.0.11"
+
+  groups = [ "network" ]
+}
+
+object Host "eq3max-cube" {
+  import "generic-host"
+
+  address = "{{ eq3max.cube_host }}"
+
+  groups = [ "network" ]
+}
diff --git a/webserver/docker_icinga/templates/etc/icinga/conf.d/notifications.conf b/webserver/docker_icinga/templates/etc/icinga/conf.d/notifications.conf
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..eadaa8ea3ebe47aeddf8d57b3de97a5c03d27287 100644
--- a/webserver/docker_icinga/templates/etc/icinga/conf.d/notifications.conf
+++ b/webserver/docker_icinga/templates/etc/icinga/conf.d/notifications.conf
@@ -0,0 +1,22 @@
+
+apply Notification "matrix" to Host {
+  import "matrix-host-notification"
+
+  users = [ "matrix" ]
+
+  interval = 4h
+
+  assign where host.address && host.vars.enable_nofitications != false
+}
+
+
+apply Notification "matrix" to Service {
+  import "matrix-service-notification"
+
+  users = [ "matrix" ]
+
+  interval = 4h
+
+  assign where service.name && service.vars.enable_nofitications != false
+}
+
diff --git a/webserver/docker_icinga/templates/etc/icinga/conf.d/services_backup.conf b/webserver/docker_icinga/templates/etc/icinga/conf.d/services_backup.conf
index 2e3d4d573be7ec5dc5ed88c19a4e793b4d327861..d3217ad4f8cbd076078a73dee0697b6dbf35b5bf 100644
--- a/webserver/docker_icinga/templates/etc/icinga/conf.d/services_backup.conf
+++ b/webserver/docker_icinga/templates/etc/icinga/conf.d/services_backup.conf
@@ -1,5 +1,5 @@
 
-{% for host in groups['all'] %}
+{% for host in groups['prod'] %}
 
   {% if hostvars[host].borgbackup_repos is defined %}
   {% for repo in hostvars[host].borgbackup_repos %}
diff --git a/webserver/docker_icinga/templates/etc/icinga/conf.d/services_container.conf b/webserver/docker_icinga/templates/etc/icinga/conf.d/services_container.conf
index abac49262a0270323f9a1863cec876711413a7be..1a0d315da9dedc3ebc82803266744cab9e548ad0 100644
--- a/webserver/docker_icinga/templates/etc/icinga/conf.d/services_container.conf
+++ b/webserver/docker_icinga/templates/etc/icinga/conf.d/services_container.conf
@@ -1,5 +1,5 @@
 
-{% for host in groups['all'] %}
+{% for host in groups['prod'] %}
 {% if hostvars[host].alert is defined and hostvars[host].alert %}
 
   {% if hostvars[host].alert.containers is defined %}
diff --git a/webserver/docker_icinga/templates/etc/icinga/conf.d/services_domains.conf b/webserver/docker_icinga/templates/etc/icinga/conf.d/services_domains.conf
index 48542184056cc51960ddfa80a787baedc7b8f45e..90fca025c6e07d43b2a05d38d45724b37f6126cb 100644
--- a/webserver/docker_icinga/templates/etc/icinga/conf.d/services_domains.conf
+++ b/webserver/docker_icinga/templates/etc/icinga/conf.d/services_domains.conf
@@ -1,5 +1,5 @@
 
-{% for host in groups['all'] %}
+{% for host in groups['prod'] %}
 
   {% if hostvars[host].ext_ip4 is defined and hostvars[host].ext_ip6 is defined and hostvars[host].webserver_domains is defined %}
   {% for domain in hostvars[host].webserver_domains %}
@@ -151,6 +151,8 @@ apply Service "spf record - {{ mail_domains[maildomain].maildomain }}" {
   assign where host.address && host.vars.is_dnsserver == "True"
 }
 
+  {% if mail_domains[maildomain].dmarc is defined %}
+
 apply Service "DMARC record - {{ mail_domains[maildomain].maildomain }}" {
   import "generic-service"
 
@@ -166,7 +168,7 @@ apply Service "DMARC record - {{ mail_domains[maildomain].maildomain }}" {
 
   assign where host.address && host.vars.is_dnsserver == "True"
 }
-
+  {% endif %}
 
   {% if mail_domains[maildomain].dkim is defined %}
   {% for entry in mail_domains[maildomain].dkim %}
@@ -179,7 +181,7 @@ apply Service "DKIM {{entry.selector}} record - {{ mail_domains[maildomain].mail
 
   vars.dig_lookup = "{{entry.selector}}._domainkey.{{ mail_domains[maildomain].maildomain }}"
   vars.dig_record_type = "TXT"
-  vars.dig_expected_address = "{{ entry.value }}"
+  vars.dig_expected_address = "{{ entry.value | replace("\"","\\\"") }}"
   vars.dig_arguments = "+tcp"
 
   groups = [ "mail" ]
diff --git a/webserver/docker_icinga/templates/etc/icinga/conf.d/services_exporters.conf b/webserver/docker_icinga/templates/etc/icinga/conf.d/services_exporters.conf
index 6898e7620c89bc17aec7f19ee634abedcdf7480c..c819a64a4c0d0606008b5d6931f6358aa291e84c 100644
--- a/webserver/docker_icinga/templates/etc/icinga/conf.d/services_exporters.conf
+++ b/webserver/docker_icinga/templates/etc/icinga/conf.d/services_exporters.conf
@@ -1,5 +1,5 @@
 
-{% for host in groups['all'] %}
+{% for host in groups['prod'] %}
 {% if hostvars[host].alert is defined and hostvars[host].alert %}
 
 apply Service "node-exporter" {
diff --git a/webserver/docker_icinga/templates/etc/icinga/conf.d/services_homematic.conf b/webserver/docker_icinga/templates/etc/icinga/conf.d/services_homematic.conf
new file mode 100644
index 0000000000000000000000000000000000000000..57f9aff5c2d165450e3140f92024e0beb1f03d8b
--- /dev/null
+++ b/webserver/docker_icinga/templates/etc/icinga/conf.d/services_homematic.conf
@@ -0,0 +1,36 @@
+
+apply Service "homematic-exporter" {
+  import "generic-service"
+
+  check_command = "http"
+  enable_perfdata = false
+
+  vars.http_address = "{{ hostvars['ogg'].int_ip4 }}"
+  vars.http_port = 8010
+  vars.http_uri = "/metrics"
+
+  groups = [ "exporter", "homematic" ]
+
+  assign where host.name == "ogg"
+}
+
+{% for device in homematic.devices_heizung %}
+
+apply Service "{{ device.name }}_homematic_lowbat" {
+  import "generic-service"
+
+  check_command = "check_metric_value"
+  enable_perfdata = true
+
+  vars.metric_url = "http://{{ hostvars['ogg'].int_ip4 }}:8010/metrics"
+  vars.metric_name = "homematic_lowbat"
+  vars.metric_labelname = "device"
+  vars.metric_labelvalue = "{{ device.id }}:0"
+  vars.metric_operator = "gt"
+  vars.metric_warn = "0"
+  vars.metric_crit = "0"
+
+  assign where host.name == "ogg"
+}
+
+{% endfor %}
\ No newline at end of file
diff --git a/webserver/docker_icinga/templates/etc/icinga/conf.d/services_ldap.conf b/webserver/docker_icinga/templates/etc/icinga/conf.d/services_ldap.conf
index 9e36e7a06c334692ca35c2a76e6dc0087be450d0..68ad1e39f2ada01c54cb1b76df6efd18a3cba265 100644
--- a/webserver/docker_icinga/templates/etc/icinga/conf.d/services_ldap.conf
+++ b/webserver/docker_icinga/templates/etc/icinga/conf.d/services_ldap.conf
@@ -1,5 +1,5 @@
 
-{% for host in groups['all'] %}
+{% for host in groups['prod'] %}
 
 
 apply Service "ldap_ok" {
diff --git a/webserver/docker_icinga/templates/etc/icinga/conf.d/services_manual.conf b/webserver/docker_icinga/templates/etc/icinga/conf.d/services_manual.conf
index 25e83bd2ff7a3a89ebb53d2e5e4e93d700c37693..4ddcc4e6cdc1794cc69d9dfe53191a6ef68508aa 100644
--- a/webserver/docker_icinga/templates/etc/icinga/conf.d/services_manual.conf
+++ b/webserver/docker_icinga/templates/etc/icinga/conf.d/services_manual.conf
@@ -9,4 +9,49 @@ apply Service "warpfire-admin" {
   vars.http_port = 80
 
   assign where host.name == "warpfire"
-}
\ No newline at end of file
+}
+
+apply Service "wz-uplink-globe" {
+  import "generic-service"
+
+  check_command = "ping4"
+
+  vars.ping_address = "212.124.34.242"
+
+  vars.ping_wrta = "100"
+  vars.ping_crta = "300"
+  vars.ping_wpl = "20"
+  vars.ping_cpl = "50"
+
+  assign where host.name == "wz-router"
+}
+
+apply Service "wz-uplink-webdiscount-1" {
+  import "generic-service"
+
+  check_command = "ping4"
+
+  vars.ping_address = "212.3.64.45"
+
+  vars.ping_wrta = "100"
+  vars.ping_crta = "300"
+  vars.ping_wpl = "20"
+  vars.ping_cpl = "50"
+
+  assign where host.name == "wz-router"
+}
+
+apply Service "wz-uplink-webdiscount-2" {
+  import "generic-service"
+
+  check_command = "ping4"
+
+  vars.ping_address = "212.3.80.222"
+
+  vars.ping_wrta = "100"
+  vars.ping_crta = "300"
+  vars.ping_wpl= "20"
+  vars.ping_cpl = "50"
+
+  assign where host.name == "wz-router"
+}
diff --git a/webserver/docker_icinga/templates/etc/icinga/conf.d/services_mqttsensors.conf b/webserver/docker_icinga/templates/etc/icinga/conf.d/services_mqttsensors.conf
index b0a31dd69d9dc6eb742d83781b0feb47a4b5f4fd..61650544a0c1616588856dcf1d44e44d3d689a90 100644
--- a/webserver/docker_icinga/templates/etc/icinga/conf.d/services_mqttsensors.conf
+++ b/webserver/docker_icinga/templates/etc/icinga/conf.d/services_mqttsensors.conf
@@ -15,4 +15,4 @@ apply Service "esphome-{{ device.id }}-status" {
   assign where host.name == "intserver"
 }
 
-{% endfor %}
+{% endfor %}
\ No newline at end of file
diff --git a/webserver/docker_icinga/templates/etc/icinga/conf.d/services_system.conf b/webserver/docker_icinga/templates/etc/icinga/conf.d/services_system.conf
index 5c54759f6f48aac02b498238d8ecd6a637c28f65..04ac2b43d996c615ba080cd4628ac10c33a95dfa 100644
--- a/webserver/docker_icinga/templates/etc/icinga/conf.d/services_system.conf
+++ b/webserver/docker_icinga/templates/etc/icinga/conf.d/services_system.conf
@@ -1,5 +1,5 @@
 
-{% for host in groups['all'] %}
+{% for host in groups['prod'] %}
 {% if hostvars[host].alert is defined and hostvars[host].alert %}
 
 apply Service "node_metrics" {
diff --git a/webserver/docker_icinga/templates/etc/icinga/conf.d/templates.conf b/webserver/docker_icinga/templates/etc/icinga/conf.d/templates.conf
index 5655e3f2d4b7c3dadbdadbada85bc8c7d8957946..4cc6d9e0f17b510a589252cc4034256a9dd69e1c 100644
--- a/webserver/docker_icinga/templates/etc/icinga/conf.d/templates.conf
+++ b/webserver/docker_icinga/templates/etc/icinga/conf.d/templates.conf
@@ -81,3 +81,30 @@ template Notification "mail-service-notification" {
 
   period = "24x7"
 }
+
+/**
+ * Provides default settings for Matrix.org service notifications.
+ */
+
+template Notification "matrix-host-notification" {
+    command = "matrix-host-notification"
+
+    states = [ Up, Down ]
+    types = [ Problem, Acknowledgement, Custom, FlappingStart, FlappingEnd ]
+    period = "24x7"
+    vars += {
+        notification_icingaweb2url = "https://{{ domain }}/icingaweb2"
+    }
+}
+
+template Notification "matrix-service-notification" {
+    command = "matrix-service-notification"
+
+    states = [ OK, Critical, Unknown ]
+    types = [ Problem, Acknowledgement, Custom, FlappingStart, FlappingEnd ]
+    period = "24x7"
+    vars += {
+        notification_icingaweb2url = "https://{{ domain }}/icingaweb2"
+    }
+}
+
diff --git a/webserver/docker_icinga/templates/etc/icinga/conf.d/users_groups.conf b/webserver/docker_icinga/templates/etc/icinga/conf.d/users_groups.conf
index bd6aee1279ace2904e33b7652d55c9710849d400..c16c7ea70af8c76166a5e24274d178999a02947d 100644
--- a/webserver/docker_icinga/templates/etc/icinga/conf.d/users_groups.conf
+++ b/webserver/docker_icinga/templates/etc/icinga/conf.d/users_groups.conf
@@ -3,3 +3,18 @@ object UserGroup "icingaadmins" {
   display_name = "Icinga 2 Admin Group"
 }
 
+object User "matrix" {
+  import "generic-user"
+
+  display_name = "Matrix User"
+  vars.matrix = {
+    token = "{{ matrix_notification_access_token }}"
+    channel = "{{ matrix.notifications_room_id }}"
+    server = "{{ matrix.public_url }}"
+  }
+}
+
+object UserGroup "matrix" {
+  display_name = "Matrix Group"
+  assign where user.vars.matrix
+}
diff --git a/webserver/docker_keycloak/tasks/main.yml b/webserver/docker_keycloak/tasks/main.yml
index 0f98082d518327ba033115f18df31a7212250da7..57a68e4c48789cbc3ffc688d3bde6eb6c6c04741 100644
--- a/webserver/docker_keycloak/tasks/main.yml
+++ b/webserver/docker_keycloak/tasks/main.yml
@@ -2,6 +2,7 @@
 
 - include_tasks: ../functions/get_secret.yml
   with_items:
+   - { path: /srv/shared/noreply_email_pass, length: -1 } 
    - { path: /srv/keycloak/keycloak_admin_pass,  length: 32 }
    - { path: /srv/keycloak/postgres_user_pass,  length: 24 }
 
@@ -37,13 +38,13 @@
 
 
 - name: stop keycloak docker
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: /srv/keycloak/
     state: absent
   when: config.changed
 
 
 - name: start keycloak docker
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: /srv/keycloak/
     state: present
diff --git a/webserver/docker_keycloak/templates/docker-compose.yml b/webserver/docker_keycloak/templates/docker-compose.yml
index 814219a746761fff3d2f978083682749548d6b97..e57b8b70345de5232c16c45c1241c7644b002d2e 100644
--- a/webserver/docker_keycloak/templates/docker-compose.yml
+++ b/webserver/docker_keycloak/templates/docker-compose.yml
@@ -6,7 +6,7 @@ services:
 
 
   app:
-
+    # values set in configuration: noreply_email_user - noreply_email_pass - smtp_host - smtp_port 
     image: jboss/keycloak:16.1.1
     restart: always
     depends_on:
@@ -25,13 +25,13 @@ services:
       DB_PASSWORD: "{{ postgres_user_pass }}"
       PROXY_ADDRESS_FORWARDING: "true"
     labels:
+      - com.centurylinklabs.watchtower.enable=false
       - traefik.enable=true
       - traefik.http.routers.{{ servicename }}.rule=Host(`{{ domain }}`)
       - traefik.http.routers.{{ servicename }}.entrypoints=websecure
       - traefik.http.services.{{ servicename }}.loadbalancer.server.port=8080
     networks:
       - default
-      - mail
       - web
 
 
@@ -64,7 +64,5 @@ services:
 
 
 networks:
-  mail:
-    external: true
   web:
     external: true
diff --git a/webserver/docker_keycloak/templates/sync-group-active/Dockerfile b/webserver/docker_keycloak/templates/sync-group-active/Dockerfile
index 8ed78b8b1c26a9d2467c1a09ac15a8f152597a64..fb9b9c7dfcf60dd02b52b1939b326c7c0dbe8388 100644
--- a/webserver/docker_keycloak/templates/sync-group-active/Dockerfile
+++ b/webserver/docker_keycloak/templates/sync-group-active/Dockerfile
@@ -1,5 +1,5 @@
 
-FROM python:3.9-alpine3.13
+FROM python:3.10-alpine3.13
 
 RUN pip install python-keycloak
 
diff --git a/webserver/docker_mail/defaults/main.yaml b/webserver/docker_mail/defaults/main.yaml
deleted file mode 100644
index 8c56cf91d8145fcaaefd2efa7a61f02267317332..0000000000000000000000000000000000000000
--- a/webserver/docker_mail/defaults/main.yaml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-servicename: mail
-basedir: /srv/mail
diff --git a/webserver/docker_mail/tasks/main.yaml b/webserver/docker_mail/tasks/main.yaml
index bb5a9941eb33489cedf1467fd9650979958d461b..c9d324eeae4f03c95927ce028437498f0f374336 100644
--- a/webserver/docker_mail/tasks/main.yaml
+++ b/webserver/docker_mail/tasks/main.yaml
@@ -2,21 +2,23 @@
 
 - include_tasks: ../functions/get_secret.yml
   with_items:
-   - { path: "{{ basedir }}/secrets/mailcow_admin_pass",  length: 28 }
-   - { path: "{{ basedir }}/secrets/mysql_mailcow_pass",  length: 28 }
-   - { path: "{{ basedir }}/secrets/mysql_root_pass",     length: 28 }
-   # mailman
+   - { path: "{{ basedir }}/secrets/mailu_secret_key",  length: 32 }
+   - { path: "{{ basedir }}/secrets/mailu_admin_pass",  length: 32 }
+   - { path: "{{ basedir }}/secrets/mailu_api_token",  length: 32 }
+   - { path: "{{ basedir }}/secrets/mailu_db_pass",  length: 28 }
+   - { path: "{{ basedir }}/secrets/roundcube_db_pass",  length: 28 }
    - { path: "{{ basedir }}/secrets/hyperkitty_api_key",  length: 28 }
-   - { path: "{{ basedir }}/secrets/postgres_mailman_pass",  length: 28 }
+   - { path: "{{ basedir }}/secrets/mailman_db_pass",  length: 28 }
    - { path: "{{ basedir }}/secrets/mailman_secret_key",  length: 28 }
    - { path: "{{ basedir }}/secrets/mailman_restapi_pass",  length: 28 }
+   - { path: "{{ basedir }}/secrets/mysql_root_pass",  length: 28 }
 
 
-- name: pakete installieren
-  apt:
-    pkg: ['git', 'logrotate', 'openssl']
-    update_cache: no
-    state: present
+# - name: pakete installieren
+#   apt:
+#     pkg: ['logrotate']
+#     update_cache: no
+#     state: present
 
 
 - name: "create folder struct for {{ servicename }}"
@@ -26,139 +28,85 @@
   with_items:
     - "{{ basedir }}"
     - "{{ basedir }}/secrets"
-    # mailcow
-    - "{{ basedir }}/data/mysql"
-    - "{{ basedir }}/data/mysql-socket"
-    - "{{ basedir }}/data/redis"
-    - "{{ basedir }}/data/rspamd"
-    - "{{ basedir }}/data/solr"
-    - "{{ basedir }}/data/postfix"
-    - "{{ basedir }}/data/sogo-web"
-    - "{{ basedir }}/data/sogo-userdata-backup"
-    - "{{ basedir }}/data/xmpp-vol-1"
-    - "{{ basedir }}/data/xmpp-upload-vol-1"
-    # mailmann
-    - "{{ basedir }}/data/mailman-core"
-    - "{{ basedir }}/data/mailman-core/var"
-    - "{{ basedir }}/data/mailman-core/var/data"
-    - "{{ basedir }}/data/mailman-web"
-    - "{{ basedir }}/data/mailman-postgres"
-
-
-- name: "create folder struct for {{ servicename }} with rights"
-  file:
-    path: "{{ item }}"
-    state: "directory"
-    owner: "5000"
-    group: "5000"
-    mode: "ugo+rwx"
-  with_items:
-  - "{{ basedir }}/data/crypt"
-  - "{{ basedir }}/data/vmail"
-  - "{{ basedir }}/data/vmail-index"
-
-
-- name: check if git dir exists
-  stat:
-    path: "{{ basedir }}/mailcow-dockerized/.git"
-  register: mailcow_dotgit
-
-- name: revert main.cf to avoid local changes
-  command: "git checkout data/conf/postfix/main.cf"
-  args:
-    chdir: "{{ basedir }}/mailcow-dockerized"
-  when: mailcow_dotgit.stat.exists == True
-
-
-- name: Git checkout mailcow
-  git:
-    repo: 'https://github.com/mailcow/mailcow-dockerized.git'
-    dest: "{{ basedir }}/mailcow-dockerized"
-    version: d6a3094bcc8b3d748994978ca7e274301b39e583
-    # current version 2021-05-18
-
-
-- name: Git checkout mailman-dockerized
-  git:
-    repo: 'https://github.com/maxking/docker-mailman.git'
-    dest: "{{ basedir }}/docker-mailman"
-    version: v0.4.4
-    # current version 2020-03-15
-
-
-- name: "create folder struct for {{ servicename }} 3"
-  file:
-    path: "{{ item }}"
-    state: "directory"
-  with_items:
-    - "{{ basedir }}/mailcow-dockerized/data/assets/ssl/"
-
-
-- name: check if DH Params exists
-  stat:
-    path: "{{ basedir }}/mailcow-dockerized/data/assets/ssl/dhparams.pem"
-  register: dhparams
-
-- name: generate new DH Params
-  command: "openssl dhparam -out {{ basedir }}/mailcow-dockerized/data/assets/ssl/dhparams.pem 2048"
-  when: dhparams.stat.exists == False
-
-
-- name: deploy mailcow config files
-  template:
-    dest:  "{{ basedir }}/{{ item }}"
-    src: "{{ item }}"
-    mode: 0644
-  with_items:
-    - mailcow-dockerized/mailcow.conf
-    - mailcow-dockerized/docker-compose.override.yml
-    - mailcow-dockerized/data/conf/postfix/extra.cf
-  register: config_mailcow
-
-
-- name: deploy mailman config files
+    - "{{ basedir }}/db"
+    - "{{ basedir }}/db-init"
+    - "{{ basedir }}/mailu"
+    - "{{ basedir }}/mailu/overrides"
+    - "{{ basedir }}/mailu/overrides/postfix"
+    - "{{ basedir }}/mailman-core"
+    - "{{ basedir }}/mailman-core/var"
+    - "{{ basedir }}/mailman-core/var/data"
+    - "{{ basedir }}/mailman-web"
+#    - "{{ basedir }}/mailman-db"
+
+
+# - name: "create folder struct for {{ servicename }} with rights"
+#   file:
+#     path: "{{ item }}"
+#     state: "directory"
+#     owner: "5000"
+#     group: "5000"
+#     mode: "ugo+rwx"
+#   with_items:
+#   - "{{ basedir }}/data/crypt"
+#   - "{{ basedir }}/data/vmail"
+#   - "{{ basedir }}/data/vmail-index"
+
+
+
+- name: "deploy {{ servicename }} config files"
   template:
     dest:  "{{ basedir }}/{{ item }}"
     src: "{{ item }}"
     mode: 0644
   with_items:
-    - docker-mailman/docker-compose.override.yml
-    - docker-mailman/nginx.conf
-    - data/mailman-core/mailman-extra.cfg
-    - data/mailman-web/settings_local.py
-  register: config_mailman
-
-
-- name: deploy LogRotate configs
-  template:
-    src: "logrotate/{{item}}"
-    dest: "/etc/logrotate.d/{{item}}"
-  with_items:
-    - mailman-core
-    - mailman-web
-
-
-# Start mailcow containers
-- name: "stop {{ servicename }} (mailcow) docker"
-  docker_compose:
-    project_src: "{{ basedir }}/mailcow-dockerized"
+    - docker-compose.yml
+    - mailu.env
+    - mailman.env
+    - mailman-nginx.conf
+    - db-init/mailman.sql
+    - db-init/roundcube.sql
+    - mailu/overrides/postfix/postfix.cf
+  register: config
+
+- name: "set local dns record"
+  become: true
+  blockinfile:
+    path: /etc/hosts
+    create: yes
+    block: |
+      {{ ext_ip4 }} mailserver.warpzone.ms
+
+# - name: deploy LogRotate configs
+#   template:
+#     src: "logrotate/{{item}}"
+#     dest: "/etc/logrotate.d/{{item}}"
+#   with_items:
+#     - mailman-core
+#     - mailman-web
+
+
+# Start containers
+- name: "stop {{ servicename }} docker"
+  community.docker.docker_compose_v2:
+    project_src: "{{ basedir }}"
     state: absent
-  when: config_mailcow.changed
+  when: config.changed
 
-- name: "start {{ servicename }} (mailcow) docker"
-  docker_compose:
-    project_src: "{{ basedir }}/mailcow-dockerized"
+- name: "start {{ servicename }} docker"
+  community.docker.docker_compose_v2:
+    project_src: "{{ basedir }}"
     state: present
 
 
 # Start mailman containers
-- name: "stop {{ servicename }} (mailman) docker"
-  docker_compose:
-    project_src: "{{ basedir }}/docker-mailman"
-    state: absent
-  when: config_mailcow.changed
-
-- name: "start {{ servicename }} (mailman) docker"
-  docker_compose:
-    project_src: "{{ basedir }}/docker-mailman"
-    state: present
+# - name: "stop {{ servicename }} (mailman) docker"
+#   community.docker.docker_compose_v2:
+#     project_src: "{{ basedir }}/docker-mailman"
+#     state: absent
+#   when: config_mailcow.changed
+
+# - name: "start {{ servicename }} (mailman) docker"
+#   community.docker.docker_compose_v2:
+#     project_src: "{{ basedir }}/docker-mailman"
+#     state: present
diff --git a/webserver/docker_mail/templates/data/mailman-core/mailman-extra.cfg b/webserver/docker_mail/templates/data/mailman-core/mailman-extra.cfg
deleted file mode 100644
index 5058fa5b340a5cbd70a7c0a6f5aea7a1472b8dbe..0000000000000000000000000000000000000000
--- a/webserver/docker_mail/templates/data/mailman-core/mailman-extra.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-[mailman]
-site_owner: listmaster@warpzone.ms
-
-[mta]
-remove_dkim_headers: yes
diff --git a/webserver/docker_mail/templates/data/mailman-web/settings_local.py b/webserver/docker_mail/templates/data/mailman-web/settings_local.py
deleted file mode 100644
index 5ad1b39eec21031167f1009dc0e7e363ddd2f638..0000000000000000000000000000000000000000
--- a/webserver/docker_mail/templates/data/mailman-web/settings_local.py
+++ /dev/null
@@ -1,20 +0,0 @@
-
-from settings import *
-import socket
-
-# Archivierung für Mailman-Core Container erlauben
-MAILMAN_ARCHIVER_FROM = (socket.gethostbyname('mailman-core'),)
-
-# disable social logins (google, facebook, etc. )
-INSTALLED_APPS = [a for a in INSTALLED_APPS if not 
-a.startswith('allauth.socialaccount.providers') and not
-a.startswith('django_mailman3.lib.auth.fedora')]
-
-# Mail backend settings
-EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
-EMAIL_HOST = 'postfix'
-EMAIL_PORT = 25
-EMAIL_HOST_USER = ''
-EMAIL_HOST_PASSWORD = ''
-DEFAULT_FROM_EMAIL = 'listmaster@warpzone.ms'
-SERVER_EMAIL = 'listmaster@warpzone.ms'
diff --git a/webserver/docker_mail/templates/db-init/mailman.sql b/webserver/docker_mail/templates/db-init/mailman.sql
new file mode 100644
index 0000000000000000000000000000000000000000..27ff11b022f639467d9da9686b81477be370d439
--- /dev/null
+++ b/webserver/docker_mail/templates/db-init/mailman.sql
@@ -0,0 +1,4 @@
+CREATE DATABASE IF NOT EXISTS mailman;
+CREATE USER IF NOT EXISTS mailman@'%' IDENTIFIED BY '{{ mailman_db_pass }}';
+GRANT ALL ON mailman.* TO mailman@'%';
+FLUSH PRIVILEGES;
diff --git a/webserver/docker_mail/templates/db-init/roundcube.sql b/webserver/docker_mail/templates/db-init/roundcube.sql
new file mode 100644
index 0000000000000000000000000000000000000000..32e4983adfe2d9ae4976b9383d0feb1330c14e73
--- /dev/null
+++ b/webserver/docker_mail/templates/db-init/roundcube.sql
@@ -0,0 +1,4 @@
+CREATE DATABASE IF NOT EXISTS roundcube;
+CREATE USER IF NOT EXISTS roundcube@'%' IDENTIFIED BY '{{ roundcube_db_pass }}';
+GRANT ALL ON roundcube.* TO roundcube@'%';
+FLUSH PRIVILEGES;
diff --git a/webserver/docker_mail/templates/docker-compose.yml b/webserver/docker_mail/templates/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..7916c2021f28fd62e8630538522632a45f5e7b18
--- /dev/null
+++ b/webserver/docker_mail/templates/docker-compose.yml
@@ -0,0 +1,218 @@
+version: '2.2'
+
+services:
+
+  # External dependencies
+  redis:
+    image: redis:alpine
+    restart: always
+    volumes:
+      - "{{ basedir }}/mailu/redis:/data"
+    depends_on:
+      - resolver
+    dns:
+      - 192.168.203.254
+
+  # Certdumper
+  certdumper:
+    image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}traefik-certdumper:latest
+    restart: always
+    environment:
+      - DOMAIN={{ mailserver }}
+      - TRAEFIK_VERSION=v2
+    volumes:
+      - "/srv/traefik:/traefik"
+      - "{{ basedir }}/mailu/certs:/output"
+
+  # Core services
+  front:
+    image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}nginx:latest
+    restart: always
+    depends_on:
+      - db
+      - resolver
+    env_file: mailu.env
+    ports:
+      - "25:25" #smtp
+      - "465:465" #submissions
+      - "587:587" #submission
+      - "143:143" #imap
+      - "993:993" #imaps
+    volumes:
+      - "{{ basedir }}/mailu/certs:/certs"
+      - "{{ basedir }}/mailu/overrides/nginx:/overrides:ro"
+    labels:
+      - "traefik.enable=true"
+      - "traefik.http.routers.{{ servicename }}.entrypoints=websecure"
+      - "traefik.http.routers.{{ servicename }}.rule=Host(`{{ mailserver }}`)"
+      - "traefik.http.routers.{{ servicename }}.tls"
+      - "traefik.http.routers.{{ servicename }}.tls.certresolver=letsencrypt"
+      - "traefik.http.routers.{{ servicename }}.tls.domains[0].main={{ domain }}"
+      - "traefik.http.routers.{{ servicename }}.tls.domains[0].sans={{ mailserver }},imap.warpzone.ms,smtp.warpzone.ms"
+      - "traefik.http.routers.{{ servicename }}.service={{ servicename }}"
+      - "traefik.http.services.{{ servicename }}.loadbalancer.server.port=80"
+    networks:
+      - default
+      - web
+    dns:
+      - 192.168.203.254
+
+  resolver:
+    image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}unbound:latest
+    env_file: mailu.env
+    restart: always
+    networks:
+      default:
+        ipv4_address: 192.168.203.254
+
+  admin:
+    image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}admin:latest
+    restart: always
+    depends_on:
+      - db
+      - redis
+      - resolver
+    env_file: mailu.env
+    volumes:
+      - "{{ basedir }}/mailu/data:/data"
+      - "{{ basedir }}/mailu/dkim:/dkim"
+    dns:
+      - 192.168.203.254
+
+  imap:
+    image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}dovecot:latest
+    restart: always
+    depends_on:
+      - db
+      - front
+      - resolver
+    env_file: mailu.env
+    volumes:
+      - "{{ basedir }}/mailu/mail:/mail"
+      - "{{ basedir }}/mailu/overrides/dovecot:/overrides:ro"
+    dns:
+      - 192.168.203.254
+
+  smtp:
+    image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}postfix:latest
+    restart: always
+    depends_on:
+      - db
+      - front
+      - resolver
+      - mailman-core
+    env_file: mailu.env
+    volumes:
+      - "{{ basedir }}/mailu/mailqueue:/queue"
+      - "{{ basedir }}/mailu/overrides/postfix:/overrides:ro"
+      - "{{ basedir }}/mailman-core/var/data:/opt/mailman:ro"
+    dns:
+      - 192.168.203.254
+
+  oletools:
+    image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}oletools:latest
+    hostname: oletools
+    restart: always
+    depends_on:
+      - resolver
+    networks:
+      - noinet
+    dns:
+      - 192.168.203.254
+
+  antispam:
+    image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}rspamd:latest
+    hostname: antispam
+    restart: always
+    depends_on:
+      - front
+      - redis
+      - oletools
+      - resolver
+    env_file: mailu.env
+    volumes:
+      - "{{ basedir }}/mailu/filter:/var/lib/rspamd"
+      - "{{ basedir }}/mailu/overrides/rspamd:/overrides:ro"
+    networks:
+      default:
+        ipv4_address: 192.168.203.253
+      noinet:
+    dns:
+      - 192.168.203.254
+
+  # Optional mailu services: Database
+  db:
+    image: mariadb:11.2
+    command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
+    restart: always
+    volumes:
+      - "{{ basedir }}/db:/var/lib/mysql"
+      - "{{ basedir }}/db-init:/docker-entrypoint-initdb.d:ro"
+    environment:
+      - MYSQL_DATABASE=mailu
+      - MYSQL_USER=mailu
+      - MYSQL_PASSWORD={{ mailu_db_pass }}
+      - MYSQL_ROOT_PASSWORD={{ mysql_root_pass }}
+
+  # Optional mailu services: Webmail
+  webmail:
+    image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}webmail:latest
+    restart: always
+    depends_on:
+      - front
+    env_file: mailu.env
+    volumes:
+      - "{{ basedir }}/mailu/webmail:/data"
+      - "{{ basedir }}/mailu/overrides/roundcube:/overrides:ro"
+
+  # Additional Services: mailman
+  mailman-core:
+    image: maxking/mailman-core:0.4
+    restart: always
+    env_file: mailman.env
+    depends_on:
+      - db
+    volumes:
+      - "{{ basedir }}/mailman-core:/opt/mailman:rw,z"
+
+  mailman-web:
+    image: maxking/mailman-web:0.4
+    restart: always
+    env_file: mailman.env
+    depends_on:
+      - db
+    volumes:
+      - "{{ basedir }}/mailman-web:/opt/mailman-web-data:rw,z"
+
+  mailman-nginx:
+    image: nginx:1.25
+    restart: always
+    depends_on:
+      - mailman-web
+    volumes:
+      - "{{ basedir }}/mailman-web/:/opt/mailman-web-data:ro,z"
+      - "{{ basedir }}/mailman-nginx.conf:/etc/nginx/conf.d/default.conf:ro" 
+    labels:
+      - traefik.enable=true
+      - traefik.http.routers.{{ servicename }}-mailman.rule=Host(`{{ listserver }}`)
+      - traefik.http.routers.{{ servicename }}-mailman.entrypoints=websecure
+      - traefik.http.services.{{ servicename }}-mailman.loadbalancer.server.port=80
+    networks:
+      - default
+      - web
+
+networks:
+  default:
+    driver: bridge
+    enable_ipv6: true
+    ipam:
+      driver: default
+      config:
+        # must be a ULA range
+        - subnet: fd00:dead:beef:25::/64
+        - subnet: 192.168.203.0/24
+  noinet:
+    driver: bridge
+    internal: true
+  web:
+    external: true
diff --git a/webserver/docker_mail/templates/docker-mailman/docker-compose.override.yml b/webserver/docker_mail/templates/docker-mailman/docker-compose.override.yml
deleted file mode 100644
index 9da9c4eadb83d131f5a1597493c5d49924db0aee..0000000000000000000000000000000000000000
--- a/webserver/docker_mail/templates/docker-mailman/docker-compose.override.yml
+++ /dev/null
@@ -1,88 +0,0 @@
-version: '2'
-
-services:
-
-
-  mailman-core:
-    container_name: mail_mailman-core
-    restart: always
-    volumes:
-      - "{{ basedir }}/data/mailman-core:/opt/mailman:rw,z"
-    environment:
-      - DATABASE_URL=postgres://mailman:{{ postgres_mailman_pass }}@database/mailmandb
-      - MTA=postfix
-      - MM_HOSTNAME=mailman-core-mail
-      - SMTP_HOST=postfix
-      - SMTP_PORT=25
-      - MAILMAN_REST_USER=mailman
-      - MAILMAN_REST_PASSWORD={{ mailman_restapi_pass }}
-      - HYPERKITTY_URL=http://mailman-web:8000/hyperkitty
-      - HYPERKITTY_API_KEY={{ hyperkitty_api_key }}
-    networks:
-      mailman:
-        aliases:
-          - mailman-core
-      mail:
-        aliases:
-          - mailman-core
-          - mailman-core-mail
-
-
-  mailman-web:
-    container_name: mail_mailman-web
-    restart: always
-    volumes:
-      - "{{ basedir }}/data/mailman-web:/opt/mailman-web-data:rw,z"
-    environment:
-      - DATABASE_URL=postgres://mailman:{{ postgres_mailman_pass }}@database/mailmandb
-      - HYPERKITTY_API_KEY={{ hyperkitty_api_key }}
-      - SECRET_KEY={{ mailman_secret_key }}
-      - SERVE_FROM_DOMAIN=listserver.warpzone.ms
-      - MAILMAN_REST_URL=http://mailman-core-mail:8001
-      - MAILMAN_REST_USER=mailman
-      - MAILMAN_REST_PASSWORD={{ mailman_restapi_pass }}
-    networks:
-      - mail
-      - mailman
-
-
-  nginx:
-    container_name: mail_mailman-nginx
-    image: nginx:1.19
-    restart: always
-    depends_on:
-      - mailman-web
-    volumes:
-      - "{{ basedir }}/data/mailman-web/:/opt/mailman-web-data:ro,z"
-      - "{{ basedir }}/docker-mailman/nginx.conf:/etc/nginx/conf.d/default.conf:ro" 
-    labels:
-      - traefik.enable=true
-      - traefik.http.routers.{{ servicename }}-mailman.rule=Host(`listserver.warpzone.ms`) || Host(`lists.warpzone.ms`)
-      - traefik.http.routers.{{ servicename }}-mailman.entrypoints=websecure
-      - traefik.http.services.{{ servicename }}-mailman.loadbalancer.server.port=80
-    networks:
-      - mailman
-      - web
-
-
-  database:
-    container_name: mail_mailman-db
-    restart: always
-    environment:
-      - POSTGRES_PASSWORD={{ postgres_mailman_pass }}
-    volumes:
-      - "{{ basedir }}/data/mailman-postgres:/var/lib/postgresql/data"
-    networks:
-      - mailman
-
-
-
-networks:
-  mailman:
-    driver: bridge
-    ipam:
-      driver: default
-  mail:
-    external: true
-  web:
-    external: true
diff --git a/webserver/docker_mail/templates/logrotate/mailman-core b/webserver/docker_mail/templates/logrotate/mailman-core
deleted file mode 100644
index bb8e31704a1dcca0da654f29e85fd78387efc7e6..0000000000000000000000000000000000000000
--- a/webserver/docker_mail/templates/logrotate/mailman-core
+++ /dev/null
@@ -1,7 +0,0 @@
-/srv/mail/data/mailman-core/var/logs/*.log {
-  rotate 12
-  monthly
-  compress
-  missingok
-  notifempty
-}
diff --git a/webserver/docker_mail/templates/logrotate/mailman-web b/webserver/docker_mail/templates/logrotate/mailman-web
deleted file mode 100644
index 17f75f37047cb26973d5d710676266c012ebe7d4..0000000000000000000000000000000000000000
--- a/webserver/docker_mail/templates/logrotate/mailman-web
+++ /dev/null
@@ -1,7 +0,0 @@
-/srv/mail/data/mailman-web/logs/*.log {
-  rotate 12
-  monthly
-  compress
-  missingok
-  notifempty
-}
diff --git a/webserver/docker_mail/templates/mailcow-dockerized/data/conf/postfix/extra.cf b/webserver/docker_mail/templates/mailcow-dockerized/data/conf/postfix/extra.cf
deleted file mode 100644
index cc443f471121ee2578fd5b5f413729a80d45f722..0000000000000000000000000000000000000000
--- a/webserver/docker_mail/templates/mailcow-dockerized/data/conf/postfix/extra.cf
+++ /dev/null
@@ -1,22 +0,0 @@
-
-# Support the default VERP delimiter.
-recipient_delimiter = +
-unknown_local_recipient_reject_code = 550
-owner_request_special = no
-
-# use relay_recipient_maps instead of local_recipient_maps
-relay_recipient_maps =
-  regexp:/opt/mailman/postfix_lmtp
-
-# Wert aus main.cf übernommen und ergänzt 
-transport_maps = 
-  pcre:/opt/postfix/conf/custom_transport.pcre,
-  pcre:/opt/postfix/conf/local_transport,
-  proxy:mysql:/opt/postfix/conf/sql/mysql_relay_ne.cf,
-  proxy:mysql:/opt/postfix/conf/sql/mysql_transport_maps.cf,
-  regexp:/opt/mailman/postfix_lmtp
-
-# Wert aus main.cf übernommen und ergänzt 
-relay_domains = 
-  proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_relay_domain_maps.cf,
-  regexp:/opt/mailman/postfix_domains
diff --git a/webserver/docker_mail/templates/mailcow-dockerized/docker-compose.override.yml b/webserver/docker_mail/templates/mailcow-dockerized/docker-compose.override.yml
deleted file mode 100644
index b891ae979b41408c6c006319ff0d182c01009150..0000000000000000000000000000000000000000
--- a/webserver/docker_mail/templates/mailcow-dockerized/docker-compose.override.yml
+++ /dev/null
@@ -1,182 +0,0 @@
-version: '2.1'
-
-services:
-
-# Export der Letsencrypt-Zertifikate von traefik zur Verwendung in Postfix und Dovecot
-
-    traefik-certdumper:
-        image: humenius/traefik-certs-dumper
-        restart: always
-        network_mode: none
-        command: --restart-containers mail_dovecot-mailcow_1,mail_postfix-mailcow_1,mail_nginx-mailcow_1,mail_watchdog-mailcow_1
-        volumes:
-          # mount the folder which contains Traefik's `acme.json' file
-          - /srv/traefik/acme.json:/traefik/acme.json:ro
-          # mount mailcow's SSL folder
-          - ./data/assets/ssl/:/output:rw
-          # Docker API for Container restart
-          - /var/run/docker.sock:/var/run/docker.sock:ro
-        environment:
-          # only change this, if you're using another domain for mailcow's web frontend compared to the standard config
-          - DOMAIN=${MAILCOW_HOSTNAME}
-
-
-# Prometheus Postfix Exporter
-
-    postfix-exporter:
-        image: unikum/postfix_exporter:latest
-        restart: always
-        depends_on:
-          - postfix-mailcow
-        ports:
-          - "{{ int_ip4 }}:9154:9154"
-        volumes:
-          - "postfix-vol-1:/var/spool/postfix:z"
-
-
-# Labels für traefik Konfiguration
-# Der Container nginx-mailcow benötigt zusätzlich den Alias sogo, damit der Container wegfallen kann
-
-    nginx-mailcow:
-      labels:
-        - traefik.enable=true
-        - traefik.http.routers.{{ servicename }}-mailcow.rule=Host(`${MAILCOW_HOSTNAME}`) || Host(`mail.warpzone.ms`)
-        - traefik.http.routers.{{ servicename }}-mailcow.entrypoints=websecure
-        - traefik.http.services.{{ servicename }}-mailcow.loadbalancer.server.port=42012
-      networks:
-        mailcow-network:
-          aliases:
-            - nginx
-            - sogo
-            - ejabberd
-        web:
-          aliases:
-            - mailcow
-
-
-# Mailman konfiguration in Postfix-Container mounten
-# postfix ans mail netzwerk um mit mailman zu kommunizieren
-
-    postfix-mailcow:
-      volumes:
-        - "{{ basedir }}/data/mailman-core/var/data:/opt/mailman:rw,z"
-      networks:
-        mail:
-          aliases:
-            - postfix
-
-
-# Container anpassen um start zu unterbinden
-    clamd-mailcow:
-      image: stakater/exit-container
-      restart: 'no'
-
-    sogo-mailcow:
-      image: stakater/exit-container
-      restart: 'no'
-
-    acme-mailcow:
-      image: stakater/exit-container
-      restart: 'no'
-
-    solr-mailcow:
-      image: stakater/exit-container
-      restart: 'no'
-
-    ejabberd-mailcow:
-      image: stakater/exit-container
-      restart: 'no'
-
-
-# Externes Netzwerk
-
-networks:
-  web:
-    external: true
-  mail:
-    external: true
-
-
-# Volumes auf lokale Verzeichnise umlenken
-
-volumes:
-  # Storage for email files
-  vmail-vol-1:
-    driver: local
-    driver_opts:
-      o: bind
-      type: none
-      device: "{{ basedir }}/data/vmail"
-  # Storage for index (deduplicated)
-  vmail-index-vol-1:
-    driver: local
-    driver_opts:
-      o: bind
-      type: none
-      device: "{{ basedir }}/data/vmail-index"
-  mysql-vol-1:
-    driver: local
-    driver_opts:
-      o: bind
-      type: none
-      device: "{{ basedir }}/data/mysql"
-  mysql-socket-vol-1:
-    driver: local
-    driver_opts:
-      o: bind
-      type: none
-      device: "{{ basedir }}/data/mysql-socket"
-  redis-vol-1:
-    driver: local
-    driver_opts:
-      o: bind
-      type: none
-      device: "{{ basedir }}/data/redis"
-  rspamd-vol-1:
-    driver: local
-    driver_opts:
-      o: bind
-      type: none
-      device: "{{ basedir }}/data/rspamd"
-  solr-vol-1:
-    driver: local
-    driver_opts:
-      o: bind
-      type: none
-      device: "{{ basedir }}/data/solr"
-  postfix-vol-1:
-    driver: local
-    driver_opts:
-      o: bind
-      type: none
-      device: "{{ basedir }}/data/postfix"
-  crypt-vol-1:
-    driver: local
-    driver_opts:
-      o: bind
-      type: none
-      device: "{{ basedir }}/data/crypt"
-  sogo-web-vol-1:
-    driver: local
-    driver_opts:
-      o: bind
-      type: none
-      device: "{{ basedir }}/data/sogo-web"
-  sogo-userdata-backup-vol-1:
-    driver: local
-    driver_opts:
-      o: bind
-      type: none
-      device: "{{ basedir }}/data/sogo-userdata-backup"
-  xmpp-vol-1:
-    driver: local
-    driver_opts:
-      o: bind
-      type: none
-      device: "{{ basedir }}/data/xmpp-vol-1"
-  xmpp-upload-vol-1:
-    driver: local
-    driver_opts:
-      o: bind
-      type: none
-      device: "{{ basedir }}/data/xmpp-upload-vol-1"
diff --git a/webserver/docker_mail/templates/mailcow-dockerized/mailcow.conf b/webserver/docker_mail/templates/mailcow-dockerized/mailcow.conf
deleted file mode 100644
index 6aac1d7fe879ad80ba0030b32d4a2a75865b891e..0000000000000000000000000000000000000000
--- a/webserver/docker_mail/templates/mailcow-dockerized/mailcow.conf
+++ /dev/null
@@ -1,208 +0,0 @@
-# ------------------------------
-# mailcow web ui configuration
-# ------------------------------
-# example.org is _not_ a valid hostname, use a fqdn here.
-# Default admin user is "admin"
-# Default password is "moohoo"
-
-MAILCOW_HOSTNAME=mailserver.warpzone.ms
-
-# ------------------------------
-# SQL database configuration
-# ------------------------------
-
-DBNAME=mailcow
-DBUSER=mailcow
-
-# Please use long, random alphanumeric strings (A-Za-z0-9)
-
-DBPASS={{ mysql_mailcow_pass }}
-DBROOT={{ mysql_root_pass }}
-
-# ------------------------------
-# HTTP/S Bindings
-# ------------------------------
-
-# You should use HTTPS, but in case of SSL offloaded reverse proxies:
-# Might be important: This will also change the binding within the container.
-# If you use a proxy within Docker, point it to the ports you set below.
-# Do _not_ use IP:PORT in HTTP(S)_BIND or HTTP(S)_PORT
-# IMPORTANT: Do not use port 8081, 9081 or 65510!
-
-HTTP_PORT=42012
-HTTP_BIND=127.0.0.1
-
-HTTPS_PORT=42013
-HTTPS_BIND=127.0.0.1
-
-# ------------------------------
-# Other bindings
-# ------------------------------
-# You should leave that alone
-# Format: 11.22.33.44:25 or 0.0.0.0:465 etc.
-
-SMTP_PORT=25
-SMTPS_PORT=465
-SUBMISSION_PORT=587
-IMAP_PORT=127.0.0.1:143
-IMAPS_PORT=993
-POP_PORT=127.0.0.1:110
-POPS_PORT=127.0.0.1:995
-SIEVE_PORT=127.0.0.1:4190
-DOVEADM_PORT=127.0.0.1:19991
-SQL_PORT=127.0.0.1:23306
-SOLR_PORT=127.0.0.1:18983
-REDIS_PORT=127.0.0.1:7654
-
-# bind jabber to nonstandard port because we already have a jabber running
-# no (vig) risk as we use the exit container
-XMPP_C2S_PORT=127:0.0.1:15222
-XMPP_S2S_PORT=127:0.0.1:15269
-XMPP_HTTPS_PORT=127:0.0.1:15443
-
-# Your timezone
-
-TZ=Europe/Berlin
-
-# Fixed project name
-# Please use lowercase letters only
-
-COMPOSE_PROJECT_NAME=mail
-
-# Set this to "allow" to enable the anyone pseudo user. Disabled by default.
-# When enabled, ACL can be created, that apply to "All authenticated users"
-# This should probably only be activated on mail hosts, that are used exclusivly by one organisation.
-# Otherwise a user might share data with too many other users.
-ACL_ANYONE=disallow
-
-# Garbage collector cleanup
-# Deleted domains and mailboxes are moved to /var/vmail/_garbage/timestamp_sanitizedstring
-# How long should objects remain in the garbage until they are being deleted? (value in minutes)
-# Check interval is hourly
-
-MAILDIR_GC_TIME=7200
-
-# Additional SAN for the certificate
-#
-# You can use wildcard records to create specific names for every domain you add to mailcow.
-# Example: Add domains "example.com" and "example.net" to mailcow, change ADDITIONAL_SAN to a value like:
-#ADDITIONAL_SAN=imap.*,smtp.*
-# This will expand the certificate to "imap.example.com", "smtp.example.com", "imap.example.net", "imap.example.net"
-# plus every domain you add in the future.
-#
-# You can also just add static names...
-#ADDITIONAL_SAN=srv1.example.net
-# ...or combine wildcard and static names:
-#ADDITIONAL_SAN=imap.*,srv1.example.com
-#
-
-ADDITIONAL_SAN=
-
-# Skip running ACME (acme-mailcow, Let's Encrypt certs) - y/n
-
-SKIP_LETS_ENCRYPT=y
-
-# Create seperate certificates for all domains - y/n
-# this will allow adding more than 100 domains, but some email clients will not be able to connect with alternative hostnames
-# see https://wiki.dovecot.org/SSL/SNIClientSupport
-ENABLE_SSL_SNI=n
-
-# Skip IPv4 check in ACME container - y/n
-
-SKIP_IP_CHECK=n
-
-# Skip HTTP verification in ACME container - y/n
-
-SKIP_HTTP_VERIFICATION=n
-
-# Skip ClamAV (clamd-mailcow) anti-virus (Rspamd will auto-detect a missing ClamAV container) - y/n
-
-SKIP_CLAMD=y
-
-# Skip SOGo: Will disable SOGo integration and therefore webmail, DAV protocols and ActiveSync support (experimental, unsupported, not fully implemented) - y/n
-
-SKIP_SOGO=y
-
-# Skip Solr on low-memory systems or if you do not want to store a readable index of your mails in solr-vol-1.
-
-SKIP_SOLR=y
-
-# Solr heap size in MB, there is no recommendation, please see Solr docs.
-# Solr is a prone to run OOM and should be monitored. Unmonitored Solr setups are not recommended.
-
-SOLR_HEAP=1024
-
-# Allow admins to log into SOGo as email user (without any password)
-
-ALLOW_ADMIN_EMAIL_LOGIN=n
-
-# Enable watchdog (watchdog-mailcow) to restart unhealthy containers
-
-USE_WATCHDOG=y
-
-# Send watchdog notifications by mail (sent from watchdog@MAILCOW_HOSTNAME)
-# CAUTION:
-# 1. You should use external recipients
-# 2. Mails are sent unsigned (no DKIM)
-# 3. If you use DMARC, create a separate DMARC policy ("v=DMARC1; p=none;" in _dmarc.MAILCOW_HOSTNAME)
-# Multiple rcpts allowed, NO quotation marks, NO spaces
-
-#WATCHDOG_NOTIFY_EMAIL=a@example.com,b@example.com,c@example.com
-WATCHDOG_NOTIFY_EMAIL=warpzone-server-issues@void.ms
-
-# Notify about banned IP (includes whois lookup)
-WATCHDOG_NOTIFY_BAN=n
-
-# Checks if mailcow is an open relay. Requires a SAL. More checks will follow.
-# https://www.servercow.de/mailcow?lang=en
-# https://www.servercow.de/mailcow?lang=de
-# No data is collected. Opt-in and anonymous.
-# Will only work with unmodified mailcow setups.
-WATCHDOG_EXTERNAL_CHECKS=y
-
-# Max log lines per service to keep in Redis logs
-
-LOG_LINES=9999
-
-# Internal IPv4 /24 subnet, format n.n.n (expands to n.n.n.0/24)
-# Use private IPv4 addresses only, see https://en.wikipedia.org/wiki/Private_network#Private_IPv4_addresses
-
-IPV4_NETWORK=192.168.15
-
-# Internal IPv6 subnet in fc00::/7
-# Use private IPv6 addresses only, see https://en.wikipedia.org/wiki/Private_network#Private_IPv6_addresses
-
-IPV6_NETWORK=fd4d:dead:beef:2342::/64
-
-# Use this IPv4 for outgoing connections (SNAT)
-
-SNAT_TO_SOURCE={{ ext_ip4 }}
-
-# Use this IPv6 for outgoing connections (SNAT)
-
-SNAT6_TO_SOURCE={{ ext_ip6 }}
-
-# Create or override an API key for the web UI
-# You _must_ define API_ALLOW_FROM, which is a comma separated list of IPs
-# An API key defined as API_KEY has read-write access
-# An API key defined as API_KEY_READ_ONLY has read-only access
-# Allowed chars for API_KEY and API_KEY_READ_ONLY: a-z, A-Z, 0-9, -
-# You can define API_KEY and/or API_KEY_READ_ONLY
-
-#API_KEY=
-#API_KEY_READ_ONLY=
-#API_ALLOW_FROM=172.22.1.1,127.0.0.1
-
-# mail_home is ~/Maildir
-MAILDIR_SUB=Maildir
-
-# SOGo session timeout in minutes
-SOGO_EXPIRE_SESSION=480
-
-# DOVECOT_MASTER_USER and DOVECOT_MASTER_PASS must both be provided. No special chars.
-# Empty by default to auto-generate master user and password on start.
-# User expands to DOVECOT_MASTER_USER@mailcow.local
-# LEAVE EMPTY IF UNSURE
-DOVECOT_MASTER_USER=
-# LEAVE EMPTY IF UNSURE
-DOVECOT_MASTER_PASS=
diff --git a/webserver/docker_mail/templates/mailman-nginx.conf b/webserver/docker_mail/templates/mailman-nginx.conf
new file mode 100644
index 0000000000000000000000000000000000000000..408ed688375938830043040f924c927180a82e36
--- /dev/null
+++ b/webserver/docker_mail/templates/mailman-nginx.conf
@@ -0,0 +1,25 @@
+
+server {
+
+    listen 80;
+    listen [::]:80;
+
+    server_name listserver.warpzone.ms;
+    root /dev/null;
+    index index.html;
+
+    location / {
+        # First attempt to serve request as file, then
+
+        uwsgi_pass mailman-web:8080;
+        include uwsgi_params;
+        uwsgi_read_timeout 300;
+    }
+
+	location /static  {
+ 
+        root /opt/mailman-web-data;
+
+    }
+
+}
\ No newline at end of file
diff --git a/webserver/docker_mail/templates/mailman.env b/webserver/docker_mail/templates/mailman.env
new file mode 100644
index 0000000000000000000000000000000000000000..7ade751389ef13db6a94193c0bd67c65314f6ace
--- /dev/null
+++ b/webserver/docker_mail/templates/mailman.env
@@ -0,0 +1,32 @@
+# Admin User 
+MAILMAN_ADMIN_USER=listadmin
+MAILMAN_ADMIN_EMAIL=listadmin@warpzone.ms
+
+# MTA to use 
+MTA=postfix
+
+# SMTP Host and Port 
+SMTP_HOST=smtp
+SMTP_PORT=25
+
+# External Domain for Mailman web Interface
+SERVE_FROM_DOMAIN={{ listserver }}
+
+# Mailman Secret Key 
+SECRET_KEY={{ mailman_secret_key }}
+
+# Database for mailman and Hyperkitty 
+DATABASE_URL=mysql://mailman:{{ mailman_db_pass }}@db/mailman?charset=utf8mb4
+
+# Internal hostname of the Mailman Core Container 
+MM_HOSTNAME=mailman-core
+
+# User and Password for Mailman API
+MAILMAN_REST_USER=mailman
+MAILMAN_REST_PASSWORD={{ mailman_restapi_pass }}
+
+# internal URL and API Key for Hyperkitty 
+HYPERKITTY_URL=http://mailman-web:8000/hyperkitty
+HYPERKITTY_API_KEY={{ hyperkitty_api_key }}
+
+
diff --git a/webserver/docker_mail/templates/mailu.env b/webserver/docker_mail/templates/mailu.env
new file mode 100644
index 0000000000000000000000000000000000000000..208d611ee04c26ba56a5dddb9dbf4fdf3414e61d
--- /dev/null
+++ b/webserver/docker_mail/templates/mailu.env
@@ -0,0 +1,181 @@
+###################################
+# Additional Setings 
+###################################
+
+# Set Version 
+MAILU_VERSION=2.0.37
+
+# enable IPv6
+SUBNET6=fd00:dead:beef:25::/64
+
+# Autocreate Admin User 
+INITIAL_ADMIN_ACCOUNT=mailadmin
+INITIAL_ADMIN_DOMAIN={{ domain }}
+INITIAL_ADMIN_PW={{ mailu_admin_pass }}
+INITIAL_ADMIN_MODE=ifmissing
+
+# force internel connect to rspamd with ipv4
+ANTISPAM_ADDRESS=192.168.203.253
+
+# Use Mysql as Database
+SQLALCHEMY_DATABASE_URI=mysql+mysqlconnector://mailu:{{ mailu_db_pass }}@db/mailu
+
+# Use Mysql as Database
+SQLALCHEMY_DATABASE_URI_ROUNDCUBE=mysql://roundcube:{{ roundcube_db_pass }}@db/roundcube
+
+###################################
+# Common configuration variables
+###################################
+
+# Set to a randomly generated 16 bytes string
+SECRET_KEY={{ mailu_secret_key }}
+
+# Subnet of the docker network. This should not conflict with any networks to which your system is connected. (Internal and external!)
+SUBNET=192.168.203.0/24
+
+# Main mail domain
+DOMAIN={{ domain }}
+
+# Hostnames for this server, separated with comas
+HOSTNAMES={{ mailserver }}
+
+# Postmaster local part (will append the main mail domain)
+POSTMASTER=admin
+
+# Choose how secure connections will behave (value: letsencrypt, cert, notls, mail, mail-letsencrypt)
+TLS_FLAVOR=mail
+
+# Authentication rate limit per IP (per /24 on ipv4 and /48 on ipv6)
+AUTH_RATELIMIT_IP=60/hour
+
+# Authentication rate limit per user (regardless of the source-IP)
+AUTH_RATELIMIT_USER=100/day
+
+# Opt-out of statistics, replace with "True" to opt out
+DISABLE_STATISTICS=True
+
+###################################
+# Optional features
+###################################
+
+# Expose the admin interface (value: true, false)
+ADMIN=true
+
+# Choose which webmail to run if any (values: roundcube, snappymail, none)
+WEBMAIL=roundcube
+
+# Expose the API interface (value: true, false)
+API=false
+
+# Dav server implementation (value: radicale, none)
+WEBDAV=none
+
+# Antivirus solution (value: clamav, none)
+ANTIVIRUS=none
+
+# Scan Macros solution (value: true, false)
+SCAN_MACROS=true
+
+###################################
+# Mail settings
+###################################
+
+# Message size limit in bytes
+# Default: accept messages up to 50MB
+# Max attachment size will be 33% smaller
+MESSAGE_SIZE_LIMIT=50000000
+
+# Message rate limit (per user)
+MESSAGE_RATELIMIT=200/day
+
+# Networks granted relay permissions
+# Use this with care, all hosts in this networks will be able to send mail without authentication!
+RELAYNETS=
+
+# Will relay all outgoing mails if configured
+RELAYHOST=
+
+# Enable fetchmail
+FETCHMAIL_ENABLED=False
+
+# Fetchmail delay
+FETCHMAIL_DELAY=600
+
+# Recipient delimiter, character used to delimiter localpart from custom address part
+# must be set to + for mailman
+RECIPIENT_DELIMITER=+
+
+# DMARC rua and ruf email
+DMARC_RUA=admin
+DMARC_RUF=admin
+
+# Welcome email, enable and set a topic and body if you wish to send welcome
+# emails to all users.
+WELCOME=false
+WELCOME_SUBJECT=Welcome to your new email account
+WELCOME_BODY=Welcome to your new email account, if you can read this, then it is configured properly!
+
+# Maildir Compression
+# choose compression-method, default: none (value: gz, bz2)
+COMPRESSION=
+# change compression-level, default: 6 (value: 1-9)
+COMPRESSION_LEVEL=
+
+# IMAP full-text search is enabled by default. Set the following variable to off in order to disable the feature.
+FULL_TEXT_SEARCH=on
+
+###################################
+# Web settings
+###################################
+
+# Path to redirect / to
+WEBROOT_REDIRECT=/webmail
+
+# Path to the admin interface if enabled
+WEB_ADMIN=/admin
+
+# Path to the webmail if enabled
+WEB_WEBMAIL=/webmail
+
+# Path to the API interface if enabled
+WEB_API=
+
+# Website name
+SITENAME=warpzone mail
+
+# Linked Website URL
+WEBSITE=https://listserver.{{ domain }}
+
+
+
+###################################
+# Advanced settings
+###################################
+
+# Docker-compose project name, this will prepended to containers names.
+COMPOSE_PROJECT_NAME=mailu
+
+# Number of rounds used by the password hashing scheme
+CREDENTIAL_ROUNDS=12
+
+# Header to take the real ip from
+REAL_IP_HEADER=X-Real-Ip
+
+# IPs for nginx set_real_ip_from (CIDR list separated by commas)
+REAL_IP_FROM=0.0.0.0/0
+
+# choose wether mailu bounces (no) or rejects (yes) mail when recipient is unknown (value: yes, no)
+REJECT_UNLISTED_RECIPIENT=
+
+# Log level threshold in start.py (value: CRITICAL, ERROR, WARNING, INFO, DEBUG, NOTSET)
+LOG_LEVEL=WARNING
+
+# Timezone for the Mailu containers. See this link for all possible values https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
+TZ=Europe/Berlin
+
+# Default spam threshold used for new users
+DEFAULT_SPAM_THRESHOLD=80
+
+# API token required for authenticating to the RESTful API.
+# This is a mandatory setting for using the RESTful API.
+API_TOKEN={{ mailu_api_token }}
diff --git a/webserver/docker_mail/templates/mailu/overrides/postfix/postfix.cf b/webserver/docker_mail/templates/mailu/overrides/postfix/postfix.cf
new file mode 100644
index 0000000000000000000000000000000000000000..7c0123e79805c85732436ebb7c34c66ec48de90c
--- /dev/null
+++ b/webserver/docker_mail/templates/mailu/overrides/postfix/postfix.cf
@@ -0,0 +1,14 @@
+
+# Overrides for mailman3 integration 
+# see https://patrick.georgi.family/2019/01/12/combining-mailman-3-with-mailu/
+
+always_add_missing_headers = yes
+append_at_myorigin=no
+append_dot_mydomain=no
+local_header_rewrite_clients = permit_sasl_authenticated
+owner_request_special = no
+unknown_local_recipient_reject_code = 550
+
+local_recipient_maps = regexp:/opt/mailman/postfix_lmtp
+transport_maps = regexp:/opt/mailman/postfix_lmtp, lmdb:/etc/postfix/transport.map, \${podop}transport
+virtual_mailbox_maps = regexp:/opt/mailman/postfix_lmtp, \${podop}mailbox
diff --git a/webserver/docker_mail/templates/mailu/overrides/postfix/transport.map b/webserver/docker_mail/templates/mailu/overrides/postfix/transport.map
new file mode 100644
index 0000000000000000000000000000000000000000..80a3d9e5e568fa2a380ebef229108794d66574f2
--- /dev/null
+++ b/webserver/docker_mail/templates/mailu/overrides/postfix/transport.map
@@ -0,0 +1,9 @@
+yahoo.com	polite:
+hotmail.com	polite:
+outlook.com	polite:
+exchange.com	polite:
+microsoft.com	polite:
+1und1.de	polite:
+t-online.de	polite:
+web.de		polite:
+gmail.com	polite:
diff --git a/webserver/docker_matrix/tasks/main.yml b/webserver/docker_matrix/tasks/main.yml
index 990d843ee8d0f0a4dc436db788f39a2e68b3e0e4..27dc2fdaa156cef1d9699c849984ec3bff03650d 100644
--- a/webserver/docker_matrix/tasks/main.yml
+++ b/webserver/docker_matrix/tasks/main.yml
@@ -5,6 +5,7 @@
    - { path: /srv/shared/noreply_email_pass, length: -1 }
    - { path: /srv/ldap/secret/ldap_readonly_pass, length: -1 }
    - { path: /srv/matrix/postgres_user_pass,  length: 24 }
+   - { path: /srv/matrix/admin_access_token,  length: -1 } # Get in Element fo an Admin User: Settings > Help > Advanced 
 
 
 - name: create folder struct for matrix
@@ -31,7 +32,9 @@
 
 
 - name: Konfig-Dateien erstellen
-  template: src={{ item }} dest=/srv/matrix/{{ item }}
+  template: 
+    src: "{{ item }}" 
+    dest: "/srv/matrix/{{ item }}"
   with_items:
     - docker-compose.yml
     - rest_auth_provider.py
@@ -41,13 +44,22 @@
   register: configs
 
 
+- name: Script-Dateien erstellen 
+  template: 
+    src: "{{ item }}" 
+    dest: "/srv/matrix/{{ item }}"
+    mode: "ug+rwx"
+  with_items:
+    - purgemediacache.sh
+
+
 - name: stop matrix docker
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: /srv/matrix/
     state: absent
   when: configs.changed
 
 - name: start matrix docker
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: /srv/matrix/
     state: present
diff --git a/webserver/docker_matrix/templates/docker-compose.yml b/webserver/docker_matrix/templates/docker-compose.yml
index 25c55decf8bf27258a59802ff2ea7834a68f2e77..ea93fd0ebc9091b62b9c6669d74b48422d8ea6cd 100644
--- a/webserver/docker_matrix/templates/docker-compose.yml
+++ b/webserver/docker_matrix/templates/docker-compose.yml
@@ -8,9 +8,12 @@ services:
   # Datenbank einlesen nach Upgrade (im Container)
   # psql -U synapse -d synapse < /var/lib/postgresql/data/dump.sql
 
+  # Alternativer weg mit inplace-Upgrade (funktioniert nicht)
+  # https://github.com/tianon/docker-postgres-upgrade
+
   db:
 
-    image: postgres:13.6
+    image: postgres:16
     restart: always
     volumes:
       - /srv/matrix/db:/var/lib/postgresql/data
@@ -24,7 +27,7 @@ services:
 
   synapse:
 
-    image: matrixdotorg/synapse:v1.78.0
+    image: matrixdotorg/synapse:latest
     restart: always
     cpu_count: "1"
     cpuset: "0"
@@ -50,7 +53,6 @@ services:
       - traefik.http.services.matrix_federation.loadbalancer.server.port=8448
     networks:
       - default
-      - mail
       - web
 
   ma1sd:
@@ -61,6 +63,7 @@ services:
       - /srv/matrix/ma1sd-config/:/etc/ma1sd
       - /srv/matrix/ma1sd-data/:/var/ma1sd
     labels:
+      - com.centurylinklabs.watchtower.enable=false
       - traefik.enable=true
       - traefik.http.routers.{{ servicename }}-ma1sd.rule=((Host(`{{ domain }}`) && PathPrefix(`/_matrix/client/r0/login`)) || (Host(`{{ domain }}`) && PathPrefix(`/_matrix/identity`)))
       - traefik.http.routers.{{ servicename }}-ma1sd.entrypoints=websecure
@@ -69,8 +72,21 @@ services:
       - default
       - web
 
+
+  purgemediacache:
+    
+    image: jsonfry/curl-cron:latest 
+    restart: always
+    depends_on:
+      - synapse
+    volumes:
+      - /srv/matrix/purgemediacache.sh:/curl.sh
+    environment:
+      CRON_SCHEDULE: "0 7 * * *"
+    networks:
+      - default
+
+
 networks:
-  mail:
-    external: true
   web:
     external: true
diff --git a/webserver/docker_matrix/templates/purgemediacache.sh b/webserver/docker_matrix/templates/purgemediacache.sh
new file mode 100644
index 0000000000000000000000000000000000000000..bd3f4f3e08117291b0acf9e756e7965cc9e70b32
--- /dev/null
+++ b/webserver/docker_matrix/templates/purgemediacache.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+set -e
+
+echo "$(date) - Start"
+
+TS_NOW=$(date +%s)
+DELAY=$((30*24*60*60))
+TS=$((TS_NOW-$DELAY))
+
+curl -X POST --insecure --header "Authorization: Bearer {{ admin_access_token }}" https://{{ domain }}/_synapse/admin/v1/purge_media_cache?before_ts=$(($TS*1000))
+
+echo "$(date) End"
\ No newline at end of file
diff --git a/webserver/docker_matrix/templates/synapse-data/homeserver.yaml b/webserver/docker_matrix/templates/synapse-data/homeserver.yaml
index 94ac867e259b51fa223a9ffbb3ffa5e1ef4abbac..93813866e74f62ffc18298e85b73cf81e0581264 100644
--- a/webserver/docker_matrix/templates/synapse-data/homeserver.yaml
+++ b/webserver/docker_matrix/templates/synapse-data/homeserver.yaml
@@ -4,6 +4,7 @@ public_baseurl: "{{ matrix.public_url }}/"
 use_presence: false
 allow_public_rooms_without_auth: false
 allow_public_rooms_over_federation: true
+forget_rooms_on_leave: true
 
 listeners:
   - port: 8448
@@ -94,10 +95,12 @@ trusted_key_servers:
   - server_name: "matrix.org"
 
 email:
-  smtp_host: postfix
-  smtp_port: 25
+  smtp_host: {{ smtp_host }}
+  smtp_port: {{ smtp_port }}
+  smtp_user: "{{ noreply_email_user }}"
+  smtp_pass: "{{ noreply_email_pass }}"
   require_transport_security: false
-  notif_from: "Your Friendly warpzone Matrix homeserver <{{ noreply_email_user }}>"
+  notif_from: "Warpzone Matrix <matrix@{{ smtp_domain }}>"
   enable_notifs: true
   notif_for_new_users: False
 
diff --git a/webserver/docker_matterbridge/tasks/main.yml b/webserver/docker_matterbridge/tasks/main.yml
index 08b5520d67cd62ff425616efab90e006b907fbf2..b22fb98f95540f4b91e9daf91533fc2ea273b91f 100644
--- a/webserver/docker_matterbridge/tasks/main.yml
+++ b/webserver/docker_matterbridge/tasks/main.yml
@@ -50,7 +50,7 @@
     dest: "/srv/matterbridge/docker-compose.yml"
   
 - name: start matterbridge docker
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: /srv/matterbridge/
     state: present
   
diff --git a/webserver/docker_matterbridge/templates/docker-compose.yml b/webserver/docker_matterbridge/templates/docker-compose.yml
index 382867034c559f35a51e1aee6533a81c70f4db48..a6de5dc7f788a1de0e8e2932b38a59ee3ff1bc9a 100644
--- a/webserver/docker_matterbridge/templates/docker-compose.yml
+++ b/webserver/docker_matterbridge/templates/docker-compose.yml
@@ -5,7 +5,7 @@ services:
 
   cw:
 
-    image: 42wim/matterbridge:1.25
+    image: 42wim/matterbridge:latest
     restart: always
     volumes:
       - /srv/matterbridge/etc/matterbridge_cw.toml:/matterbridge.toml:ro
@@ -16,7 +16,7 @@ services:
 
   wz:
 
-    image: 42wim/matterbridge:1.25
+    image: 42wim/matterbridge:latest
     restart: always
     volumes:
       - /srv/matterbridge/etc/matterbridge_wz.toml:/matterbridge.toml:ro
@@ -27,7 +27,7 @@ services:
 
   web:
 
-    image: nginx:1.21.6-alpine
+    image: nginx:latest
     restart: always
     volumes:
       - /srv/matterbridge/media/:/usr/share/nginx/html/matterbridge/:ro,z
@@ -45,7 +45,7 @@ services:
 
   restarter:
     
-    image: docker:20.10
+    image: docker:25.0
     restart: always
     command: [ "/bin/sh", "-c", "while true; do sleep 1h; docker restart matterbridge_cw_1; docker restart matterbridge_wz_1; done" ]
     volumes: 
diff --git a/webserver/docker_matterbridge/templates/matterbridge_wz.toml b/webserver/docker_matterbridge/templates/matterbridge_wz.toml
index f682d81ede987a14c546ad9f98fd652b8ffeb50b..1d90082072f8aaedf32947d394a682c2b50a649c 100644
--- a/webserver/docker_matterbridge/templates/matterbridge_wz.toml
+++ b/webserver/docker_matterbridge/templates/matterbridge_wz.toml
@@ -1,4 +1,3 @@
-
 ###################################################################
 #IRC section
 ###################################################################
@@ -208,9 +207,13 @@ enable=true
     ## 8.8.2017 von void deaaktiviert das das Spammen im Telegram Leute genervt hat
     ## 24.4.2018 für die spamfreie warpzone Gruppe wieder aktiviert (Beschluss Plenum)
     ## Vorgehen um Guppen-ID zu bekommen:
+    ## - Eine Nachricht aus dem Chat an @JsonDumpBot weiterleiten
+    ## - Die ID steht in "forward_from_chat"->"id"
+    ## Alte Vorgehensweise um die Gruppen-ID zu erhalten
     ## - Bot in Gruppe einfügen
     ## - Chatnachricht erstellen  
     ## - https://api.telegram.org/<API Token>/getUpdates ausrufen, die ID findet sich in der Eigenschaft "message.chat.id"
+    ## Check Gruppen-ID: https://api.telegram.org/bot<TOKEN>/getChat?chat_id=<CHAT ID>
     account="telegram.bot"
     channel="-272574265" 
 
@@ -218,3 +221,22 @@ enable=true
     ## Raum auf dem Warpzone Matrix Server 
     account="matrix.warpzone"
     channel="#warpzone-bridge:{{ matrix.domain }}"
+
+
+[[gateway]]
+#OPTIONAL (not used for now)
+name="gateway2"
+#Enable enables this gateway
+##OPTIONAL (default false)
+enable=true
+
+    [[gateway.inout]]
+    ## Telegramm Gruppe "Family Hacking Warpzone"
+    account="telegram.bot"
+    channel="-4193835577"
+
+    [[gateway.inout]]
+    ## Raum auf dem Warpzone Matrix Server
+    account="matrix.warpzone"
+    channel="#familyhacking:matrix.warpzone.ms"
+
diff --git a/webserver/docker_vpnserver/tasks/main.yml b/webserver/docker_vpnserver/tasks/main.yml
index 9d49fd746bc4d77da71b6599217a0425a81e6031..f5db7127b2ba3a44a88ce4298e37ce10d0a215ff 100644
--- a/webserver/docker_vpnserver/tasks/main.yml
+++ b/webserver/docker_vpnserver/tasks/main.yml
@@ -25,13 +25,13 @@
 
 
 - name: "stop {{ servicename }} docker"
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: "{{ basedir }}"
     state: absent
   when: config.changed
 
 
 - name: "start {{ servicename }} docker"
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: "{{ basedir }}"
     state: present
diff --git a/webserver/docker_vpnserver/templates/docker-compose.yml b/webserver/docker_vpnserver/templates/docker-compose.yml
index d3ee2382f408b6aae4b1ebdd7a9c6853d611613b..2c6364cd5ac44d22ee6fa0fc0f4b5ba5f21f5f57 100644
--- a/webserver/docker_vpnserver/templates/docker-compose.yml
+++ b/webserver/docker_vpnserver/templates/docker-compose.yml
@@ -3,7 +3,7 @@ version: "3"
 services:
 
   app:
-    image: ghcr.io/freifunkmuc/wg-access-server:v0.8.2
+    image: ghcr.io/freifunkmuc/wg-access-server:latest
     restart: always
     cap_add:
       - NET_ADMIN
diff --git a/webserver/docker_warpapi/tasks/main.yml b/webserver/docker_warpapi/tasks/main.yml
index dbda040c910feefc0350690ddcebf9222f277da9..5f47685a43315631247882140591b12044ebb026 100644
--- a/webserver/docker_warpapi/tasks/main.yml
+++ b/webserver/docker_warpapi/tasks/main.yml
@@ -9,18 +9,6 @@
     path: "/srv/warpapi"
     state: "directory"
 
-- name: clone repo
-  git:
-    repo: "https://gitlab.warpzone.ms/infrastruktur/warpapi.git"
-    version: "b84d10e8882da98c2a6a71f6995cfaeb7a051c79"
-    dest: "/srv/warpapi"
-    force: "yes"
-  register: gitclone
-
-- name: clone repo status
-  debug:
-    msg: "{{gitclone}}"
-
 - name: Helper-Scripte erstellen
   template:
     src: "{{ item }}"
@@ -36,6 +24,6 @@
     dest: "/srv/warpapi/docker-compose.yml"
 
 - name: start warpapi docker
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: /srv/warpapi/
     state: present
diff --git a/webserver/docker_warpapi/templates/docker-compose.yml b/webserver/docker_warpapi/templates/docker-compose.yml
index e75908179941fe04a2f7072d68b942739a2c732b..fbcfae2097abee1779f432ccbebac59f1beb543f 100644
--- a/webserver/docker_warpapi/templates/docker-compose.yml
+++ b/webserver/docker_warpapi/templates/docker-compose.yml
@@ -1,27 +1,24 @@
 version: "3"
 
 services:
-  
+
   app:
 
-    build: .
-    image: warpapi:{{ gitclone.after }}
+    image: gitlab-registry.warpzone.ms/infrastruktur/warpapi:latest
     restart: always
     ports:
       - 127.0.0.1:42010:5000
-    volumes:
-      - /srv/warpapi/warpapi/:/opt/warpapi
     environment:
-      UPDATE_KEY: "{{ update_key }}" 
+      UPDATE_KEY: "{{ update_key }}"
     labels:
       - traefik.enable=true
       - traefik.http.routers.{{ servicename }}.rule=Host(`{{ domain }}`)
       - traefik.http.routers.{{ servicename }}.entrypoints=websecure
       - traefik.http.services.{{ servicename }}.loadbalancer.server.port=5000
     networks:
-      - default      
-      - web  
+      - default
+      - web
 
 networks:
   web:
-    external: true    
+    external: true
diff --git a/webserver/docker_wordpress/tasks/main.yml b/webserver/docker_wordpress/tasks/main.yml
index 6e69e0641df98b3452eef4e7ea356b92d8d8c4aa..0f207950a08fce9bd0b9232f3dd7500b250c343b 100644
--- a/webserver/docker_wordpress/tasks/main.yml
+++ b/webserver/docker_wordpress/tasks/main.yml
@@ -2,6 +2,7 @@
 
 - include_tasks: ../functions/get_secret.yml
   with_items:
+   - { path: /srv/shared/noreply_email_pass, length: -1 } 
    - { path: /srv/wordpress/mysql_root_pass,  length: 24 }
    - { path: /srv/wordpress/mysql_user_pass,  length: 12 }
 
@@ -28,6 +29,6 @@
     - data/wp-content/plugins/wz-status/wz-status.php
 
 - name: start wordpress docker
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: /srv/wordpress/
     state: present
diff --git a/webserver/docker_wordpress/templates/Dockerfile b/webserver/docker_wordpress/templates/Dockerfile
index 36579bd894c7126a6de771c8f8c29ee27ba5df39..1c41da02f4c43761b8e7f8e4639d7314a7390b4a 100644
--- a/webserver/docker_wordpress/templates/Dockerfile
+++ b/webserver/docker_wordpress/templates/Dockerfile
@@ -1,4 +1,4 @@
-FROM wordpress:6.1.1-php8.2-apache
+FROM wordpress:6.4.2-apache
 
 # install the PHP extensions we need
 RUN set -x \
diff --git a/webserver/docker_wordpress/templates/docker-compose.yml b/webserver/docker_wordpress/templates/docker-compose.yml
index a6e9313da60b0f7c016f619838a3085f5b6d06f2..117d151d61820427e8be9f76d29fc542305c0d2c 100644
--- a/webserver/docker_wordpress/templates/docker-compose.yml
+++ b/webserver/docker_wordpress/templates/docker-compose.yml
@@ -5,7 +5,7 @@ services:
 
   db:
 
-    image: mariadb:10.7.1
+    image: mariadb:11
     restart: always
     volumes:
       - /srv/wordpress/db/:/var/lib/mysql
@@ -18,7 +18,7 @@ services:
       - default
 
   app:
-
+    # values set in configuration: noreply_email_user - noreply_email_pass - smtp_host - smtp_port 
     build: .
     restart: always
     volumes:
@@ -29,17 +29,15 @@ services:
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD: "{{ mysql_user_pass }}"
     labels:
+      - com.centurylinklabs.watchtower.enable=false
       - traefik.enable=true
       - traefik.http.routers.{{ servicename }}.rule=Host(`{{ domain }}`)
       - traefik.http.routers.{{ servicename }}.entrypoints=websecure
       - traefik.http.services.{{ servicename }}.loadbalancer.server.port=80
     networks:
       - default
-      - mail
       - web
 
 networks:
-  mail:
-    external: true
   web:
     external: true
diff --git a/webserver/docker_workadventure/tasks/main.yml b/webserver/docker_workadventure/tasks/main.yml
index af8e009cca6559323cb26dac50d14f3cc7f0c9bf..2e494a4b3b7479203eabad4ea1d84eaca39078f5 100644
--- a/webserver/docker_workadventure/tasks/main.yml
+++ b/webserver/docker_workadventure/tasks/main.yml
@@ -24,12 +24,12 @@
   register: config
 
 - name: "stop {{servicename}} docker"
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: /srv/{{servicename}}/
     state: absent
   when: config.changed
 
 - name: "start {{servicename}} docker"
-  docker_compose:
+  community.docker.docker_compose_v2:
     project_src: /srv/{{servicename}}/
     state: present
diff --git a/webserver/docker_workadventure/templates/docker-compose.yml b/webserver/docker_workadventure/templates/docker-compose.yml
index ef95316c89ac40abe36045be097fad8cbc2547dd..980767a7edef0d0580fd385389a72d6fddfa0c21 100644
--- a/webserver/docker_workadventure/templates/docker-compose.yml
+++ b/webserver/docker_workadventure/templates/docker-compose.yml
@@ -79,7 +79,7 @@ services:
 
 
   icon:
-    image: matthiasluedtke/iconserver:v3.13.0
+    image: matthiasluedtke/iconserver:v3.16.0
     restart: always
     labels:
       - traefik.enable=true
@@ -92,7 +92,7 @@ services:
 
 
   redis:
-    image: redis:6.2.6
+    image: redis:7.2.4
     restart: always
     networks:
       - default