diff --git a/defaults/main.yml b/defaults/main.yml
deleted file mode 100644
index 0e8cadf83d5be82545ce8d89504220b746c41036..0000000000000000000000000000000000000000
--- a/defaults/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-
-alerta_ui_version: 7.0.1
diff --git a/handlers/main.yml b/handlers/main.yml
index 4aece8a73c6766714ea6622dda362440a6f90ac4..39a23dc9f8bdbcd2a1b8527a73b82daa8cec263b 100644
--- a/handlers/main.yml
+++ b/handlers/main.yml
@@ -1,18 +1,6 @@
 ---
 
-- name: Restart uwsgi
-  service:
-    name: uwsgi
-    state: restarted
-
-- name: Re-create the alerta ui container
-  docker_container:
-    name: alerta-beta
-    image: alerta/alerta-beta
-    state: started
-    recreate: yes
-    restart_policy: always
-    published_ports:
-      - 8999:80
-    volumes:
-      - /var/www/alerta/config.json:/usr/share/nginx/html/config.json
+- name: Re-create Docker Network and Containers
+  docker_compose:
+    project_src: /opt/alerta
+    build: yes
diff --git a/meta/main.yml b/meta/main.yml
index 5d68df995e782ae241ec92d4643d50cf585ad22b..94231559d86f102c4b5f48a6a0e6e0e4d6c00fe1 100644
--- a/meta/main.yml
+++ b/meta/main.yml
@@ -12,5 +12,6 @@ galaxy_info:
         - 16
         - 18
 dependencies:
-  - { role: mongodb }
-  - { role: nginx }
+  - role: apache
+  - role: docker
+  - role: letsencrypt
diff --git a/tasks/alerta.yml b/tasks/alerta.yml
index 8547c43214940208ef190020fa5ae53794c68c24..11bbeecd3c29bdff32e76ae94d6e6dfe993604ba 100644
--- a/tasks/alerta.yml
+++ b/tasks/alerta.yml
@@ -1,161 +1,75 @@
 ---
 # file: roles/alerta/tasks/alerta.yml
 
-- name: Ensure packages
-  apt:
-    pkg: '{{ packages }}'
-    state: present
-  vars:
-    packages:
-      - python-pip
-      - python-dev
-      - python3-dev
-      - libpq-dev
-
-- name: Ensure PIP packages
-  pip:
-    name: '{{ packages }}'
-    state: present
-  vars:
-    packages:
-      - alerta-server
-      - alerta
-      - uwsgi
-      - python-gitlab
-
-- name: Remove directories for web UI
-  file:
-    path: '{{ item }}'
-    state: absent
-  with_items:
-    - /var/www/alerta
-    - /tmp/angular-alerta-webui-master
-
-- name: Ensure directory for web UI
+- name: Ensure directory
   file:
     path: '{{ item }}'
-    state: absent
+    state: directory
   with_items:
-    - /var/www/alerta
-
-#- name: Download and extract web UI
-#  unarchive:
-#    src: 'https://github.com/alerta/angular-alerta-webui/archive/v{{ alerta_ui_version }}.zip'
-#    dest: /tmp
-#    remote_src: yes
-
-#- name: Move new web UI
-#  command: mv /tmp/angular-alerta-webui-{{ alerta_ui_version }}/app /var/www/alerta
-#  args:
-#    creates: /var/www/alerta
-#    removes: /tmp/angular-alerta-webui-{{ alerta_ui_version }}/app
-
-- name: Copy wsgi.py
-  template:
-    src: wsgi.py
-    dest: /var/www/alerta/wsgi.py
-
-- name: Copy uwsgi.ini
-  template:
-    src: uwsgi.ini
-    dest: /etc/uwsgi.ini
-
-- name: Copy uwsgi.service
-  template:
-    src: uwsgi.service
-    dest: /etc/systemd/system/uwsgi.service
-
-- name: Prepare uwsgi for autostart
-  systemd:
-    name: uwsgi
-    state: restarted
-    enabled: yes
-    daemon_reload: yes
-
-- name: Copy nginx default config
-  template:
-    src: nginx.default
-    dest: /etc/nginx/sites-available/default
-  notify:
-    - Restart nginx
+    - /opt/alerta/api/plugins
+    - /opt/alerta/webui
 
-- name: Copy config.js
+- name: Copy Alerta config files
   template:
     src: '{{ item }}'
-    dest: /var/www/alerta/{{ item }}
+    dest: /opt/alerta/{{ item }}
   with_items:
-    - config.js
-    - config.json
+    - docker-compose.yml
+  notify:
+    - Re-create Docker Network and Containers
 
