Unauthenticated, session-free HTTP health-check endpoints for Request Tracker 6:
- A fast liveness ping for load balancers — no I/O, proves the web worker process is alive, independent of database or Redis health.
- A slower, extended status check for monitoring systems like Icinga — checks database connectivity and, if RT stores web sessions in Redis, Redis connectivity too.
Both endpoints are guaranteed to never create a session record, in Redis or any other session store.
RT::Interface::Web::HandleRequest ties a web session (and sends a
Set-Cookie header) for every request that reaches Mason — including
/NoAuth/ pages — before it even checks whether the page is a NoAuth page.
Without an already-valid session cookie (the normal case for every load
balancer or Icinga probe), this creates a brand new session record the
moment it's tied, regardless of whether the page ever touches %session. A
probe hitting the page every few seconds would flood the session store with
a fresh key per hit.
The only way to guarantee zero session interaction is to intercept the
request before Mason ever sees it — at the PSGI layer, via RT's documented,
version-stable per-plugin PSGIWrap hook (the same mechanism
RT::Extension::ReverseProxy
uses):
for my $plugin (RT->Config->Get("Plugins")) {
my $wrap = $plugin->can("PSGIWrap") or next;
$app = $wrap->($plugin, $app);
}This extension's PSGIWrap answers matched paths directly with a PSGI
response, without ever calling the wrapped Mason/REST2/static application.
perl -I. Makefile.PL
make
make installEdit /opt/rt/etc/RT_SiteConfig.pm:
Plugin('RT::Extension::HealthEndpoint');Clear the Mason cache and restart the webserver:
rm -rf /opt/rt/var/mason_data/objAll optional; sensible defaults apply. Changes require a webserver restart.
Set($HealthEndpoint_PingPath, '/healthz/ping'); # default
Set($HealthEndpoint_StatusPath, '/healthz/status'); # default
# undef (default) = auto-detect Redis via $WebSessionClass; 0 = never; 1 = always
Set($HealthEndpoint_CheckRedis, undef);Only the server key of %WebSessionProperties is used to connect. If your
Redis requires a password or a unix socket, the health check will not pass
it through and will report fail for an otherwise-healthy Redis.
Ping — GET/HEAD /healthz/ping always returns 200 with body pong
(empty for HEAD). No I/O, never fails.
Status — GET/HEAD /healthz/status returns:
{"checks":{"database":"ok","redis":"ok"},"status":"ok"}status is ok only if every executed check is ok; skipped (Redis not
configured) never degrades it. HTTP status mirrors this: 200 for ok,
503 otherwise. Only the fixed tokens ok/fail/skipped ever reach the
caller — failure details are logged server-side via RT->Logger->error.
Any method other than GET/HEAD on either path returns 405.
Both endpoints are unauthenticated by design. The response body is deliberately minimal. Add IP allowlisting at the reverse proxy or firewall layer if the endpoints should not be publicly reachable.
NETWAYS GmbH support@netways.de
This software is Copyright (c) 2026 by NETWAYS GmbH
This is free software, licensed under:
The GNU General Public License, Version 2, June 1991