diff --git a/README.md b/README.md
index b10c6f643c4bd6b6a1e4fed62f2b2e2af278dd4c..60e18e8fca46637199807dfc0e01e7f241d881eb 100644
--- a/README.md
+++ b/README.md
@@ -21,14 +21,27 @@ Extract the archive (or use git pull).
 
 We need to setup the url for the api of the IML Appmonitor instance. In `public_html/javascript` copy the dist file inc_config.js.dist to inc_config.js
 
-Replace values in AM_SERVER_URL and AM_TAGS with your real data:
+Replace values in the first object in the AM_INSTANCES array with your real data:
 
 ```js
-const AM_SERVER_URL='https://appmonitor.example.com/api';
-const AM_TAGS='live,myapp';
+/**
+ * you can add multiple instances of appmonitor servers
+ */
+const AM_INSTANCES=[
+    {
+        'label':    'local Docker',
+        'url':      'http://localhost:8001',
+        'tags':     'monitoring',
+        'user':     'api',
+        'password': 'hello'
+    }
+];
+
 const REFRESHTIME=30; // in sec
 ```
 
+You can multiple instances of appmonitor servers with creating an additional object here. You get a select box to switch between them.
+
 Open the file `public_html/index.html` in your webbrowser.
 
 ## Troubleshooting ##
diff --git a/public_html/javascript/functions.js b/public_html/javascript/functions.js
index 666f1db97c33108336c7ce5c5c3052f6067662c0..a6e97b8ee78913adb6fdef0017f1745e4afa44c7 100644
--- a/public_html/javascript/functions.js
+++ b/public_html/javascript/functions.js
@@ -24,7 +24,7 @@ const OUT_ID_MAIN='header-section';
 const OUT_ID_APPS='app-section';
 const OUT_ID_TAGS='tag-section';
 const ID_TAGINPUT='E_TAGS';
-
+const ID_DELTAGS='button-disable-all-tags';
 
 // callback object after changing a tag filter
 const FILTER_CALLBACK="oUbdApps.update()";
@@ -48,8 +48,8 @@ var AM_TAGLIST={};
  */
 function _getAMApiUrl(sPath){
     return AM_PRETTYURL 
-        ? AM_SERVER_URL+sPath
-        : AM_SERVER_URL+'/index.php?request='+sPath
+        ? AM_SERVER_URL+'/api'+sPath
+        : AM_SERVER_URL+'/api/index.php?request='+sPath
     ;
 }
 
@@ -119,6 +119,7 @@ function _2digits(i){
     }
     if(sLast!==sReturn){
         document.getElementById(ID_TAGINPUT).value=sReturn;
+        document.getElementById(ID_DELTAGS).style.display=sReturn ? 'inline' : 'none';
         eval(FILTER_CALLBACK);
     }
 }
@@ -156,7 +157,7 @@ function _renderTaglist(aData){
             : ''
             );
     }
-    sReturn+='<button onclick="cbTagToggle(true);return false;"> ❌ </button>'
+    sReturn+='<button id="'+ID_DELTAGS+'" onclick="cbTagToggle(true);return false;"> '+AM_ICONS['delete']+' </button>'
     // sReturn+='<input id="'+ID_TAGINPUT+'" type="text" size="20" value="'+AM_TAGS+'"'+'>'
     sReturn+='<input id="'+ID_TAGINPUT+'" type="hidden" size="20" value="'+AM_TAGS+'">'
     AM_TAGLIST=_TAGLIST;
@@ -187,9 +188,11 @@ function _getAllAppsStatus(aAllData){
             +' (update every '+REFRESHTIME+' sec)'
         // +'</p>';
     // let aAllData=JSON.parse(sData);
+    var appOut='';
     for (var key in aAllData){
-        sReturn+=_getSingleAppStatus(aAllData[key]);
+        appOut+=_getSingleAppStatus(aAllData[key]);
     }
+    sReturn+=appOut ? appOut : '<div class="app result2">NO DATA.<br>No application matches this combination of tags.</div>';
     return sReturn;
 }
 
@@ -262,44 +265,76 @@ function _getSingleAppStatus(aData){
 }
 
 // ----------------------------------------------------------------------
-// MAIN
+// init instance
 // ----------------------------------------------------------------------
 