-- name: Copy alertad.conf
+- name: Copy API config files
   template:
-    src: alertad.conf
-    dest: /etc/alertad.conf
+    src: api/{{ item }}
+    dest: /opt/alerta/api/{{ item }}
+  with_items:
+    - alerta.conf
+    - alertad.conf
+    - Dockerfile
   notify:
-    - Restart uwsgi
+    - Re-create Docker Network and Containers
 
-- name: Configure root CLI
+- name: Copy Web UI config files
   template:
-    src: alerta.conf
-    dest: /root/.alerta.conf
-
-- name: Configure crontabs
-  cron:
-    name: '{{ item.name }}'
-    minute: '{{ item.minute }}'
-    job: '{{ item.job }} >/dev/null 2>&1'
-    disabled: '{{ crons_disabled|default(false) }}'
+    src: webui/{{ item }}
+    dest: /opt/alerta/webui/{{ item }}
   with_items:
-    - name: Heartbeats to Alert
-      minute: '*/3'
-      job: /usr/local/bin/alerta heartbeats --alert
-    - name: Alerta Housekeeping
-      minute: 0
-      job: /usr/local/bin/alerta housekeeping
-  tags:
-    - cron
+    - .env
+    - config.json
+    - nginx.conf
+    - Dockerfile
+  notify:
+    - Re-create Docker Network and Containers
 
 - name: Copy plugins
   template:
-    src: '{{ item }}/plugin.py'
-    dest: /tmp/alerta_{{ item }}.py
+    src: plugins/{{ item }}/plugin.py
+    dest: /opt/alerta/api/plugins/alerta_{{ item }}.py
   with_items:
     - elastalert
     - gitlab
-  tags:
-    - plugin
+  notify:
+    - Re-create Docker Network and Containers
 
 - name: Copy plugin setups
   template:
-    src: '{{ item }}/setup.py'
-    dest: /tmp/setup_alerta_{{ item }}.py
-  with_items:
-    - elastalert
-    - gitlab
-  tags:
-    - plugin
-
-- name: Install plugins
-  command: python3 setup_alerta_{{ item }}.py install
-  args:
-    chdir: /tmp
+    src: plugins/{{ item }}/setup.py
+    dest: /opt/alerta/api/plugins/setup_alerta_{{ item }}.py
   with_items:
     - elastalert
     - gitlab
-  tags:
-    - plugin
-
-- name: Copy favicon.ico
-  copy:
-    src: '{{ inventory_dir }}/files/favicon.ico'
-    dest: /var/www/alerta/favicon.ico
+  notify:
+    - Re-create Docker Network and Containers
 
 - name: Pull docker image
   docker_image:
-    name: alerta/alerta-beta
+    name: "{{ item }}"
     source: pull
     force_source: yes
+  with_items:
+    - alerta/alerta-web
+    - node:lts-alpine
+    - nginx:stable-alpine
+    - postgres
   notify:
-    - Re-create the alerta ui container
-  tags:
-    - ui
+    - Re-create Docker Network and Containers
diff --git a/tasks/apache.yml b/tasks/apache.yml
new file mode 100644
index 0000000000000000000000000000000000000000..fa42effac38411fdb2b4369219d9dd5029dd54e9
--- /dev/null
+++ b/tasks/apache.yml
@@ -0,0 +1,33 @@
+---
+# file: roles/alerta/tasks/apache.yml
+
+- name: Set facts
+  set_fact:
+    apacheUser: www-data
+
+- name: Apache Modules
+  apache2_module:
+    state: present
+    name: '{{ item }}'
+  with_items:
+    - proxy
+    - proxy_http
+  notify:
+    - Restart Apache
+
+- name: Apache Configuration File
+  template:
+    src: vhost.conf
+    dest: /etc/apache2/sites-available/alerta{{ apache_conf_ext }}
+    owner: root
+    group: root
+    mode: 0664
+  notify:
+    - Restart Apache
+
+- name: Apache enable site
+  command: a2ensite alerta
+  args:
+    creates: /etc/apache2/sites-enabled/alerta{{ apache_conf_ext }}
+  notify:
+    - Restart Apache
diff --git a/tasks/main.yml b/tasks/main.yml
index 2fa34e838d0952635ec90fb88d7f8ab017dd836a..38031ad8881ba36c3bb563c1af3ca750e6f3b897 100644
--- a/tasks/main.yml
+++ b/tasks/main.yml
@@ -12,6 +12,19 @@
     - always
 
 - block:
