Search by

teufels / tt3-stackmonitor

teufels

[teufels] stackmonitor - Secret-protected /stackmonitor endpoint that reports CMS, PHP and database versions as JSON to the teufels stack monitoring dashboard

Package info

bitbucket.org/teufels/tt3-stackmonitor/

Homepage

Issues

Type:typo3-cms-extension

pkg:composer/teufels/tt3-stackmonitor

Statistics

Installs: 8

Dependents: 0

Suggesters: 0

1.0.0 2026-11-09 13:02 UTC

This package is auto-updated.

Last update: 2026-11-09 13:30:53 UTC


README

VENDOR PACKAGE KEY version

[ ṯeufels ] Stackmonitor

Minimal monitoring endpoint for the teufels stack monitoring dashboard. GET https://<domain>/stackmonitor returns the CMS, PHP and database versions of the installation as JSON. The data is only handed out if the request carries the shared secret in the HTTP header X-Stackmonitor-Secret.

This version supports TYPO3

TYPO3 9.5 to 14.3 (PHP 7.2 to 8.5), one code base. Verified at runtime on TYPO3 14.3, the APIs used are checked against 9.5 - 13.4.

Composer support

composer req teufels/tt3-stackmonitor

Links

URL
Repository:https://bitbucket.org/teufels/tt3-stackmonitor/
Packagist:https://packagist.org/packages/teufels/tt3-stackmonitor/
TER:tbd
Documentation:tbd

1. How it works

A single PSR-15 middleware is registered in the frontend middleware stack in front of the site resolver. It answers requests to /stackmonitor itself and passes everything else through untouched. No page, site configuration, TypoScript or web server rewrite is needed, the dashboard only needs the domain. The path /stackmonitor is fixed and therefore reserved.

2. Installation

  1. composer req teufels/tt3-stackmonitor and set up the extension (typo3 extension:setup). Classic mode: install the extension in the Extension Manager.
  2. Set the secret (see below). Without a secret the endpoint stays closed.

3. Secret

The secret is a single field of the extension configuration (Admin Tools > Settings > Extension Configuration > tt3_stackmonitor). It is stored in settings.php (LocalConfiguration.php before TYPO3 12) under EXTENSIONS/tt3_stackmonitor/secret.

  • Format: letters and digits, 43 characters recommended (e.g. jnadAMFadkerASiONcEImIStivIsHeRATHe21khRMhec), at least 16 required.
  • Generate one with a password generator or LC_ALL=C tr -dc 'A-Za-z0-9' </dev/urandom | head -c 43; echo.
  • Enter the identical secret for the domain in the dashboard.
  • Replace the secret by entering a new value in the field and updating it in the dashboard.
  • Use a separate secret per installation and environment. It may be identical to the t3monitoring_client secret, but the two are configured independently (see below).

Secret from .env

In teufels projects the secret of each environment is set in its .env. Add STACKMONITOR_SECRET there (template: #STACKMONITOR_SECRET="" in .env.local). config/system/additional.php maps it to the extension configuration, next to T3MONITORING_CLIENT_SECRET. A set variable overrides the value from settings.php, without it the extension configuration applies. This works in non-local environments only, on *.localhost the value from settings.php is used.

STACKMONITOR_SECRET and T3MONITORING_CLIENT_SECRET are independent, neither falls back to the other. To use the same secret for both, enter the same value in both variables. t3monitoring_client receives its secret as ?secret= query parameter, which ends up in access logs, a shared secret is exposed the same way. The minimum length of 16 characters applies to the stackmonitor secret, a shorter one keeps the endpoint closed (HTTP 503).

Mapping for projects whose additional.php does not have it yet (inside the non-local branch, after the T3MONITORING_CLIENT_SECRET block):

if (isset( $config['STACKMONITOR_SECRET'] ) && $config['STACKMONITOR_SECRET'] != "" ) {
    $GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['tt3_stackmonitor']['secret'] = $config['STACKMONITOR_SECRET'];
}

Other setups: set $GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['tt3_stackmonitor']['secret'] in config/system/additional.php (typo3conf/AdditionalConfiguration.php before TYPO3 12), it is executed after settings.php.

4. Request and response

curl -H "X-Stackmonitor-Secret: <secret>" https://example.com/stackmonitor

200 OK

{
    "cms": "TYPO3",
    "cmsVersion": "14.3.10",
    "phpVersion": "8.5.12",
    "dbVersion": "11.8.9-MariaDB-ubu2404-log",
    "serverIp": "192.168.2.1"
}
KeySource
cmsfixed value TYPO3
cmsVersionTYPO3 version
phpVersionmajor.minor.patch of the running PHP, without distribution suffix
dbVersionraw SELECT VERSION() of the Default database connection
serverIpSERVER_ADDR as seen by PHP (fallback: gethostbyname(gethostname())), may be internal behind a proxy

Errors are always returned as {"error": "<message>"}:

StatusCaseerror
405method is not GET (response header Allow: GET)Method not allowed
401header X-Stackmonitor-Secret missing or emptyMissing X-Stackmonitor-Secret header
503no secret configured (empty or shorter than 16 characters)Stackmonitor is not configured
401secret does not matchSecret does not match
503database not reachableDatabase not reachable

All responses carry Cache-Control: no-store, X-Robots-Tag: noindex and X-Content-Type-Options: nosniff.

5. Notes

  • Use HTTPS only. The secret is accepted in the header only, a ?secret= query parameter is ignored (it would end up in access logs).
  • The secret is compared in constant time. Data is only collected after a successful check, unauthorized requests cause no database load.
  • Without a valid secret the endpoint never returns data (fail closed).
  • The secret is stored in clear text in settings.php, like the database password. It is visible to backend admins in System > Configuration if EXT:lowlevel is installed.
  • No logging and no rate limiting, this is a task for the web server or a WAF.
  • /stackmonitor must reach TYPO3. The default TYPO3 .htaccess and nginx configuration pass unknown paths to index.php; a blocking WAF, Basic Auth or a rewrite rule that catches the path prevents it.
  • Web server error pages (e.g. nginx fastcgi_intercept_errors on together with error_page 401 ...) replace the JSON error of a 4xx/5xx response with their own page, or with a 404 if that page does not exist. The 200 response is never affected.