-// for auth header with basic auth
-let oHeaders=(AM_USER)
-    ? { "Authorization": "Basic " + btoa(AM_USER + ":" + AM_PASSWORD) }
-    : {}
-;
-
-document.getElementById(OUT_ID_MAIN).innerHTML=''+AM_ICONS['connect']+' Connected instance <a href="'+AM_SERVER_URL+'">'+AM_SERVER_URL+'</a>';
-
-// initialize tags
-var oUbdTag=new ubd(
-    {
-        'domid':     OUT_ID_TAGS,
-        'url':       _getUrlForTags(),
-        'header':    { "headers": oHeaders },
-        'renderer':  _renderTaglist,
-        'ttl':       0,
-    }
-);
-
-// initialize visible apps
-var oUbdApps=new ubd(
-    {
-        'domid':     OUT_ID_APPS,
-        'url':       _getUrlWithTags, // remark: this is a function
-        'header':    { "headers": oHeaders },
-        'renderer':  _getAllAppsStatus,
-        'ttl':       REFRESHTIME,
-    }
-);
+/**
+ * set a appmonitor instance that are defined in AM_INSTANCES
+ * see inc_config.js
+ * 
+ * @param {integer} i  number of instance to activate
+ */
+function initInstance(i){
 
+    AM_SERVER_URL=AM_INSTANCES[i]['url'];
+    AM_TAGS=AM_INSTANCES[i]['tags'];
+    AM_USER=AM_INSTANCES[i]['user'];
+    AM_PASSWORD=AM_INSTANCES[i]['password'];
 
+    // for auth header with basic auth
+    let oHeaders=(AM_USER)
+        ? { "Authorization": "Basic " + btoa(AM_USER + ":" + AM_PASSWORD) }
+        : {}
+    ;
 
-// fill in initial values ... and update based on given ttl
-oUbdTag.update();
-oUbdApps.update();
+    // initialize tags
+    oUbdTag=new ubd(
+        {
+            'domid':     OUT_ID_TAGS,
+            'url':       _getUrlForTags(),
+            'header':    { "headers": oHeaders },
+            'renderer':  _renderTaglist,
+            'ttl':       0,
+        }
+    );
+
+    // initialize visible apps
+    oUbdApps=new ubd(
+        {
+            'domid':     OUT_ID_APPS,
+            'url':       _getUrlWithTags, // remark: this is a function
+            'header':    { "headers": oHeaders },
+            'renderer':  _getAllAppsStatus,
+            'ttl':       REFRESHTIME,
+        }
+    );
+
+
+    let sInstances='';
+    for (var j=0; j<AM_INSTANCES.length; j++){
+        sInstances+='<option value="'+j+'" '
+            +(i==j ? 'selected ' : '')
+            + '>'+AM_INSTANCES[j]['label']+'</option>';
+    }
+    sInstances=sInstances 
+        ? AM_ICONS['connect']+' Connected instance '
+            + '<select onchange="initInstance(this.value); return false;">'+sInstances+'</select> ' 
+            + ' <a href="'+AM_SERVER_URL+'">'+AM_SERVER_URL+'</a>'
+        : '';
+    
+    document.getElementById(OUT_ID_MAIN).innerHTML= sInstances;
+
+    // fill in initial values ... and update based on given ttl
+    window.setTimeout("oUbdTag.update();", 50);
+    window.setTimeout("oUbdApps.update();", 400);
+    
+
+}
+
+// ----------------------------------------------------------------------
+// MAIN
+// ----------------------------------------------------------------------
 
+initInstance(0);
 
 // ----------------------------------------------------------------------
\ No newline at end of file
diff --git a/public_html/javascript/inc_config.js.dist b/public_html/javascript/inc_config.js.dist
index fb490522c81e494072c063dc6741e2e062ed113b..333c3ff0270a7d80f9acd1969f75eb9ba92cdcc7 100644
--- a/public_html/javascript/inc_config.js.dist
+++ b/public_html/javascript/inc_config.js.dist
@@ -1,8 +1,14 @@
-const AM_SERVER_URL='https://appmonitor.example.com/api';
-const AM_TAGS='live,myapp';
+/**
+ * you can add multiple instances of appmonitor servers
+ */
+const AM_INSTANCES=[
+    {
+        'label':    'local Docker',
+        'url':      'http://localhost:8001',
+        'tags':     'monitoring',
+        'user':     'api',
+        'password': 'hello'
+    }
+];
 
-// optional: BASIC AUTH
-const AM_USER='';
-const AM_PASSWORD='';
-
-const REFRESHTIME=30; // in sec
+const REFRESHTIME=30; // in sec
\ No newline at end of file
diff --git a/public_html/javascript/ubd.class.js b/public_html/javascript/ubd.class.js
index 69ea642bfac355f2ebfc664243ab31c7c82e9f65..1ebb58290f98823e205a4d77a43022080f653fc5 100644
--- a/public_html/javascript/ubd.class.js
+++ b/public_html/javascript/ubd.class.js
@@ -15,22 +15,14 @@
  * ======================================================================
  */
 