+    - name: Install Certs
+      include_tasks: ../../letsencrypt/tasks/cert.yml
+      with_items: '{{ alerta_settings|default([]) }}'
+      loop_control:
+        loop_var: domain
+      when: domain.protocol|default("https") == "https" and domain.letsencrypt|default(true)
+
+  when: (not excluded_roles or "letsencrypt" not in excluded_roles) and groups.proxyserver is not defined
+
+- block:
+
+    - name: Import apache
+      import_tasks: apache.yml
 
     - name: Import alerta
       import_tasks: alerta.yml
diff --git a/templates/api/Dockerfile b/templates/api/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..b85cd06157ecfe8d60229a590b05774277614557
--- /dev/null
+++ b/templates/api/Dockerfile
@@ -0,0 +1,10 @@
+FROM alerta/alerta-web
+
+USER root
+COPY ./plugins/*.py /tmp/plugins/
+RUN /venv/bin/pip install python-gitlab && \
+    /venv/bin/python3 /tmp/plugins/setup_alerta_gitlab.py install && \
+    /venv/bin/python3 /tmp/plugins/setup_alerta_elastalert.py install && \
+    echo "Done"
+
+USER 1001
diff --git a/templates/alerta.conf b/templates/api/alerta.conf
similarity index 100%
rename from templates/alerta.conf
rename to templates/api/alerta.conf
diff --git a/templates/alertad.conf b/templates/api/alertad.conf
similarity index 85%
rename from templates/alertad.conf
rename to templates/api/alertad.conf
index fafcda8f105914b0692bbc369fdd801be2b5bb17..2034192ae81021c9181dc24ca9e8c24857693d36 100644
--- a/templates/alertad.conf
+++ b/templates/api/alertad.conf
@@ -1,4 +1,5 @@
 BASE_URL='https://{{ alerta_domain }}/api'
+USE_PROXYFIX=True
 AUTH_REQUIRED=True
 AUTH_PROVIDER='gitlab'
 SECRET_KEY='{{ alerta_secret_key }}'
@@ -12,7 +13,7 @@ OAUTH2_CLIENT_SECRET='{{ alerta_gitlab.client_secret }}'
 ALLOWED_GITLAB_GROUPS=['{{ alerta_environments|join("','") }}']
 
 # Plugins
-PLUGINS=['reject','gitlab','elastalert']
+PLUGINS=['reject','blackout','normalise','enhance','gitlab','elastalert']
 ORIGIN_BLACKLIST=[]
 ALLOWED_ENVIRONMENTS=['{{ alerta_environments|join("','") }}']
 ACTIONS = ['createIssue']
diff --git a/templates/docker-compose.yml b/templates/docker-compose.yml
index 2f64c987415cce2870731c0c12f5149644fc0b17..8b9de03631a65435f0e88d5102b837977600c6e0 100644
--- a/templates/docker-compose.yml
+++ b/templates/docker-compose.yml
@@ -1,20 +1,35 @@
-version: '2.1'
+version: '3.7'
 services:
-  web:
-    image: alerta/alerta-web
+  webui:
+    build:
+      context: webui
+    ports:
+      - "8092:80"
+    depends_on:
+      - api
+    networks:
+      net:
+        aliases:
+          - web
+    restart: always
+  api:
+    build:
+      context: api
     ports:
       - "8091:8080"
     depends_on:
       - db
     volumes:
-      - ./config/alerta.conf:/app/alerta.conf
-      - ./config/alertad.conf:/app/alertad.conf
-      - ./config/config.json:/web/config.json
-      - ./plugins/gitlab.py:/venv/lib/python3.7/site-packages/alerta/plugins/gitlab.py
+      - ./api/alerta.conf:/app/alerta.conf
+      - ./api/alertad.conf:/app/alertad.conf
     environment:
       - DATABASE_URL=postgres://postgres:postgres@db:5432/monitoring
-      - BASE_URL=https://alerta.lakedrops.com/api
+      - BASE_URL=https://{{ alerta_domain }}/api
       - ALERTA_CONF_FILE=/app/alerta.conf
+    networks:
+      net:
+        aliases:
+          - api
     restart: always
   db:
     image: postgres
@@ -24,4 +39,11 @@ services:
       POSTGRES_DB: monitoring
       POSTGRES_USER: postgres
       POSTGRES_PASSWORD: postgres
+    networks:
+      net:
+        aliases:
+          - db
     restart: always
+
+networks:
+  net: {}
diff --git a/templates/elastalert/plugin.py b/templates/plugins/elastalert/plugin.py
similarity index 100%
rename from templates/elastalert/plugin.py
rename to templates/plugins/elastalert/plugin.py
diff --git a/templates/elastalert/setup.py b/templates/plugins/elastalert/setup.py
similarity index 95%
rename from templates/elastalert/setup.py
rename to templates/plugins/elastalert/setup.py
index b7fd2fa9f11b42fb295a628227e6e4335972e2f9..fe868b15a8e0d4e912b6db1e2b8ae1d9b352f517 100644
--- a/templates/elastalert/setup.py
+++ b/templates/plugins/elastalert/setup.py
@@ -9,7 +9,7 @@ setup(
     description='LakeDrops Alerta plugin for incoming alerts from Elastalert',
     url='https://gitlab.lakedrops.com/ansible-roles/alerta',
     license='MIT',
-    author='Jürgen Haas',
+    author='Juergen Haas',
     author_email='juergen.haas@lakedrops.com',
     packages=find_packages(),
     py_modules=['alerta_elastalert'],
diff --git a/templates/gitlab/plugin.py b/templates/plugins/gitlab/plugin.py
similarity index 100%
rename from templates/gitlab/plugin.py
rename to templates/plugins/gitlab/plugin.py
diff --git a/templates/gitlab/setup.py b/templates/plugins/gitlab/setup.py
similarity index 95%
rename from templates/gitlab/setup.py
rename to templates/plugins/gitlab/setup.py
index 7988d32b195c7a4a63d491a897c5f506c0ce00a8..782e9963fbf60b6ffd64a421ec40b81c458e7e09 100644
--- a/templates/gitlab/setup.py
+++ b/templates/plugins/gitlab/setup.py
@@ -9,7 +9,7 @@ setup(
     description='LakeDrops Alerta plugin for GitLab Issues',
     url='https://gitlab.lakedrops.com/ansible-roles/alerta',
     license='MIT',
-    author='Jürgen Haas',
+    author='Juergen Haas',
     author_email='juergen.haas@lakedrops.com',
     packages=find_packages(),
     py_modules=['alerta_gitlab'],
diff --git a/templates/vhost.conf b/templates/vhost.conf
index 04610996c5c8c4c1eae69cbb2a3fd8e4ecf8312f..2d466e18a971f839490ed2198b188bc2afce245d 100644
--- a/templates/vhost.conf
+++ b/templates/vhost.conf
@@ -2,59 +2,48 @@
   Include /etc/apache2/conf-available/global-redirect.conf
 
   ServerAdmin webmaster@paragon-es.de
-  ServerName  alerta.lakedrops.com
+  ServerName  {{ alerta_domain }}
 
   Include /etc/apache2/conf-available/redirect-ssl.conf
   Include /etc/apache2/conf-available/letsencrypt-redirect.conf
 
-  ErrorLog ${APACHE_LOG_DIR}/alerta.lakedrops.com-error.log
+  ErrorLog ${APACHE_LOG_DIR}/{{ alerta_domain }}-error.log
   LogLevel warn
   LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" proxy
   SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded
-  CustomLog ${APACHE_LOG_DIR}/alerta.lakedrops.com-access.log combined env=!forwarded
-  CustomLog ${APACHE_LOG_DIR}/alerta.lakedrops.com-access.log proxy env=forwarded
+  CustomLog ${APACHE_LOG_DIR}/{{ alerta_domain }}-access.log combined env=!forwarded
+  CustomLog ${APACHE_LOG_DIR}/{{ alerta_domain }}-access.log proxy env=forwarded
 </VirtualHost>
 
 <VirtualHost *:443>
   Include /etc/apache2/conf-available/global-redirect.conf
 
   ServerAdmin webmaster@paragon-es.de
-  ServerName  alerta.lakedrops.com
+  ServerName  {{ alerta_domain }}
 
   Header always add Strict-Transport-Security "max-age=15768000; includeSubDomains; preload"
 
-  FileETag None
-  Header unset ETag
-  Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
-  Header set Pragma "no-cache"
-  Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
-
-  RequestHeader set Host alerta.lakedrops.com
-  RequestHeader set X_FORWARDED_PROTO 'https'
-  RequestHeader set X-Forwarded-Ssl on
-  RequestHeader set X-Forwarded-For alerta.lakedrops.com
-
   DocumentRoot /var/www/html
 
   <Proxy *>
     Include /etc/apache2/conf-available/global-deny.conf
   </Proxy>
 
-  RewriteEngine on
-  RewriteCond ${HTTP:Upgrade} websocket [NC]
-  RewriteCond ${HTTP:Connection} upgrade [NC]
-  RewriteRule .* "wss:/localhost:8091/$1" [P,L]
-
-  ProxyPass / http://localhost:8091/
-  ProxyPassReverse / http://localhost:8091/
   ProxyPreserveHost On
+  ProxyRequests Off
+
+  ProxyPass /web http://127.0.0.1:8092/
+  ProxyPassReverse /web http://127.0.0.1:8092/
+
+  ProxyPass /api http://127.0.0.1:8091/api
+  ProxyPassReverse /api http://127.0.0.1:8091/api
 
-  ErrorLog ${APACHE_LOG_DIR}/alerta.lakedrops.com-error.log
+  ErrorLog ${APACHE_LOG_DIR}/{{ alerta_domain }}-error.log
   LogLevel warn
   LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" proxy
   SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded
-  CustomLog ${APACHE_LOG_DIR}/alerta.lakedrops.com-access.log combined env=!forwarded
-  CustomLog ${APACHE_LOG_DIR}/alerta.lakedrops.com-access.log proxy env=forwarded
+  CustomLog ${APACHE_LOG_DIR}/{{ alerta_domain }}-access.log combined env=!forwarded
+  CustomLog ${APACHE_LOG_DIR}/{{ alerta_domain }}-access.log proxy env=forwarded
 
   <IfModule mod_expires.c>
     ExpiresActive On
@@ -72,7 +61,7 @@
 
   SSLEngine on
   Include /etc/letsencrypt/options-ssl-apache.conf
-  SSLCertificateFile /etc/letsencrypt/live/alerta.lakedrops.com/cert.pem
-  SSLCertificateKeyFile /etc/letsencrypt/live/alerta.lakedrops.com/privkey.pem
-  SSLCertificateChainFile /etc/letsencrypt/live/alerta.lakedrops.com/chain.pem
+  SSLCertificateFile /etc/letsencrypt/live/{{ alerta_domain }}/cert.pem
+  SSLCertificateKeyFile /etc/letsencrypt/live/{{ alerta_domain }}/privkey.pem
+  SSLCertificateChainFile /etc/letsencrypt/live/{{ alerta_domain }}/chain.pem
 </VirtualHost>
diff --git a/templates/webui/.env b/templates/webui/.env
new file mode 100644
index 0000000000000000000000000000000000000000..3856e077da658396a361186f92d785c52c8b79b5
--- /dev/null
+++ b/templates/webui/.env
@@ -0,0 +1 @@
+BASE_URL=/web
diff --git a/templates/webui/Dockerfile b/templates/webui/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..3172ca47f38f9bff1e79d756878846952881d677
--- /dev/null
+++ b/templates/webui/Dockerfile
@@ -0,0 +1,18 @@
+# build stage
+FROM node:lts-alpine as build-stage
+
+RUN apk add --no-cache git
+WORKDIR /app
+ADD https://github.com/alerta/alerta-webui/archive/master.tar.gz /tmp/webui.tar.gz
+RUN tar zxvf /tmp/webui.tar.gz -C /app --strip-components=1
+RUN npm install
+COPY .env .
+RUN npm run build
+
+# production stage
+FROM nginx:stable-alpine as production-stage
+COPY --from=build-stage /app/dist /app
+COPY config.json /app/config.json
+COPY nginx.conf /etc/nginx/nginx.conf
+EXPOSE 80
+CMD ["nginx", "-g", "daemon off;"]
diff --git a/templates/config.json b/templates/webui/config.json
similarity index 100%
rename from templates/config.json
rename to templates/webui/config.json
diff --git a/templates/webui/nginx.conf b/templates/webui/nginx.conf
new file mode 100644
index 0000000000000000000000000000000000000000..6f61d6c7cc064dff3f0ab028c4667471b74d0f56
--- /dev/null
+++ b/templates/webui/nginx.conf
@@ -0,0 +1,30 @@
+user  nginx;
+worker_processes  1;
+error_log  /var/log/nginx/error.log warn;
+pid        /var/run/nginx.pid;
+events {
+  worker_connections  1024;
+}
+http {
+  include       /etc/nginx/mime.types;
+  default_type  application/octet-stream;
+  log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
+                    '$status $body_bytes_sent "$http_referer" '
+                    '"$http_user_agent" "$http_x_forwarded_for"';
+  access_log  /var/log/nginx/access.log  main;
+  sendfile        on;
+  keepalive_timeout  65;
+  server {
+    listen       80;
+    server_name  localhost;
+    location / {
+      root   /app;
+      index  index.html;
+      try_files $uri $uri/ /index.html;
+    }
+    error_page   500 502 503 504  /50x.html;
+    location = /50x.html {
+      root   /usr/share/nginx/html;
+    }
+  }
+}