DocsGetting started

Uptrail documentation

Monitor the systems your product depends on

Configure service checks, cron heartbeats, incidents, and a public status page from one self-hosted control plane. This guide documents every exposed option and the tradeoffs behind it.

Getting started

Introduction

Uptrail checks services from the server where it is deployed. That detail matters: a target that is reachable from your laptop may not be reachable from the Uptrail process, container, or private network. Design checks around the path your production users and workloads actually take.

Service monitors

HTTP, MySQL, PostgreSQL, Redis, Nats JetStream, and raw TCP connectivity.

Cron health

Detect jobs that fail to start, stop sending heartbeats, or miss their schedule.

Incidents

Publish updates and resolved timelines to a stable, embeddable public page.

Quick start

  1. 1

    Open the control plane

    Sign in, create or select a workspace, then open Monitors. Workspace boundaries isolate monitors, incidents, settings, and members.
  2. 2

    Create a service group

    Use a stable product or capability name such as Checkout API. A group rolls its child monitor states into one status-page service.
  3. 3

    Add the first monitor

    Choose the protocol, enter its connection details, and keep the initial interval at 60 seconds. Start with three down retries to filter brief network noise.
  4. 4

    Run Check now

    Trigger an immediate check. Confirm the response code, matched value, latency, and any error before relying on scheduled checks.
  5. 5

    Configure alert delivery

    Add workspace notification destinations, then test a controlled failure. An alerting system is only complete after the delivery path is verified.
A minimal HTTP health response
HTTP/1.1 200 OK
Content-Type: application/json

{
  "status": "ok",
  "dependencies": {
    "database": "ok"
  }
}

Self-hosting

Uptrail consists of a static marketing site, a Vite-built React control plane, an Express API, a background monitor scheduler, WebSocket updates, and a MySQL application database. In production, run one authoritative scheduler process unless you have explicitly added distributed locking; duplicate schedulers can perform duplicate checks and alerts.

Production checklist

  1. 1

    Provision MySQL

    Create a dedicated database and least-privilege user. Back it up on the same schedule as other operational data.
  2. 2

    Build the client

    Install dependencies and run npm run build. Set VITE_API_BASE_URL before building only when the API lives on another origin.
  3. 3

    Set production secrets

    At minimum set NODE_ENV=production, a random SESSION_SECRET, database credentials, APP_BASE_URL, and the exact CORS_ORIGINS.
  4. 4

    Place behind TLS

    Terminate HTTPS at a trusted reverse proxy, forward WebSocket upgrades for /ws, and set TRUST_PROXY=true.
  5. 5

    Verify network reachability

    Allow the Uptrail host to reach every monitored host and port. Restrict inbound access to the UI/API and outbound access to only required targets where practical.
.env.production
NODE_ENV=production
PORT=3001
APP_BASE_URL=https://uptime.example.com
CORS_ORIGINS=https://uptime.example.com
TRUST_PROXY=true
SESSION_SECRET=replace-with-at-least-32-random-bytes

MYSQL_HOST=mysql.internal
MYSQL_PORT=3306
MYSQL_USER=uptrail
MYSQL_PASSWORD=replace-me
MYSQL_DATABASE=uptrail

RESEND_API_KEY=re_...
EMAIL_FROM=Uptrail <[email protected]>

Environment variables

Values are read when the server starts, except VITE_API_BASE_URL, which is compiled into the frontend at build time. Durations ending in _MS are milliseconds; monitor and cron form windows use seconds.

