diff --git a/config/config_custom.php.dist b/config/config_custom.php.dist
index b8ea8520b2b2a29e848145447f904319e5d89a3b..50c09d5c8769a35144225b26528d2078b8234068 100644
--- a/config/config_custom.php.dist
+++ b/config/config_custom.php.dist
@@ -91,6 +91,7 @@ return [
 
         'rollout'=>[
             'default'=>[],
+            /*
             'ssh'=>[
                 'user'=>'imldeployment',
                 'privatekey'=>'',
@@ -99,13 +100,13 @@ return [
                 'command'=>'/usr/local/bin/puppetrun.sh',
             ],
             'awx'=>[
-                'url'=>'https://awx.sys.iml.unibe.ch/api/v2', // no ending "/"
-                'user'=>'api-ci',
-                'password'=>'awRSbdB2rkViaBXBKOvtr11DEoZJSqHceih1hEE4awrjIO1wuArKu85WmetsRp63',
+                'url'=>'https://awx.example.com/api/v2', // no ending "/"
+                'user'=>'ciserver',
+                'password'=>'ciserver',
                 'jobtemplate'=>'36',
                 'tags'=>'rollout',
-                // 'ignore-ssl-error'=>false,
             ],
+            */
         ],
     ],
     
@@ -128,6 +129,42 @@ return [
             ],
         ],
     ],
+
+    // ----------------------------------------------------------------------    
+    // APPMONITOR
+    // see <https://os-docs.iml.unibe.ch/appmonitor/>
+    // ----------------------------------------------------------------------    
+
+    "appmonitor" => [
+
+        // notification
+
+        // email notification for this application
+        /*
+        "email" => [
+            "sysadmin@example.com"            
+        ],
+        */
+        // email notification for this application
+        /*
+        "slack" => [
+            ["#sysadmins", "https://hooks.slack.com/services/AAA/BBB/CCC" ]
+        ],
+        */
+
+        // limit access to appmonitor client to specific IP addresses
+        /*
+        "ip" => [
+            '127.0.0.1',
+            '::1',
+            '10.0.2.2',
+        ],
+        */
+
+        // limit access to appmonitor client to specific token
+        // "token" => ["token", "1234567890"],
+
+
     // ----------------------------------------------------------------------    
 
 ];
\ No newline at end of file
diff --git a/config/inc_projects_config.php b/config/inc_projects_config.php
index 0345ab7affa26af284cbbff71d9e6cc83aca0136..17cfa94e3e59fee88a94805e1f903765c5ff42ef 100644
--- a/config/inc_projects_config.php
+++ b/config/inc_projects_config.php
@@ -1,4 +1,10 @@
 <?php