-var ubd = function(){
-
-    this._sDomId='';
-    this._oDomObject=false;
-    this._sUrl2Fetch=false; // static value or reference of a function
-    this._oHeader={};
-    this._sRenderfunction=false;
-    this._iTTL=false;
-
-    this._oTimer=false;
-
-    this._body='';
-        
+/**
+ * Url binded to a dom id
+ * @return class
+ */
+class ubd {
     /**
      * initialize data for a dom object
-     * @parm  {object}  oConfig    optional config object with those subkeys:
+     * @param  {object}  oConfig    optional config object with those subkeys:
      *                                  domid    - id of a dom object
      *                                  url      - url to an api
      *                                  header   - http request header data
@@ -38,25 +30,40 @@ var ubd = function(){
      *                                  ttl      - ttl in sec (TODO)
      * @returns {undefined}
      */
-    this.init = function(oConfig){
-        if (oConfig){
-            if(oConfig['domid']){
+    constructor(oConfig) {
+
+        this._sDomId = '';
+        this._oDomObject = false;
+        this._sUrl2Fetch = false; // static value or reference of a function
+        this._oHeader = {};
+        this._sRenderfunction = false;
+        this._iTTL = false;
+
+        this._oTimer = false;
+
+        this._body = '';
+
+        oConfig = arguments ? arguments[0] : false;
+
+
+        if (oConfig) {
+            if (oConfig['domid']) {
                 this.setDomid(oConfig['domid']);
             }
-            if(oConfig['url']){
+            if (oConfig['url']) {
                 this.setUrl(oConfig['url']);
             }
-            if(oConfig['header']){
+            if (oConfig['header']) {
                 this.setHeaders(oConfig['header']);
             }
-            if(oConfig['renderer']){
+            if (oConfig['renderer']) {
                 this.setRenderfunction(oConfig['renderer']);
             }
-            if(oConfig['ttl']){
+            if (oConfig['ttl']) {
                 this.setTtl(oConfig['ttl']);
             }
         }
-    },
+    }
 
     // ----------------------------------------------------------------------
     // public SETTER for properties
@@ -66,141 +73,130 @@ var ubd = function(){
      * set domid that will by updated
      * @param {string} sDomid if of a domobject
      */
-    this.setDomid = function(sDomid){
-        if (document.getElementById(sDomid)){
-            this._sDomId=sDomid;
-            this._oDomObject=document.getElementById(sDomid);
-        } else {
-            this._sDomId=false;
-            this._oDomObject=false;
-            console.error('ERROR: setDomid("'+sDomid+'") got an invalid string - this domid does not exist.');
-        }
-    },
-
+    setDomid(sDomid) {
+            if (document.getElementById(sDomid)) {
+                this._sDomId = sDomid;
+                this._oDomObject = document.getElementById(sDomid);
+            } else {
+                this._sDomId = false;
+                this._oDomObject = false;
+                console.error('ERROR: setDomid("' + sDomid + '") got an invalid string - this domid does not exist.');
+            }
+    }
 
     /**
      * set a rendering function that visualized data after a http request
      * @param {string|function} oFunction reference to a function ... or false to disable rendering
      */
-    this.setRenderfunction = function(oFunction){
-        this._sRenderfunction=oFunction;
-    },
+    setRenderfunction (oFunction) {
+        this._sRenderfunction = oFunction;
+    }
 
     /**
      * Set time to live in seconds
-     * @param {int} iTTL 
+     * @param {int} iTTL
      */
-    this.setTtl = function(iTTL){
-        this._iTTL=iTTL/1;
+    setTtl(iTTL) {
+        this._iTTL = iTTL / 1;
         this.resetTimer();
-    },
+    }
 
     /**
      * set an url to be requested
      * @param {string|function} sUrl  static value or reference of a function
      */
-    this.setUrl = function(sUrl){
-        this._sUrl2Fetch=sUrl;
-    },
+    setUrl(sUrl) {
+        this._sUrl2Fetch = sUrl;
+    }
 
     /**
      * set header obejct for 2nd param in javascript  fetch() function
-     * @param {object} oHeader 
+     * @param {object} oHeader
      */
-    this.setHeaders = function(oHeader){
-        this._oHeader=oHeader;
-    },
+    setHeaders(oHeader) {
+        this._oHeader = oHeader;
+    }
 
     /**
      * helper: dump current object instance to console
      */
-    this.dumpme = function(){
+    dumpme() {
         console.log('---------- DUMP ubd');
         console.log(this);
         console.log('---------- /DUMP ubd');
-    },
+    }
     // ----------------------------------------------------------------------
     // public ACTIONS
     // ----------------------------------------------------------------------
-
     /**
      * show rendered html content into set domid using the render function.
      * If no rendering function was set then the response will be written
      * directly.
      * You can override both by giving a parameter (a string with html)
      * to write that one directly. It can be used to show an error message.
-     * 
+     *
      * TODO:
-     * other output places than innerHTML by detecting the tag e.g. 
+     * other output places than innerHTML by detecting the tag e.g.
      * to use input or textarea.
-     * 
+     *
      * @param {string} sHtml  optional: htmlcode of an error message
      */
-    this.render = function(sHtml) {
-        let out = sHtml ? sHtml : 
-            (this._sRenderfunction 
+    render(sHtml) {
+        let out = sHtml ? sHtml :
+            (this._sRenderfunction
                 ? this._sRenderfunction(this._body)
                 : this._body
             );
-        this._oDomObject.innerHTML=out;
-    },
+        this._oDomObject.innerHTML = out;
+    }
 
     /**
      * reset timer to update the content in dom id after reaching TTL
      * used in setTtl
      */
-    this.resetTimer = function(){
+    resetTimer() {
         clearTimeout(this._oTimer);
         // clearInterval(this._oTimer);
-        if(this._iTTL) {
+        if (this._iTTL) {
             let self = this;
-            self._oTimer=window.setTimeout( function(){ self.update() }, this._iTTL*1000);
+            self._oTimer = window.setTimeout(function () { self.update(); }, this._iTTL * 1000);
             // self._oTimer=window.setInterval(self.update, this._iTTL*1000);
         }
-    },
+    }
 
     /**
      * make http request and call the renderer
      */
-    this.update = async function(){
+    async update() {
         let self = this;
-        let url=( typeof this._sUrl2Fetch == "function" ) ? this._sUrl2Fetch() : this._sUrl2Fetch;
+        let url = (typeof this._sUrl2Fetch == "function") ? this._sUrl2Fetch() : this._sUrl2Fetch;
         console.log("update from url [" + url + "]");
-        if (url == undefined){
+        if (url == undefined) {
             console.error("SKIP update - there is no url in this object instance (anymore) :-/");
             this.dumpme();
             return 0;
         }
-        try{
+        try {
             let response = await fetch(url, this._oHeader);
             if (response.ok) {
-                this._body=await response.json();
-                
+                this._body = await response.json();
+
                 this.render();
             } else {
                 this.render('<div class="app result1">'
-                    +'ERROR '+response.status+': '+response.statusText + ' - '
-                    +url
-                    +'</div>');
-            } 
-        } catch(e) {
+                    + 'ERROR ' + response.status + ': ' + response.statusText + ' - '
+                    + url
+                    + '</div>');
+            }
+        } catch (e) {
             this.render('<div class="app result1">'
-            +'UNKNOWN: no response from '
-            +this._sUrl2Fetch
-            +'</div>');
+                + 'UNKNOWN: no response from '
+                + this._sUrl2Fetch
+                + '</div>');
             console.error(e);
         }
         this.resetTimer();
     }
 
-    // ----------------------------------------------------------------------
-    // MAIN
-    // ----------------------------------------------------------------------
-
-    if (arguments) {
-        this.init(arguments[0]);
-    } else {
-        this.init();
-    }
-
-};
\ No newline at end of file
+ 
+    }
\ No newline at end of file
diff --git a/public_html/main.css b/public_html/main.css
index 16e92b27873b8e7c7d3f6da624802b316e4e9a95..f7617f9768137e36e09e9cfc1ee176ffecc1f2d4 100644
--- a/public_html/main.css
+++ b/public_html/main.css
@@ -1,6 +1,6 @@
 :root{
     --color-0: #345;
-    --color-h1: #abc;
+    --color-h1: #789;
     --color-h2: #579;
     --color-links: #349;
 
@@ -19,8 +19,8 @@ body{
     font-family: verdana,arial;
 }
 
-button{ border: 1px solid  rgba(0,0,0,0.1); background: linear-gradient(#f8f8f8, #ddd); border-radius: 0.3em; margin: 0 0.5em 0.5em 0; padding: 0.5em;}
-button:hover{ background: linear-gradient(#eee, #ccc); border-radius: 0.3em; margin: 0 0.5em 0.5em 0; padding: 0.5em;}
+button{ border: 1px solid  rgba(0,0,0,0.1); background: linear-gradient(#f8f8f8, #ddd); border-radius: 0.3em; margin: 0 0.5em 0; padding: 0.5em;}
+button:hover{ background: linear-gradient(#eee, #ccc);}
 button:active{ border:1px solid #fc2;}
 input{ border:1px solid #ccc; padding: 0.4em;}
 
@@ -52,7 +52,15 @@ section input[type=checkbox]:checked + label {
 section input[type=checkbox]+ label:hover {
     border-color: #89a;
 }
-
+select{
+    background: #fff;
+    border: 2px solid #f8f8f8;
+    color: var(--color-0);
+    font-size: 110%; 
+}
+select:hover{
+    background: #fec;
+}
 td{vertical-align: top;}
 
 #main{