OptionDefaultHow to use it
NODE_ENVdevelopmentRuntime mode. Set to production for a deployed server.
PORT3001Port used by the API and production server.
APP_BASE_URLfirst CORS originCanonical browser-facing URL used in links and authentication flows.
CORS_ORIGINShttp://localhost:3000,http://localhost:5173Comma-separated browser origins allowed to call the API.
TRUST_PROXYtrue in productionTrust reverse-proxy headers. Enable behind a trusted TLS proxy.
SESSION_SECRETchange-meSecret used to sign sessions. Always replace with a long random value.
SESSION_MAX_AGE_MS86400000Authenticated session lifetime in milliseconds (24 hours by default).
PASSWORD_RESET_TTL_MS3600000Password-reset link lifetime in milliseconds.
MYSQL_HOSTlocalhostMySQL host for Uptrail's own application data.
MYSQL_PORT3306MySQL port for Uptrail's own application data.
MYSQL_USERrootApplication database user.
MYSQL_PASSWORDemptyApplication database password.
MYSQL_DATABASEuptrailApplication database/schema name.
MYSQL_CONNECTION_LIMIT10Maximum connections in the application pool.
MONITOR_POLL_MS1000How frequently the scheduler looks for due monitor checks.
REQUEST_TIMEOUT_MS10000Global fallback timeout for service checks.
CRON_POLL_MS1000How frequently cron state is evaluated.
CRON_SWEEP_INTERVAL_MS30000Interval between scans for missed cron windows.
CRON_CATCHUP_GRACE_MS120000Grace period allowed while recovering overdue cron evaluations.
CRON_RUN_RETENTION_DAYS90Number of days cron-run history is retained.
GOOGLE_CLIENT_IDemptyOAuth client ID. Leave empty to disable Google sign-in.
RESEND_API_KEYemptyResend API key used for transactional email.
EMAIL_FROMUptrail <[email protected]>From identity for outgoing mail.
EMAIL_REPLY_TOUptrail <[email protected]>Reply-to identity for outgoing mail.
CONTACT_EMAIL[email protected]Destination for contact and support messages.
VITE_API_BASE_URLsame originBuild-time frontend API origin. Omit when UI and API share a host.

Monitors

Monitor concepts and shared options

Every monitor belongs to a group and produces timestamped check runs. A check is successful only when the connection/probe completes and its configured assertion passes.

OptionDefaultHow to use it
Group namerequiredCustomer-facing service grouping. Choose a durable capability name rather than a host name.
Monitor namerequiredOperator-facing check name, for example Public API /health or Primary Redis PING.
Monitor typeHTTPSelects the connection parser and probe runner. Type cannot be inferred from the URL.
Interval seconds60Time between scheduled checks. Use 30–60s for critical paths and longer intervals for expensive dependency probes.
Down retries3Consecutive failures required before changing to down. Higher values reduce noise but delay detection by roughly interval × retries.
Up retries1Consecutive successes required to recover. Increase when a dependency tends to flap during recovery.
Connection JSONtype-specificTransport, credentials, TLS, and timeout settings used by non-HTTP monitors.
Probe commandtype-specificCommand or query executed after connecting. Empty uses the safe default for that monitor type.
Expected probe valuetype-specificAssertion value. JSON-looking values are parsed, so use quoted JSON strings such as "ok".

Retry timing example

With a 60-second interval and three down retries, a continuously failing service is normally marked down after the third failed check—approximately two to three minutes depending on where the failure begins relative to the schedule. Manual Check now is useful for diagnosis, but should not replace a realistic retry policy.

HTTP monitors

Use HTTP monitors for APIs, web applications, health endpoints, and authenticated synthetic requests. Uptrail sends the configured request and can assert both the status code and a value inside a JSON response.

OptionDefaultHow to use it
URLrequiredAbsolute http:// or https:// target reachable from the Uptrail server.
MethodGETGET, POST, PUT, PATCH, DELETE, HEAD, or OPTIONS.
Headers JSONemptyJSON object of request headers. Use for Authorization, content negotiation, or tenant headers.
BodyemptyRaw request body. Usually JSON when Content-Type is application/json.
Expected status200Exact HTTP status required for success.
Expected JSON pathemptyDot-separated path into a JSON response. Leave empty when status alone is sufficient.
Expected JSON valueemptyValue at the JSON path that must match. Configure together with JSON path.
connection_json.timeoutMs10000Per-monitor request timeout in milliseconds.
Authenticated POST monitor
URL: https://api.example.com/v1/health/deep
Method: POST
Headers JSON:
{
  "Authorization": "Bearer <read-only-token>",
  "Content-Type": "application/json"
}
Body:
{
  "check": ["database", "queue"]
}
Expected status: 200
Expected JSON path: status
Expected JSON value: ok