+/**
+ * Array of global configuration for CI server
+ * @var array
+ */
+$aConfig = [];
+global $aConfig;
 
 $aConfig = include('config_defaults.php');
 if (file_exists(__DIR__.'/config_custom.php')){
diff --git a/hooks/templates/config_custom.php.erb b/hooks/templates/config_custom.php.erb
index 01e109e323cf18997723d7657af460f1907b7dc9..28c3d1dcfec11e8da093675b2d1f89eccfc9678d 100644
--- a/hooks/templates/config_custom.php.erb
+++ b/hooks/templates/config_custom.php.erb
@@ -103,15 +103,35 @@ return [
     ],
 
     /*
-    'foreman' => array(
+    'foreman' => [
         'api'=>'<%= @replace["foreman-url"] %>', // with ending "/"
         'user'=>'<%= @replace["foreman-user"] %>',
         'password'=>'<%= @replace["foreman-password"] %>',
         'ignore-ssl-error'=><%= @replace["foreman-ignore-ssl-error"] %>,
         // 'varname-replace'=>'ci-replacement',
-    ),
+    ],
     */
 
     // ----------------------------------------------------------------------    
+    // APPMONITOR
+    // see <https://os-docs.iml.unibe.ch/appmonitor/>
+    // ----------------------------------------------------------------------    
+
+    "appmonitor" => [
+
+        // notification
+
+        // email notification for this application
+        "email" => [<%= @replace["appmonitor-email-to"] %>],
+
+        "slack" => [<%= @replace["appmonitor-slack"] %>],
+
+        // limit access to appmonitor client to specific IP addresses
+        "ip" => [<%= @replace["appmonitor-ip"] %>],
+
+        // limit access to appmonitor client to specific token
+        "token" => [<%= @replace["appmonitor-token"] %>],
+
+    // ----------------------------------------------------------------------    
 
 ];
\ No newline at end of file
diff --git a/public_html/appmonitor/general_include.php b/public_html/appmonitor/general_include.php
index bdd129b19018a17c8f27d750d304e9198ccf12bb..b7530759bed2059dace5d912f142a0816c344d6e 100644
--- a/public_html/appmonitor/general_include.php
+++ b/public_html/appmonitor/general_include.php
@@ -7,6 +7,7 @@
  * @author: Axel Hahn
  * ----------------------------------------------------------------------
  * 2018-06-30  v0.1
+ * 2024-09-04  php8 only: short array syntax; use data from ci server config file
  */
 
 // ----------------------------------------------------------------------
@@ -17,28 +18,31 @@
 
 // check local ips and IML networks (includes the monitor)
 // appmonitor is not available on EDUROAM or VPN
-$oMonitor->checkIp(array(
-    '127.0.0.1',
-    '::1',
-    '10.0.2.2',
-    '130.92.30.11',
-    '130.92.30.44',
-    '130.92.79.49',
-));
+if(isset($aConfig['appmonitor']['ip']) && count($aConfig['appmonitor']['ip'])){
+    $oMonitor->checkIp($aConfig['appmonitor']['ip']);
+}
 
 // --- check a token
 // an incoming request must have the GET param "token=123"
 // $oMonitor->checkTokem('token', '123');
-
+if(isset($aConfig['appmonitor']['token']) && count($aConfig['appmonitor']['token'])){
+    $oMonitor->checkToken($aConfig['appmonitor']['token'][0], $aConfig['appmonitor']['token'][1]);
+}
 
 // ----------------------------------------------------------------------
 // NOTIFICATION
 // ----------------------------------------------------------------------
 
-// $oMonitor->addEmail('sysadmin@example.com');
-// $oMonitor->addSlackWebhook(array("mywebhook"=> "https://hooks.slack.com/services/(...)"));
-$oMonitor->addEmail('axel.hahn@iml.unibe.ch');
-
+if(isset($aConfig['appmonitor']['email']) && count($aConfig['appmonitor']['email'])){
+    foreach($aConfig['appmonitor']['email'] as $sEmailTo){
+        $oMonitor->addEmail($sEmailTo);
+    }
+}
+if(isset($aConfig['appmonitor']['slack']) && count($aConfig['appmonitor']['slack'])){
+    foreach($aConfig['appmonitor']['slack'] as $aSlackTarget){
+        $oMonitor->addSlackWebhook($aSlackTarget[0], $aSlackTarget[1]);
+    }
+}
 
 // ----------------------------------------------------------------------
 // set a tag with phase
@@ -46,7 +50,9 @@ $oMonitor->addEmail('axel.hahn@iml.unibe.ch');
 $sHost=$_SERVER['HTTP_HOST'];
 $sHost2=php_uname("n");   
 $sMyPhase='live';
-foreach (array('dev', 'preview', 'stage', 'demo') as $sPhase){
+
+// foreach (array('dev', 'preview', 'stage', 'demo') as $sPhase){
+foreach (array_keys($aConfig['phases']) as $sPhase){
     if(
         strstr($sHost.'.', $sPhase)!==false
         || strstr($sHost.'-', $sPhase)!==false
diff --git a/public_html/appmonitor/index.php b/public_html/appmonitor/index.php
index 15011824790473dfd0a5dbd6d1d82c227ef4566f..422c047b54f93e304b1a7d104fe718326e08edc4 100644
--- a/public_html/appmonitor/index.php
+++ b/public_html/appmonitor/index.php
@@ -1,46 +1,69 @@
 <?php
-
+/**
+ * IML APPMONITOR CHECKS FOR CI SERVER
+ * 
+ * @author: Axel Hahn
+ * 
+ * ------------------------------------------------------------------
+ * 2014-10-24  v0.1
+ * ...
+ * 2024-09-04  php8 only: short array syntax
+ */
 require_once('classes/appmonitor-client.class.php');
+
+
 require_once(__DIR__.'/../deployment/classes/project.class.php');
 $oMonitor = new appmonitor();
-    
-$oMonitor->addCheck(
-        array(
-            "name" => "simple",
-            "description" => "Very simple test",
-            "check" => array(
-                "function" => "Simple",
-                "params" => array(
-                    "result" => 0,
-                    "value" => "The appmonitor client is reachable.",
-                ),
-            ),
-        )
-);
 
 $sCfgfile='../../config/inc_projects_config.php';
+require_once $sCfgfile;
+
+include('general_include.php');
 
 
 // ----------------------------------------------------------------------
-// config file
+// config files
 // ----------------------------------------------------------------------
 
 $oMonitor->addCheck(
-    array(
+    [
         "name" => "read config file",
         "description" => "Check if config file is readable",
-        "check" => array(
+        "check" => [
             "function" => "File",
-            "params" => array(
+            "params" => [
                 "filename" => $sCfgfile,
                 "file"     => true,
                 "readable" => true,
-            ),
-        ),
-    )
+            ],
+        ],
+    ]
 );
 
-require_once $sCfgfile;
+
+
+foreach ([
+    "config/config_custom.php",
+    "config/config_defaults.php",
+    "config/inc_roles.php",
+] as $sCfgfile) {
+
+    $oMonitor->addCheck(
+        [
+            "name" => "read config file $sCfgfile",
+            "description" => "Check if config file $sCfgfile is an existing file and is readable",
+            "check" => [
+                "function" => "File",
+                "params" => [
+                    "filename" => "../../$sCfgfile",
+                    "file"     => true,
+                    "readable" => true,
+                ],
+            ],
+        ]
+    );
+}
+
 
 // echo '<pre>' . print_r($aConfig, 1) . '</pre>';die();
 
@@ -48,50 +71,50 @@ require_once $sCfgfile;
 // directories
 // ----------------------------------------------------------------------
 
-foreach (array(
+foreach ([
     
-    'tmpDir'=>array('dir'=>$aConfig['tmpDir'], 'descr'=>'Temp Dir mit git Daten'),
-    'configDir'=>array('dir'=>$aConfig['configDir'], 'descr'=>'Ablage der Programm-Config'),
-    'dataDir'=>array('dir'=>$aConfig['dataDir'], 'descr'=>'Basisverzeichnis fue DB, Projekt-Configs, SSH-Keys'),
-        'dataDir/database'=>array('dir'=>$aConfig['dataDir'].'/database', 'descr'=>'DB-Ablage (Sqlite)'),
-        'dataDir/projects'=>array('dir'=>$aConfig['dataDir'].'/projects', 'descr'=>'Projekt-Configdateien'),
-        'dataDir/sshkeys'=>array('dir'=>$aConfig['dataDir'].'/sshkeys', 'descr'=>'SSH Keys'),
+    'tmpDir'=>['dir'=>$aConfig['tmpDir'], 'descr'=>'Temp Dir mit git Daten'],
+    'configDir'=>['dir'=>$aConfig['configDir'], 'descr'=>'Ablage der Programm-Config'],
+    'dataDir'=>['dir'=>$aConfig['dataDir'], 'descr'=>'Basisverzeichnis fue DB, Projekt-Configs, SSH-Keys'],
+        'dataDir/database'=>['dir'=>$aConfig['dataDir'].'/database', 'descr'=>'DB-Ablage (Sqlite)'],
+        'dataDir/projects'=>['dir'=>$aConfig['dataDir'].'/projects', 'descr'=>'Projekt-Configdateien'],
+        'dataDir/sshkeys'=>['dir'=>$aConfig['dataDir'].'/sshkeys', 'descr'=>'SSH Keys'],
     
-    'buildDir'=>array('dir'=>$aConfig['buildDir'], 'descr'=>'Basisverzeichnis fuer Builds'),
-    'packageDir'=>array('dir'=>$aConfig['packageDir'], 'descr'=>'Basisverzeichnis der Pakete und Versionen'),
-    'archiveDir'=>array('dir'=>$aConfig['archiveDir'], 'descr'=>'Ablage der gebuildeten Archive'),
+    'buildDir'=>['dir'=>$aConfig['buildDir'], 'descr'=>'Basisverzeichnis fuer Builds'],
+    'packageDir'=>['dir'=>$aConfig['packageDir'], 'descr'=>'Basisverzeichnis der Pakete und Versionen'],
+    'archiveDir'=>['dir'=>$aConfig['archiveDir'], 'descr'=>'Ablage der gebuildeten Archive'],
     
-) as $sKey=>$aItem) {
+] as $sKey=>$aItem) {
     $oMonitor->addCheck(
-        array(
+        [
             "name" => "dir $sKey",
             "description" => $aItem['descr'],
             "parent" => "read config file",
-            "check" => array(
+            "check" => [
                 "function" => "File",
-                "params" => array(
+                "params" => [
                     "filename" => $aItem['dir'],
                     "dir"      => true,
                     "writable" => true,
-                ),
-            ),
-        )
+                ],
+            ],
+        ]
     );
 }
 $oMonitor->addCheck(
-	array(
+	[
 		"name" => "Free space in Archive dir ",
 		"description" => "The file storage must have some space left",
-		"check" => array(
+		"check" => [
 			"function" => "Diskfree",
             "parent" => "read config file",
-			"params" => array(
+			"params" => [
 				"directory" => $aConfig['archiveDir'],
 				"warning"   => "2GB",
 				"critical"  => "500MB",
-			),
-		),
-	)
+            ],
+		],
+    ]
 );
 // ----------------------------------------------------------------------
 // count of Projects
@@ -113,55 +136,55 @@ foreach ($oPrj->getProjects() as $sPrj) {
         $iInQueue+=$aProgress['hasQueue'] ? 1 : 0;
 }
 $oMonitor->addCheck(
-    array(
+    [
         "name" => "ci projects",
         "description" => "Count of Projects in CI Webgui",
         "group" => "monitor",
         "parent" => "read config file",
-        "check" => array(
+        "check" => [
             "function" => "Simple",
-            "params" => array(
+            "params" => [
                 "result" => $iProjectCount ? RESULT_OK : RESULT_ERROR,
                 "value" => "found projects: $iProjectCount",
                 "count" => $iProjectCount,
                 "visual" => "simple",
-            ),
-        ),
-    )
+            ],
+		],
+    ]
 );
 $oMonitor->addCheck(
-    array(
+    [
         "name" => "ci inProgress",
         "description" => "Projects in progress",
         "group" => "monitor",
         "parent" => "read config file",
-        "check" => array(
+        "check" => [
             "function" => "Simple",
-            "params" => array(
+            "params" => [
                 "result" => RESULT_OK,
                 "value" => "found projects: $iInProgress",
                 "count" => $iInProgress,
                 "visual" => "simple",
-            ),
-        ),
-    )
+            ],
+		],
+    ]
 );
 $oMonitor->addCheck(
-    array(
+    [
         "name" => "ci hasqueue",
         "description" => "Waiting for install",
         "group" => "monitor",
         "parent" => "read config file",
-        "check" => array(
+        "check" => [
             "function" => "Simple",
-            "params" => array(
+            "params" => [
                 "result" => RESULT_OK,
                 "value" => "found projects: $iInQueue",
                 "count" => $iInQueue,
                 "visual" => "simple",
-            ),
-        ),
-    )
+            ],
+		],
+    ]
 );
 
 include 'plugins/apps/shared_check_ssl.php';
@@ -176,32 +199,32 @@ if(isset($aConfig['foreman']['api'])){
     require_once(__DIR__.'/../deployment/classes/foremanapi.class.php');
     $oForeman = new ForemanApi($aConfig['foreman']);
 
-    foreach (array('hostgroups', 'hosts') as $sForemanKey){
-        $aFData=$oForeman->read(array(
-            'request' => array(
-                array($sForemanKey),
-            ),
-            'response' => array(
+    foreach (['hostgroups', 'hosts'] as $sForemanKey){
+        $aFData=$oForeman->read([
+            'request' => [
+                [$sForemanKey],
+            ],
+            'response' => [
                 'id', 'title'
-            ),
-        ));
+            ],
+        ]);
         
         $oMonitor->addCheck(
-            array(
+            [
                 "name" => "Foreman $sForemanKey",
                 "description" => "Count of Foreman $sForemanKey",
                 "group" => "monitor",
                 "parent" => "read config file",
-                "check" => array(
+                "check" => [
                     "function" => "Simple",
-                    "params" => array(
+                    "params" => [
                         "result" => count($aFData) ? RESULT_OK : RESULT_ERROR,
                         "value" => "Count of found Foreman $sForemanKey: " . count($aFData)."; response status: ".$oForeman->getResponseStatus() . "; Http-Code ".$oForeman->getResponseInfo('http_code'),
                         "count" => count($aFData),
                         "visual" => "simple",
-                    ),
-                ),
-            )
+                    ],
+                ],
+            ]
         );
     }
 }
@@ -220,16 +243,16 @@ if(isset($aConfig['plugins']['rollout']['awx'])){
     }
 
     $oMonitor->addCheck(
-        array(
+        [
             "name" => "AWX API",
             "description" => "check if AWX api is available",
             "group" => "network",
             "parent" => "read config file",
-            "check" => array(
+            "check" => [
                 "function" => "HttpContent",
                 "params" => $aOpts,
-            ),
-        )
+            ],
+        ]
     );
 }
 
@@ -252,56 +275,56 @@ if(count($aConfig['mirrorPackages'])){
 
         exec($sCmd, $sOut, $iRc);
         $oMonitor->addCheck(
-            array(
+            [
                 "name" => "mirror target $sHostKey",
                 "description" => "Sync target of generated packages",
                 "group" => "network",
                 "parent" => "read config file",
-                "check" => array(
+                "check" => [
                     "function" => "Simple",
-                    "params" => array(
+                    "params" => [
                         "result" => $iRc ? RESULT_ERROR : RESULT_OK,
                         "value" => "Command [$sCmd] returns with exitcode $iRc; output: ".implode(" ", $sOut),
-                    ),
-                ),
-            )
+                    ],
+                ],
+            ]
         );
     }
     
 }
-foreach(array(
+foreach([
     /*
-    array(
+    [
         'host'=>'gitlab.iml.unibe.ch',
         'port'=>22,
         'descr'=>'SSH port to Gitlab on gitlab.iml.unibe.ch'
-    ),
+    ],
      */
-    array(
+    [
         'host'=>'git-repo.iml.unibe.ch',
         'port'=>22,
         'descr'=>'SSH port to Gitlab on git-repo.iml.unibe.ch'
-    ),
-    array(
+    ],
+    [
         'host'=>'github.com',
         'port'=>22,
         'descr'=>'SSH port to Github'
-    ),
-) as $aDescr){
+    ],
+] as $aDescr){
     $oMonitor->addCheck(
-            array(
-                    "name" => 'port check '.$aDescr['host'].':'.$aDescr['port'],
-                    "description" => $aDescr['descr'],
-                    "group" => "cloud",
-                    "parent" => "read config file",
-                    "check" => array(
-                            "function" => "PortTcp",
-                            "params" => array(
-                                    "port"=>$aDescr['port'],
-                                    "host"=>$aDescr['host'],
-                            ),
-                    ),
-            )
+        [
+            "name" => 'port check '.$aDescr['host'].':'.$aDescr['port'],
+            "description" => $aDescr['descr'],
+            "group" => "cloud",
+            "parent" => "read config file",
+            "check" => [
+                "function" => "PortTcp",
+                "params" => [
+                    "port"=>$aDescr['port'],
+                    "host"=>$aDescr['host'],
+                ],
+            ],
+        ]
     );
 }
 
@@ -312,56 +335,56 @@ foreach(array(
 
 $sSqlitefile=$aConfig['dataDir'].'/database/logs.db';
 $oMonitor->addCheck(
-    array(
+    [
         "name" => "Sqlite DB for action logs",
         "description" => "Connect sqlite db ". basename($sSqlitefile),
         "parent" => "read config file",
-        "check" => array(
+        "check" => [
             "function" => "SqliteConnect",
-            "params" => array(
+            "params" => [
                 "db"=>$sSqlitefile
-            ),
-        ),
-    )
+            ],
+        ],
+    ]
 );
 
 // ----------------------------------------------------------------------
 // system stuff
 // ----------------------------------------------------------------------
 $oMonitor->addCheck(
-    array(
+    [
         "name" => "plugin Load",
         "description" => "current load",
         "parent" => false,
-        "check" => array(
+        "check" => [
             "function" => "Loadmeter",
-            "params" => array(
+            "params" => [
                 "warning" => 1.0,
                 "error" => 3,
-            ),
-        ),
+            ],
+        ],
         "worstresult" => RESULT_OK
-    )
+    ]
 );
 $oMonitor->addCheck(
-    array(
+    [
         "name" => "plugin ApacheProcesses",
         "description" => "Apache processes",
         "parent" => false,
-        "check" => array(
+        "check" => [
             "function" => "ApacheProcesses",
-            "params" => array(
+            "params" => [
                 "warning" => 50,
                 "error" => 75,
-            ),
-        ),
+            ],
+        ],
         "worstresult" => RESULT_OK
-    )
+    ]
 );
 
+// ----------------------------------------------------------------------
 
-// Gesamt-Ergebnis - ohne Param=aut. max. Wert nehmen
 $oMonitor->setResult();
-
-// Ausgabe
 $oMonitor->render();
+
+// ----------------------------------------------------------------------