MySQL monitors

A MySQL monitor opens a fresh connection, runs one query, compares the first returned scalar value when an expectation is configured, then closes the connection. The default query is SELECT 1 AS health.

OptionDefaultHow to use it
host127.0.0.1Database host reachable from Uptrail.
port3306MySQL TCP port.
userrootUse a dedicated account with only the permissions needed by the probe.
passwordemptyProbe-account password.
databaseoptionalDatabase selected after connection.
connectTimeoutREQUEST_TIMEOUT_MSConnection timeout in milliseconds.
probe commandSELECT 1 AS healthA read-only SQL statement. The first row/first column is the assertion value.
expected probe valuenoneOptional JSON-compatible scalar such as 1, true, or "primary".
MySQL replication-role probe
Connection JSON:
{
  "host": "mysql.internal",
  "port": 3306,
  "user": "uptrail_probe",
  "password": "<secret>",
  "database": "app_db",
  "connectTimeout": 5000
}

Probe command:
SELECT IF(@@read_only = 0, 'primary', 'replica') AS role

Expected probe value:
"primary"

PostgreSQL monitors

PostgreSQL checks follow the same assertion model as MySQL: connect, execute one query, inspect the first scalar value, and disconnect. The default probe is SELECT 1 AS health.

OptionDefaultHow to use it
host127.0.0.1PostgreSQL host reachable from Uptrail.
port5432PostgreSQL TCP port.
userpostgresDedicated read-only probe role.
passwordemptyProbe-role password.
databaseoptionalDatabase used for the session.
ssldriver defaultSet according to your pg client deployment and certificate policy.
connectionTimeoutMillisREQUEST_TIMEOUT_MSConnection timeout in milliseconds.
probe commandSELECT 1 AS healthRead-only SQL query; first row/first column is asserted.
expected probe valuenoneOptional JSON-compatible expected scalar.
PostgreSQL readiness probe
Connection JSON:
{
  "host": "postgres.internal",
  "port": 5432,
  "user": "uptrail_probe",
  "password": "<secret>",
  "database": "app_db",
  "ssl": { "rejectUnauthorized": true },
  "connectionTimeoutMillis": 5000
}

Probe command:
SELECT CASE WHEN pg_is_in_recovery() THEN 'replica' ELSE 'primary' END

Expected probe value:
"primary"

Redis monitors

Redis monitors connect, issue one command, optionally assert the response, and close cleanly. The default command is PING and its default expectation is "PONG".

OptionDefaultHow to use it
urloptionalFull Redis URL such as redis://user:password@host:6379/0. When present it replaces host-based fields.
host127.0.0.1Redis host used when url is omitted.
port6379Redis port used when url is omitted.
usernameoptionalACL username.
passwordoptionalACL or legacy password.
databaseoptionalNumeric logical database index.
probe commandPINGWhitespace command or a JSON array. Prefer JSON arrays when arguments contain spaces.
expected probe value"PONG" for PINGOptional assertion. Leave blank for non-PING commands when execution alone proves health.
Redis command formats
# Simple whitespace form
GET uptime:sentinel

# Unambiguous JSON-array form
["SET", "uptime:last_probe", "healthy service", "EX", "120"]

# Typical read-only assertion
Probe command: GET app:deployment
Expected probe value: "2026.06.29"

Nats JetStream monitors

Nats checks connect to one or more servers and execute a JetStream-aware probe. Use jetstream.info for general availability, stream.info for a critical stream, and consumer-lag probes when backlog growth is the operational risk.

Connection JSON

OptionDefaultHow to use it
servers[nats://127.0.0.1:4222]String or array of Nats URLs. The client can fail over across the list.
server / urloptional aliasesSingle-server alternatives to servers.
nameUptrailOptional client name visible to Nats operators.
useroptionalUsername; username is also accepted.
passoptionalPassword; password is also accepted.
tokenoptionalToken authentication. Do not combine unrelated authentication schemes.
timeoutMsREQUEST_TIMEOUT_MSNats connection timeout in milliseconds.
lag_thresholdsemptyPer-monitor object mapping consumer names and/or default to non-negative lag thresholds.

Every supported probe command

Probe commandWhat it checksExpected value
jetstream.infoConnects to JetStream Manager and reads account information. Best general JetStream readiness check."ok"
stream.info:STREAMLoads metadata for one stream and returns its configured name. Use the stream name as the expectation."STREAM"
consumers.lagEnumerates consumers across all streams and fails when any consumer exceeds its effective lag threshold."ok"
consumers.lag:THRESHOLDSame global scan with one command-level threshold for consumers without a stronger override."ok"
consumer.lag:STREAM:CONSUMERChecks one durable consumer using configured/default threshold precedence."ok"
consumer.lag:STREAM:CONSUMER:THRESHOLDChecks one consumer with an explicit non-negative command threshold."ok"
Nats connection and focused lag probe
Connection JSON:
{
  "servers": [
    "nats://nats-a.internal:4222",
    "nats://nats-b.internal:4222"
  ],
  "user": "uptrail_probe",
  "pass": "<secret>",
  "name": "uptrail-production",
  "timeoutMs": 5000,
  "lag_thresholds": {
    "ORDERS_WORKER": 250,
    "EMAIL_WORKER": 1000,
    "default": 500
  }
}

Probe command:
consumer.lag:ORDERS:ORDERS_WORKER:200

Expected probe value:
"ok"

How consumer lag is evaluated

Uptrail evaluates pending acknowledgement count, waiting pull requests, pending delivery, and changes from the previous sample. A consumer is reported as lagging when its computed backlog exceeds the effective threshold. Threshold selection is deterministic:

  1. Consumer-specific key in the monitor’s lag_thresholds.
  2. Threshold appended to the probe command.
  3. default in the monitor’s lag_thresholds.
  4. Built-in fallback of 128.

TCP port monitors

TCP monitors test whether a socket can be opened. They are ideal for basic reachability of protocols without a dedicated Uptrail probe, but they do not prove that the application protocol is healthy.

OptionDefaultHow to use it
host127.0.0.1DNS name or IP reachable from Uptrail.
port443Required TCP port in the valid 1–65535 range.
timeoutMs5000Maximum connection time in milliseconds.
expected probe value"open"The TCP runner returns open after a successful socket connection.
SMTP reachability
{
  "host": "smtp.internal",
  "port": 587,
  "timeoutMs": 5000
}

Expected probe value: "open"

Cron jobs

Cron monitoring

Cron monitoring tracks whether scheduled work starts and, optionally, continues to report progress. Enable cron monitoring at the workspace level, then define each job’s schedule, delivery mechanism, and timing windows.

OptionDefaultHow to use it
Cron namerequiredStable unique identifier used in events and run history.
ExpressionrequiredCron schedule interpreted by the server. Keep server timezone in mind; production start sets TZ=UTC.
ServiceapisGroups jobs for status and bulk pause controls.
EndpointemptyHTTP destination when trigger type is HTTP.
Trigger typeNatsHow Uptrail invokes or signals the job: Nats publish or HTTP request.
Start window seconds60Time after the scheduled instant in which the run must begin.
Ping window seconds60Maximum allowed time between progress heartbeats for tracked runs.
Track runtrueRequire ongoing pings after start. Disable for fire-and-forget or very short jobs.
StatusenabledDisable a definition without deleting its configuration or history.

HTTP cron triggers

HTTP cron triggers call an endpoint with GET or POST. Use GET only for an idempotent trigger; use POST when creating a run or sending a payload.

OptionDefaultHow to use it
HTTP methodGETGET or POST for HTTP triggers.
EndpointrequiredAbsolute URL called at the scheduled time.
Headers JSONemptyJSON object for Authorization, Content-Type, signatures, or routing.
BodyemptyRaw POST body. Ignored or unnecessary for most GET triggers.
HTTP cron trigger
Trigger type: HTTP
Method: POST
Endpoint: https://jobs.example.com/v1/run/nightly-report
Headers JSON:
{
  "Authorization": "Bearer <job-trigger-token>",
  "Content-Type": "application/json"
}
Body:
{
  "source": "uptrail",
  "job": "nightly-report"
}

Nats cron triggers

Nats triggers publish the cron payload to a subject. Configure the workspace connection first under Settings → Nats Cron Trigger; these credentials are separate from Nats service-monitor connection JSON.

OptionDefaultHow to use it
Nats connection URLrequiredMust begin with nats://.
UsernameoptionalWorkspace Nats username.
PasswordoptionalWorkspace Nats password.
TokenoptionalAlternative token authentication.
Subjectcrons.uptrailDot-delimited Nats subject; letters, numbers, underscore, and hyphen are accepted per token.
Subject strategy
# Shared worker with job name in payload
crons.uptrail

# Environment-scoped subjects
production.crons.billing
staging.crons.billing

Operations

Incident management

Open an incident when users need context beyond a red monitor. The title should name the customer-visible symptom, while updates explain impact, investigation, mitigation, and recovery.

  1. 1

    Open

    Use a concise title such as “Elevated checkout failures” and include the observed impact in the first message.
  2. 2

    Update

    Post material changes: confirmed scope, workaround, mitigation deployed, and monitoring results. Avoid low-information updates.
  3. 3

    Close

    Add a resolution note stating what recovered and how it was verified. Closing moves the incident into the public history.
Incident update example
We identified elevated database lock contention affecting checkout writes.
A configuration change was deployed at 14:32 UTC. Error rates have returned
below 0.2%, and we are monitoring recovery before resolving the incident.

The incident timeline records who opened, updated, and closed the incident. Editors can mutate incidents; viewers can inspect them. Press Escape or use the circular close control to dismiss the incident detail dialog without changing state.

Public status pages

The public incidents page exposes current health and incident history at a stable workspace URL. Open it from the Incidents header, copy the link, or copy the generated iframe snippet.

OptionDefaultHow to use it
Public URLworkspace-specificShare directly with customers or link from your support site.
Embed codegeneratedIframe using 100% width and 640px height. Adjust height to fit your host layout.
LogooptionalWorkspace branding shown on the public experience.
Footer textoptionalSupport, ownership, or legal context shown below incident history.
Responsive embed
<iframe
  src="https://uptime.example.com/incidents-public/YOUR_PUBLIC_ID"
  width="100%"
  height="640"
  style="border:0"
  title="Service status"
  loading="lazy"
></iframe>

Workspace

Notifications

Notification settings are workspace-scoped. Configure destinations for monitor state changes and cron failures, then test both failure and recovery messages. Email requires server-level Resend configuration; workspace settings determine recipients and event behavior.

Use a team-owned destination rather than an individual inbox. Route critical production alerts to a staffed operational channel, and use lower-noise destinations for non-production workspaces.

Teams, permissions, and audit history

Workspaces isolate configuration and membership. Owners and administrators should be limited to people who manage monitors, integrations, branding, and users. Editors can operate monitoring resources; viewers should receive read-only access when they only need visibility.

PracticeRecommendationWhy
Least privilegeUse read-only target credentials and the lowest sufficient workspace role.Limits blast radius if an account or stored secret is compromised.
Shared ownershipKeep at least two trusted workspace administrators.Avoids operational lockout when one person is unavailable.
Audit reviewReview the audit log after configuration and membership changes.Creates accountability for operational changes.
Secret rotationRotate probe tokens and passwords on a defined schedule.Reduces the lifetime of leaked credentials.
Network controlsRestrict Uptrail egress to monitored targets and required providers.Prevents the monitor host from becoming a general network pivot.

Was this documentation useful?

Tell us what is missing or unclear.